summaryrefslogtreecommitdiffstats
path: root/fpga/gpmc/xilinx/common/main.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/gpmc/xilinx/common/main.v')
-rw-r--r--fpga/gpmc/xilinx/common/main.v393
1 files changed, 393 insertions, 0 deletions
diff --git a/fpga/gpmc/xilinx/common/main.v b/fpga/gpmc/xilinx/common/main.v
new file mode 100644
index 0000000..370c3a2
--- /dev/null
+++ b/fpga/gpmc/xilinx/common/main.v
@@ -0,0 +1,393 @@
+`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