You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

519 lines
16 KiB

`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,
output reg userlogic_reset,
input userlogic_clock,
output userlogic_serial_txd,
input userlogic_serial_rxd,
output host_serial_txd,
input host_serial_rxd,
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 = 15;
assign host_serial_txd = userlogic_serial_rxd;
assign userlogic_serial_txd = host_serial_rxd;
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));
wire logic_analyzer_clk;
logic_analyzer_clock_generator logic_analyzer_clock_generator(.clkin(clk), .clkout(logic_analyzer_clk));
wire logic_analyzer_data_storage_clka;
wire logic_analyzer_data_storage_clkb;
reg [63:0] logic_analyzer_data_storage_dina;
reg [63:0] logic_analyzer_data_storage_dinb;
reg [10:0] logic_analyzer_data_storage_addra;
reg [10:0] logic_analyzer_data_storage_addrb;
reg logic_analyzer_data_storage_wea;
reg logic_analyzer_data_storage_web;
wire [63:0] logic_analyzer_data_storage_douta;
wire [63:0] logic_analyzer_data_storage_doutb;
assign logic_analyzer_data_storage_clka = clk;
assign logic_analyzer_data_storage_clkb = logic_analyzer_clk;
logic_analyzer_data_storage logic_analyzer_data_storage(.clka(logic_analyzer_data_storage_clka), .clkb(logic_analyzer_data_storage_clkb),
.dina(logic_analyzer_data_storage_dina), .dinb(logic_analyzer_data_storage_dinb),
.addra(logic_analyzer_data_storage_addra), .addrb(logic_analyzer_data_storage_addrb),
.wea(logic_analyzer_data_storage_wea), .web(logic_analyzer_data_storage_web),
.douta(logic_analyzer_data_storage_douta), .doutb(logic_analyzer_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
//-----------------------------------------------------------------------------------
//
// Logic analyzer
//
//-----------------------------------------------------------------------------------
reg logic_analyzer_trigger;
reg logic_analyzer_trigger_prev;
reg [11:0] logic_analyzer_address_counter;
always @(posedge logic_analyzer_clk) begin
// Trigger
logic_analyzer_trigger = ~userlogic_reset; // Trigger on userlogic_reset falling edge
if ((logic_analyzer_trigger == 1) && (logic_analyzer_trigger_prev == 0)) begin
logic_analyzer_address_counter = 0;
end
// Data load
if (logic_analyzer_address_counter[11] == 1'b0) begin
logic_analyzer_data_storage_addrb = logic_analyzer_address_counter;
// Connect signals to logic analyzer
logic_analyzer_data_storage_dinb[3:0] = four_bit_leds;
logic_analyzer_data_storage_dinb[7:4] = four_bit_switches;
logic_analyzer_data_storage_dinb[15:8] = eight_bit_leds;
logic_analyzer_data_storage_dinb[23:16] = eight_bit_switches;
logic_analyzer_data_storage_dinb[27:24] = sseg_mux;
logic_analyzer_data_storage_dinb[35:28] = sseg_data;
logic_analyzer_data_storage_dinb[43:36] = usermem_data;
logic_analyzer_data_storage_dinb[59:44] = usermem_address;
logic_analyzer_data_storage_dinb[60] = usermem_wen;
logic_analyzer_data_storage_dinb[61] = usermem_wait;
logic_analyzer_data_storage_dinb[62] = 1'b0; // UNUSED
logic_analyzer_data_storage_dinb[63] = userlogic_clock;
logic_analyzer_data_storage_web = 1'b1;
logic_analyzer_address_counter = logic_analyzer_address_counter + 1;
end
logic_analyzer_trigger_prev = logic_analyzer_trigger;
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;
if (gpmc_wen_reg == 1'b0) begin
gpmc_data_reg = gpmc_data;
end
if (gpmc_advn_reg == 1'b0) begin
gpmc_address_reg = gpmc_address;
data_storage_write_enable = 1'b0;
lcd_data_storage_wea = 1'b0;
logic_analyzer_data_storage_wea = 1'b0;
end
if (gpmc_wen_reg == 1'b1) begin
data_storage_write_enable = 1'b0;
lcd_data_storage_wea = 1'b0;
logic_analyzer_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)
// 0x0b: Number of address bits of DSP RAM (read only)
// 0x0c: User device control
// Bit 0: User logic reset
// 0x20 - 0x3f: LCD data area
// 0x4000 - 0x7fff: Logic analyzer data area (read only)
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
12: begin
userlogic_reset = 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 if (gpmc_address_reg[(RAM_ADDR_BITS-1):14] == 1) begin // Address range 0x4000 - 0x7fff
logic_analyzer_data_storage_addra = gpmc_address_reg[13:3];
logic_analyzer_data_storage_wea = 1'b0;
case (gpmc_address_reg[2:0])
0: begin
gpmc_data_out = logic_analyzer_data_storage_douta[7:0];
end
1: begin
gpmc_data_out = logic_analyzer_data_storage_douta[15:8];
end
2: begin
gpmc_data_out = logic_analyzer_data_storage_douta[23:16];
end
3: begin
gpmc_data_out = logic_analyzer_data_storage_douta[31:24];
end
4: begin
gpmc_data_out = logic_analyzer_data_storage_douta[39:32];
end
5: begin
gpmc_data_out = logic_analyzer_data_storage_douta[47:40];
end
6: begin
gpmc_data_out = logic_analyzer_data_storage_douta[55:48];
end
7: begin
gpmc_data_out = logic_analyzer_data_storage_douta[63:56];
end
endcase
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
11: begin
gpmc_data_out = RAM_ADDR_BITS;
end
12: begin
gpmc_data_out[0] = userlogic_reset;
gpmc_data_out[7:1] = 0;
end
default: begin
gpmc_data_out = 0;
end
endcase
end
end
end
gpmc_data_driven = ((~gpmc_oen) && gpmc_wen);
end
endmodule