`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // // uLab to ARM GPMC interface // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // // (c) 2014 Timothy Pearson // Raptor Engineering // http://www.raptorengineeringinc.com // ////////////////////////////////////////////////////////////////////////////////// module main( input clk, input gpmc_advn, input gpmc_oen, input gpmc_wen, inout [7:0] gpmc_data, input [RAM_ADDR_BITS:0] gpmc_address, input usermem_wen, output reg usermem_wait, inout [7:0] usermem_data, inout [RAM_ADDR_BITS:0] usermem_address, output reg userproc_start, input userproc_done, input [3:0] four_bit_leds, input [7:0] eight_bit_leds, output reg [3:0] four_bit_switches, output reg [7:0] eight_bit_switches, inout [15:0] sixteen_bit_io, input sixteen_bit_io_wen, output reg sixteen_bit_io_mode, input [3:0] sseg_mux, input [7:0] sseg_data); parameter RAM_ADDR_BITS = 14; reg [15:0] sixteen_bit_io_in; reg [15:0] sixteen_bit_io_out; reg [15:0] sixteen_bit_io_reg; reg sixteen_bit_io_wen_reg; assign sixteen_bit_io = (sixteen_bit_io_wen) ? sixteen_bit_io_out : 16'bz; always @(posedge clk) begin sixteen_bit_io_reg = sixteen_bit_io; sixteen_bit_io_wen_reg = sixteen_bit_io_wen; if (sixteen_bit_io_wen_reg == 1'b0) begin sixteen_bit_io_mode = 1'b1; sixteen_bit_io_in = sixteen_bit_io_reg; end else begin sixteen_bit_io_mode = 1'b0; end end reg [7:0] gpmc_data_out; reg gpmc_data_driven; assign gpmc_data = (gpmc_data_driven) ? gpmc_data_out : 8'bz; reg [7:0] usermem_data_out; assign usermem_data = (usermem_wen) ? usermem_data_out : 8'bz; wire data_storage_clka; reg [7:0] data_storage_dina; reg [(RAM_ADDR_BITS-1):0] data_storage_addra; reg data_storage_write_enable; wire [7:0] data_storage_data_out; assign data_storage_clka = clk; data_storage #(RAM_ADDR_BITS) data_storage(.clka(data_storage_clka), .dina(data_storage_dina), .addra(data_storage_addra), .wea(data_storage_write_enable), .douta(data_storage_data_out)); wire lcd_data_storage_clka; wire lcd_data_storage_clkb; reg [7:0] lcd_data_storage_dina; reg [7:0] lcd_data_storage_dinb; reg [4:0] lcd_data_storage_addra; reg [4:0] lcd_data_storage_addrb; reg lcd_data_storage_wea; reg lcd_data_storage_web; wire [7:0] lcd_data_storage_douta; wire [7:0] lcd_data_storage_doutb; assign lcd_data_storage_clka = clk; assign lcd_data_storage_clkb = clk; lcd_data_storage lcd_data_storage(.clka(lcd_data_storage_clka), .clkb(lcd_data_storage_clkb), .dina(lcd_data_storage_dina), .dinb(lcd_data_storage_dinb), .addra(lcd_data_storage_addra), .addrb(lcd_data_storage_addrb), .wea(lcd_data_storage_wea), .web(lcd_data_storage_web), .douta(lcd_data_storage_douta), .doutb(lcd_data_storage_doutb)); //----------------------------------------------------------------------------------- // // Create a 12.5MHz clock for the seven-segement LED emulator // //----------------------------------------------------------------------------------- reg clk_div_by_two; reg clk_div_by_two_oneeighty; reg clk_div_by_four; reg clk_div_by_eight; reg clk_div_by_sixteen; always @(posedge clk) begin clk_div_by_two = !clk_div_by_two; end always @(negedge clk_div_by_two) begin clk_div_by_two_oneeighty = !clk_div_by_two_oneeighty; end always @(posedge clk_div_by_two_oneeighty) begin clk_div_by_four = !clk_div_by_four; end always @(posedge clk_div_by_four) begin clk_div_by_eight = !clk_div_by_eight; end always @(posedge clk_div_by_eight) begin clk_div_by_sixteen = !clk_div_by_sixteen; end //----------------------------------------------------------------------------------- // // Keep track of what is on the LED display // //----------------------------------------------------------------------------------- reg [7:0] led_display_bytes [3:0]; reg [17:0] digit_blanker_1 = 0; reg [17:0] digit_blanker_2 = 0; reg [17:0] digit_blanker_3 = 0; reg [17:0] digit_blanker_4 = 0; reg [7:0] sseg_data_latch; reg [3:0] sseg_mux_latch; always @(negedge clk_div_by_sixteen) begin sseg_data_latch = sseg_data; sseg_mux_latch = sseg_mux; if (sseg_mux_latch[0] == 0) begin led_display_bytes[0] = sseg_data_latch; digit_blanker_1 = 0; digit_blanker_2 = digit_blanker_2 + 1; digit_blanker_3 = digit_blanker_3 + 1; digit_blanker_4 = digit_blanker_4 + 1; end if (sseg_mux_latch[1] == 0) begin led_display_bytes[1] = sseg_data_latch; digit_blanker_1 = digit_blanker_1 + 1; digit_blanker_2 = 0; digit_blanker_3 = digit_blanker_3 + 1; digit_blanker_4 = digit_blanker_4 + 1; end if (sseg_mux_latch[2] == 0) begin led_display_bytes[2] = sseg_data_latch; digit_blanker_1 = digit_blanker_1 + 1; digit_blanker_2 = digit_blanker_2 + 1; digit_blanker_3 = 0; digit_blanker_4 = digit_blanker_4 + 1; end if (sseg_mux_latch[3] == 0) begin led_display_bytes[3] = sseg_data_latch; digit_blanker_1 = digit_blanker_1 + 1; digit_blanker_2 = digit_blanker_2 + 1; digit_blanker_3 = digit_blanker_3 + 1; digit_blanker_4 = 0; end if (digit_blanker_1 > 128000) begin led_display_bytes[0] = 255; end if (digit_blanker_2 > 128000) begin led_display_bytes[1] = 255; end if (digit_blanker_3 > 128000) begin led_display_bytes[2] = 255; end if (digit_blanker_4 > 128000) begin led_display_bytes[3] = 255; end end //----------------------------------------------------------------------------------- // // Memory and register access // //----------------------------------------------------------------------------------- reg gpmc_advn_reg; reg gpmc_oen_reg; reg gpmc_wen_reg; reg [7:0] gpmc_data_reg; reg [RAM_ADDR_BITS:0] gpmc_address_reg; reg usermem_wen_reg; reg [7:0] usermem_data_reg; reg [RAM_ADDR_BITS:0] usermem_address_reg; always @(posedge clk) begin usermem_wen_reg = usermem_wen; usermem_data_reg = usermem_data; usermem_address_reg = usermem_address; gpmc_advn_reg = gpmc_advn; gpmc_oen_reg = gpmc_oen; gpmc_wen_reg = gpmc_wen; gpmc_data_reg = gpmc_data; if (gpmc_advn_reg == 1'b0) begin gpmc_address_reg = gpmc_address; data_storage_write_enable = 1'b0; lcd_data_storage_wea = 1'b0; end if (gpmc_address_reg[RAM_ADDR_BITS] == 1'b1) begin // System memory access usermem_wait = 1'b1; if (gpmc_wen_reg == 1'b0) begin data_storage_addra = gpmc_address_reg[(RAM_ADDR_BITS-1):0]; data_storage_dina = gpmc_data_reg; data_storage_write_enable = 1'b1; end else begin data_storage_addra = gpmc_address_reg[(RAM_ADDR_BITS-1):0]; data_storage_write_enable = 1'b0; gpmc_data_out = data_storage_data_out; end end else begin // User memory access usermem_wait = 1'b0; if (usermem_address_reg[RAM_ADDR_BITS] == 1'b1) begin // Interdevice communication region // MEMORY MAP // 0x20 - 0x3f: LCD data area if (usermem_wen_reg == 1'b0) begin if (usermem_address_reg[(RAM_ADDR_BITS-1):5] == 1) begin // Address range 0x20 - 0x3f lcd_data_storage_addrb = usermem_address_reg[4:0]; lcd_data_storage_dinb = usermem_data_reg; lcd_data_storage_web = 1'b1; end end else begin if (usermem_address_reg[(RAM_ADDR_BITS-1):5] == 1) begin // Address range 0x20 - 0x3f lcd_data_storage_addrb = usermem_address_reg[4:0]; lcd_data_storage_web = 1'b0; usermem_data_out = lcd_data_storage_doutb; end else begin // Default usermem_data_out = 8'b00000000; end end end else begin // Client scratchpad memory area if (usermem_wen_reg == 1'b0) begin data_storage_addra = usermem_address_reg[(RAM_ADDR_BITS-1):0]; data_storage_dina = usermem_data_reg; data_storage_write_enable = 1'b1; end else begin data_storage_addra = usermem_address_reg[(RAM_ADDR_BITS-1):0]; data_storage_write_enable = 1'b0; usermem_data_out = data_storage_data_out; end end // Configuration register access // MEMORY MAP // 0x00: Model number (read only) // 0x01: Version (read only) // 0x02: 4-bit I/O (lower 4 bits only) // 0x03: 8-bit I/O // 0x04: 16-bit I/O (upper 8 bits) // 0x05: 16-bit I/O (lower 8 bits) // 0x06: 7-segment LED digit 0 (read only) // 0x07: 7-segment LED digit 1 (read only) // 0x08: 7-segment LED digit 2 (read only) // 0x09: 7-segment LED digit 3 (read only) // 0x0a: User process register // Bit 0: User processing start // Bit 1: User processing done (read only) // 0x20 - 0x3f: LCD data area if (gpmc_wen_reg == 1'b0) begin if (gpmc_address_reg[(RAM_ADDR_BITS-1):5] == 1) begin // Address range 0x20 - 0x3f lcd_data_storage_addra = gpmc_address_reg[4:0]; lcd_data_storage_dina = gpmc_data_reg; lcd_data_storage_wea = 1'b1; end else begin case (gpmc_address_reg[(RAM_ADDR_BITS-1):0]) 2: begin four_bit_switches = gpmc_data_reg[3:0]; end 3: begin eight_bit_switches = gpmc_data_reg; end 4: begin sixteen_bit_io_out[15:8] = gpmc_data_reg; end 5: begin sixteen_bit_io_out[7:0] = gpmc_data_reg; end 10: begin userproc_start = gpmc_data_reg[0]; end default: begin // Do nothing end endcase end end else begin if (gpmc_address_reg[(RAM_ADDR_BITS-1):5] == 1) begin // Address range 0x20 - 0x3f lcd_data_storage_addra = gpmc_address_reg[4:0]; lcd_data_storage_wea = 1'b0; gpmc_data_out = lcd_data_storage_douta; end else begin case (gpmc_address_reg[(RAM_ADDR_BITS-1):0]) 0: begin gpmc_data_out = 8'b01000010; end 1: begin gpmc_data_out = 8'b00000001; end 2: begin gpmc_data_out[7:4] = 0; gpmc_data_out[3:0] = four_bit_leds; end 3: begin gpmc_data_out = eight_bit_leds; end 4: begin gpmc_data_out = sixteen_bit_io_in[15:8]; end 5: begin gpmc_data_out = sixteen_bit_io_in[7:0]; end 6: begin gpmc_data_out = led_display_bytes[0]; end 7: begin gpmc_data_out = led_display_bytes[1]; end 8: begin gpmc_data_out = led_display_bytes[2]; end 9: begin gpmc_data_out = led_display_bytes[3]; end 10: begin gpmc_data_out[0] = userproc_start; gpmc_data_out[1] = userproc_done; gpmc_data_out[7:2] = 0; end default: begin gpmc_data_out = 0; end endcase end end end gpmc_data_driven = ((~gpmc_oen) && gpmc_wen); end endmodule