`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 			Raptor Engineering
// Engineer: 			Timothy Pearson
// 
// Design Name:			Remote Access Sample Design
// Module Name:    		sample_demo
// Project Name: 		Remote Access Sample Design
// Target Devices: 		Any
// Description: 		Remote Access Sample Design
//
// Dependencies: 
//
// (c) 2007-2013 Timothy Pearson, Raptor Engineering
// Released into the Public Domain
//
//////////////////////////////////////////////////////////////////////////////////
module main(
	input clk,				// 100MHz clock
	
	// Serial port
	input serial_input,
	output serial_output);

	parameter RAM_ADDR_BITS = 14;

	wire [7:0] four_bit_output;		// Output from the user program to the remote access module
	wire [7:0] four_bit_input;		// Input to the user program from the remote access module
	wire [7:0] eight_bit_output;		// Output from the user program to the remote access module
	wire [7:0] eight_bit_input;		// Input to the user program from the remote access module
	wire [15:0] sixteen_bit_output;		// Output from the user program to the remote access module
	wire [15:0] sixteen_bit_input;		// Input to the user program from the remote access module
	
	wire [7:0] remote_access_local_input;
	
	reg [7:0] serial_data_to_write;
	wire sieze_serial_tx;
	reg serial_tx_strobe = 0;
	wire serial_data_received;
	wire serial_rx_strobe;
	
	wire [5:0] lcd_data_in_address;
	wire [7:0] lcd_data_in_data;
	wire lcd_data_in_enable;

	wire [7:0] led_segment_bus;
	wire [3:0] led_digit_select;
	
	//-------------------------------------------------------------------------------------------------------
	//
	// Generate a 50MHz clock for the remote access module
	//
	//-------------------------------------------------------------------------------------------------------
	
	reg main_fifty_clock = 0;
	always @(posedge clk) begin
		main_fifty_clock = !main_fifty_clock;
	end
	
	//-------------------------------------------------------------------------------------------------------
	//
	// Generate a 25MHz clock for the user progam
	//
	//-------------------------------------------------------------------------------------------------------
	
	reg clk_div_by_two = 0;
	always @(posedge main_fifty_clock) begin
		clk_div_by_two = !clk_div_by_two;
	end

	//-------------------------------------------------------------------------------------------------------
	//
	// Remote Access Module
	//
	// Inputs:
	// .clk: 							50MHz clock
	// .four_bit_input						4-bit input to the user program from the remote access module
	// .eight_bit_input						8-bit input to the user program from the remote access module
	// .sixteen_bit_input						16-bit input to the user program from the remote access module
	// .serial_port_receiver					Input from the serial port's RxD (receive data) pin
	// .remote_access_input_enable					Toggle remote access input vs. local input mode
	// .local_input							Local input to the remote program
	// .seize_serial_tx						Sieze control of the serial transmitter from the remote control system
	// .serial_tx_data						Byte to be transmitted on transmit strobe if control has been siezed
	// .serial_tx_strobe						Transmit serial data on posedge if transmit control has been siezed
	// .lcd_data_in_address						LCD character address (0-32) to write character code to
	// .lcd_data_in_data						LCD character code to write to the address specified
	// .lcd_data_in_enable						Enable LCD data write
	// .sram_wren_in						Synchronous SRAM write enable (1=write, 0=read)
	// .sram_clock_in						Synchronous SRAM clock input
	// .sram_data_in						Synchronous SRAM data input (8-bit)
	// .sram_address_in						Synchronous SRAM address input (14-bit by default)
	// .sram_processing_done					When 1, signal release of user control of synchronous SRAM
	// .led_segment_bus						Connect directly to the 8 bits controlling the LED display segments
	// .led_digit_select						Connect directly to the 4 bits enabling the LED display digits
	//
	// Outputs:
	// .four_bit_output						4-bit output from the user program to the remote access module
	// .eight_bit_output						8-bit output from the user program to the remote access module
	// .sixteen_bit_output						16-bit output from the user program to the remote access module
	// .lcd_data_out						Data output to the LCD
	// .lcd_rs_out							RS signal output to the LCD
	// .lcd_rw_out							RW signal output to the LCD
	// .lcd_enable_out						ENABLE signal output to the LCD
	// .serial_port_transmitter					Output to the serial port's TxD (transmit data) pin
	// .serial_rx_data						The last received serial data
	// .serial_rx_strobe						Recevied serial data valid while this signal is 1
	// .sram_data_out						Synchronous SRAM data output (8-bit)
	// .sram_available						Synchronous SRAM under user control
	//
	//-------------------------------------------------------------------------------------------------------

	wire sram_wren_in;
	wire sram_clock_in;
	wire [7:0] sram_data_in;
	wire [(RAM_ADDR_BITS-1):0] sram_address_in;
	wire [7:0] sram_data_out;
	wire sram_available;
	wire sram_processing_done;

	// Uncomment this block if no image processing module is provided
	// assign sram_wren_in = 0;
	// assign sram_data_in = 0;
	// assign sram_address_in = 0;
	// assign sram_processing_done = 1;
	
	assign sram_clock_in = main_fifty_clock;

	remote_access #(RAM_ADDR_BITS) remote_access(.main_fifty_clock(main_fifty_clock), .remote_access_4_bit_output(four_bit_output),
		.remote_access_4_bit_input(four_bit_input), .remote_access_8_bit_output(eight_bit_output),
		.remote_access_8_bit_input(eight_bit_input), .remote_access_16_bit_output(sixteen_bit_output),
		.remote_access_16_bit_input(sixteen_bit_input),
		.serial_port_receiver(serial_input), .serial_port_transmitter(serial_output), .remote_access_input_enable(btn_center),
		.local_input(remote_access_local_input), .seize_serial_tx(sieze_serial_tx), .serial_tx_data(serial_data_to_write),
		.serial_tx_strobe(serial_tx_strobe), .serial_rx_data(serial_data_received), .serial_rx_strobe(serial_rx_strobe),
		.lcd_data_in_address(lcd_data_in_address), .lcd_data_in_data(lcd_data_in_data), .lcd_data_in_enable(lcd_data_in_enable),
		.sram_wren_in(sram_wren_in), .sram_clock_in(sram_clock_in), .sram_data_in(sram_data_in), .sram_address_in(sram_address_in),
		.sram_data_out(sram_data_out), .sram_available(sram_available), .sram_processing_done(sram_processing_done),
		.led_segment_bus(led_segment_bus), .led_digit_select(led_digit_select));
	
	assign remote_access_local_input[7:4] = 0;					// Local inputs
	assign remote_access_local_input[3:0] = 0;					// Local inputs
	assign led_bank = eight_bit_input;						// Mirror input to the LEDs
	assign sieze_serial_tx = 0;							// Allow the remote control module to use the serial port
											// If the user module must access the serial port directly, delete
											// this assign statement and control this wire with your module.
	
	//-------------------------------------------------------------------------------------------------------
	//
	// User Module Instantiation
	//
	// Instantiate the simple user module to display remote access input values on the LEDs and to feed 
	// button presses to the remote access module.  The 16-bit remote access lines are in loopback.
	// Feel free to delete this instantiation and the module below to replace it with your module.
	//
	//-------------------------------------------------------------------------------------------------------
	
	sample_demo sample_demo(.clk(clk_div_by_two), .four_bit_input(four_bit_input), .four_bit_output(four_bit_output),
		.eight_bit_input(eight_bit_input), .eight_bit_output(eight_bit_output), .sixteen_bit_input(sixteen_bit_input),
		.sixteen_bit_output(sixteen_bit_output), .lcd_data_in_address(lcd_data_in_address),
		.lcd_data_in_data(lcd_data_in_data), .lcd_data_in_enable(lcd_data_in_enable),
		.led_segment_bus(led_segment_bus), .led_digit_select(led_digit_select));

	//-------------------------------------------------------------------------------------------------------
	//
	// User Image Processing Module Instantiation
	//
	// Instantiate the simple userimage processing module to invert the bits in any images sent to the FPGA
	//
	//-------------------------------------------------------------------------------------------------------

	sample_image_processing_demo sample_image_processing_demo(.clk(clk_div_by_two), .wren(sram_wren_in), .dout(sram_data_in), .addr(sram_address_in),
		.din(sram_data_out), .enable(sram_available), .done(sram_processing_done));

endmodule

//-------------------------------------------------------------------------------------------------------
//
// Demo User Module
//
//-------------------------------------------------------------------------------------------------------

module sample_demo(clk, four_bit_input, four_bit_output, eight_bit_input, eight_bit_output, sixteen_bit_input, sixteen_bit_output, lcd_data_in_address, lcd_data_in_data, lcd_data_in_enable, led_segment_bus, led_digit_select);
	input clk;
	
	input [3:0] four_bit_input;
	output reg [3:0] four_bit_output;
	input [7:0] eight_bit_input;
	output reg [7:0] eight_bit_output;
	input [15:0] sixteen_bit_input;
	output reg [15:0] sixteen_bit_output;
	
	output reg [5:0] lcd_data_in_address;
	output reg [7:0] lcd_data_in_data;
	output reg lcd_data_in_enable;

	output reg [7:0] led_segment_bus;
	output reg [3:0] led_digit_select;

	reg [7:0] lcd_sample_counter = 48;							// Create a sample LCD display counter register
	reg [31:0] lcd_character_change_timer = 0;						// Wait a certain number of cycles before loading a new character
	reg [5:0] lcd_current_character = 0;							// The current character's address
	
	always @(posedge clk) begin
		four_bit_output = four_bit_input;						// Loopback
		eight_bit_output = eight_bit_input[3:0] + eight_bit_input[7:4];			// Sample adder
		sixteen_bit_output = sixteen_bit_input[15:8] * sixteen_bit_input[7:0];		// Sample multiplier
		
		// Sample LCD display routine		
		lcd_data_in_address = lcd_current_character;					// Character location on the LCD display
		lcd_data_in_data = lcd_sample_counter;						// Character code to display
		lcd_data_in_enable = 1;								// Enable data transmission
		
		// Cycle through all character positions
		lcd_current_character = lcd_current_character + 1;
		if (lcd_current_character > 31) begin
			lcd_current_character = 16;
		end
		
		// Cycle through the numbers 0 to 9 at one second intervals
		lcd_character_change_timer = lcd_character_change_timer + 1;
		if (lcd_character_change_timer > 25000000) begin				// Wait one second in between character changes
			lcd_character_change_timer = 0;
			lcd_sample_counter = lcd_sample_counter + 1;
			if (lcd_sample_counter > 57) begin					// Character code for the digit 9
				lcd_sample_counter = 48;					// Character code for the digit 0
			end
		end
	end

	// 7-segment LED display driver clock generator
	reg sseg_clock;
	reg [4:0] sseg_clock_counter;

	always @(posedge clk) begin
		sseg_clock_counter = sseg_clock_counter + 1;
		if (sseg_clock_counter > 16) begin
			sseg_clock_counter = 0;
			sseg_clock = ~sseg_clock;
		end
	end

	// 7-segment LED display driver
	// led_segment_bus and led_digit_select are active low
	// The bit sequence, MSB to LSB, is dp a b c d e f g
	// Segment letters are taken from ug130.pdf page 15

	// 0: 8'b10000001
	// 1: 8'b11001111
	// 2: 8'b10010010
	// 3: 8'b10000110
	reg [2:0] current_anode;
	always @(posedge sseg_clock) begin
		current_anode = current_anode + 1;
		if (current_anode > 3) begin
			current_anode = 0;
		end

		case (current_anode)
			0: begin
				led_digit_select = 4'b1110;
				led_segment_bus = 8'b10000001;
			end
			1: begin
				led_digit_select = 4'b1101;
				led_segment_bus = 8'b11001111;
			end
			2: begin
				led_digit_select = 4'b1011;
				led_segment_bus = 8'b10010010;
			end
			3: begin
				led_digit_select = 4'b0111;
				led_segment_bus = 8'b10000110;
			end
		endcase
	end
endmodule

//-------------------------------------------------------------------------------------------------------
//
// Demo User Image Processing Module
//
//-------------------------------------------------------------------------------------------------------

module sample_image_processing_demo(clk, wren, dout, addr, din, enable, done);
	parameter IMAGE_RAM_ADDR_BITS = 14;

	input clk;

	output reg wren;
	output reg [7:0] dout;
	output reg [(IMAGE_RAM_ADDR_BITS-1):0] addr;
	input [7:0] din;
	input enable;
	output reg done;

	reg prev_enable;
	reg [IMAGE_RAM_ADDR_BITS:0] counter;
	reg toggler;

	always @(posedge clk) begin
		if ((enable == 1) && (prev_enable == 0)) begin
			counter = 0;
			toggler = 0;
		end
		if ((enable == 1) && (done == 0)) begin
			if (toggler == 0) begin
				wren = 0;
				addr = counter;
				toggler = 1;
			end else begin
				dout = ~din;
				wren = 1;
				addr = counter;
				counter = counter + 1;
				if (counter > (2**IMAGE_RAM_ADDR_BITS)) begin
					done = 1;
				end
				toggler = 0;
			end
		end
		if (enable == 0) begin
			done = 0;
			addr = 0;
			toggler = 0;
		end
		prev_enable = enable;
	end
endmodule
