diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 300a5bd..abf3ef9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -18,6 +18,7 @@ sim: stage: sim tags: - linux + - efinity script: - source init_env.sh - make sim diff --git a/Makefile b/Makefile index 4a96722..f13bfba 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,9 @@ fpga_image: $(INIT_HEX) sim: $(INIT_HEX) $(MAKE) -C hw/super6502_fpga/src/sim +waves: sim + gtkwave hw/super6502_fpga/src/sim/sim_top.vcd + # SW .PHONY: toolchain toolchain: diff --git a/hw/super6502_fpga/addr_map.mem b/hw/super6502_fpga/addr_map.mem index 3d631b3..7a02cdc 100644 --- a/hw/super6502_fpga/addr_map.mem +++ b/hw/super6502_fpga/addr_map.mem @@ -2,4 +2,6 @@ 00000000 000001ff 0000ff00 -0000ffff \ No newline at end of file +0000ffff +00000200 +0000efff \ No newline at end of file diff --git a/hw/super6502_fpga/ip/sdram_controller/ipm/component.pickle b/hw/super6502_fpga/ip/sdram_controller/ipm/component.pickle new file mode 100644 index 0000000..1ef144d Binary files /dev/null and b/hw/super6502_fpga/ip/sdram_controller/ipm/component.pickle differ diff --git a/hw/super6502_fpga/ip/sdram_controller/ipm/graph.pickle b/hw/super6502_fpga/ip/sdram_controller/ipm/graph.pickle new file mode 100644 index 0000000..6bb69b6 Binary files /dev/null and b/hw/super6502_fpga/ip/sdram_controller/ipm/graph.pickle differ diff --git a/hw/super6502_fpga/ip/sdram_controller/sdram_controller.v b/hw/super6502_fpga/ip/sdram_controller/sdram_controller.v new file mode 100644 index 0000000..926328a --- /dev/null +++ b/hw/super6502_fpga/ip/sdram_controller/sdram_controller.v @@ -0,0 +1,4347 @@ +// ============================================================================= +// Generated by efx_ipmgr +// Version: 2023.1.150 +// IP Version: 5.0 +// ============================================================================= + +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2023 Efinix Inc. All rights reserved. +// +// This document contains proprietary information which is +// protected by copyright. All rights are reserved. This notice +// refers to original work by Efinix, Inc. which may be derivitive +// of other work distributed under license of the authors. In the +// case of derivative work, nothing in this notice overrides the +// original author's license agreement. Where applicable, the +// original license agreement is included in it's original +// unmodified form immediately below this header. +// +// WARRANTY DISCLAIMER. +// THE DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND +// EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH +// RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, +// INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR +// PURPOSE. SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED +// WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE. +// +// LIMITATION OF LIABILITY. +// NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY +// INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT +// MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY +// OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, +// SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY +// CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF +// GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR +// MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN +// THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER +// (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE +// BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO +// NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR +// CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT +// APPLY TO LICENSEE. +// +//////////////////////////////////////////////////////////////////////////////// + +`define IP_UUID _5c381f4179ce404bb3abce25f7e88ca9 +`define IP_NAME_CONCAT(a,b) a``b +`define IP_MODULE_NAME(name) `IP_NAME_CONCAT(name,`IP_UUID) +module sdram_controller ( +input i_aresetn, +input [23:0] i_AXI4_AWADDR, +input i_sysclk, +input i_sdrclk, +input i_tACclk, +input i_pll_locked, +output o_dbg_ref_req, +output o_dbg_wr_ack, +output o_dbg_rd_ack, +output [1:0] o_dbg_n_CS, +output [1:0] o_dbg_n_RAS, +output [1:0] o_dbg_n_CAS, +output [1:0] o_dbg_n_WE, +output [3:0] o_dbg_BA, +output [25:0] o_dbg_ADDR, +output [31:0] o_dbg_DATA_out, +output [31:0] o_dbg_DATA_in, +output o_pll_reset, +output o_AXI4_AWREADY, +input i_AXI4_AWVALID, +output o_AXI4_WREADY, +input [31:0] i_AXI4_WDATA, +input [3:0] i_AXI4_WSTRB, +input i_AXI4_WLAST, +input i_AXI4_WVALID, +output o_AXI4_BVALID, +input i_AXI4_BREADY, +output o_AXI4_ARREADY, +input [23:0] i_AXI4_ARADDR, +input i_AXI4_RREADY, +output [31:0] o_AXI4_RDATA, +output o_AXI4_RLAST, +output o_AXI4_RVALID, +input [3:0] i_AXI4_AWID, +input [2:0] i_AXI4_AWSIZE, +input i_AXI4_ARVALID, +input [3:0] i_AXI4_ARID, +input [7:0] i_AXI4_ARLEN, +input [2:0] i_AXI4_ARSIZE, +input [1:0] i_AXI4_ARBURST, +input [7:0] i_AXI4_AWLEN, +output [3:0] o_AXI4_RID, +output o_dbg_we, +output o_dbg_last, +output [23:0] o_dbg_addr, +output [31:0] o_dbg_din, +output [1:0] o_axi4_wrstate, +output o_fifo_wr, +output o_fifo_full, +output o_fifo_empty, +output [7:0] o_dbg_fifo_waddr, +output o_dbg_fifo_re, +output [7:0] o_dbg_fifo_raddr, +output o_dbg_fifo_we, +output o_dbg_axi4_wlast, +output [6:0] o_shift_cnt, +output o_re_lock, +output [1:0] o_axi4_rastate, +output o_axi4_nwr, +output [7:0] o_axi4_arlen, +output [1:0] o_axi4_rdstate, +output o_sdr_rd_valid, +output [36:0] o_sdr_dout, +output o_dbg_re, +output [3:0] o_AXI4_BID, +input [23:0] i_addr, +input [31:0] i_din, +input [3:0] i_dm, +output [31:0] o_dout, +output [3:0] o_sdr_state, +output o_sdr_init_done, +output o_wr_ack, +output o_rd_ack, +output o_ref_req, +output o_rd_valid, +output [1:0] o_sdr_CKE, +output [1:0] o_sdr_n_CS, +output [1:0] o_sdr_n_RAS, +output [1:0] o_sdr_n_CAS, +output [1:0] o_sdr_n_WE, +output [3:0] o_sdr_BA, +output [25:0] o_sdr_ADDR, +output [31:0] o_sdr_DATA, +output [31:0] o_sdr_DATA_oe, +input [31:0] i_sdr_DATA, +output [3:0] o_sdr_DQM +); +`IP_MODULE_NAME(efx_sdram_controller) #( +.fSYS_MHz (100), +.fCK_MHz (200), +.tIORT_u (2), +.CL (3), +.BL (1), +.DDIO_TYPE ("SOFT"), +.DQ_WIDTH (8), +.DQ_GROUP (2), +.BA_WIDTH (2), +.ROW_WIDTH (13), +.COL_WIDTH (9), +.tPWRUP (200000), +.tRAS (44), +.tRAS_MAX (120000), +.tRC (66), +.tRCD (20), +.tREF (64000000), +.tRFC (66), +.tRP (20), +.tWR (2), +.tMRD (2), +.SDRAM_MODE ("AXI4"), +.DATA_RATE (2), +.AXI_AWADDR_WIDTH (24), +.AXI_WDATA_WIDTH (32), +.AXI_ARADDR_WIDTH (24), +.AXI_RDATA_WIDTH (32), +.AXI_AWID_WIDTH (4), +.AXI_AWUSER_WIDTH (2), +.AXI_WUSER_WIDTH (2), +.AXI_BID_WIDTH (4), +.AXI_BUSER_WIDTH (2), +.AXI_ARID_WIDTH (4), +.AXI_ARUSER_WIDTH (3), +.AXI_RUSER_WIDTH (3) +) u_efx_sdram_controller( +.i_aresetn ( i_aresetn ), +.i_AXI4_AWADDR ( i_AXI4_AWADDR ), +.i_sysclk ( i_sysclk ), +.i_sdrclk ( i_sdrclk ), +.i_tACclk ( i_tACclk ), +.i_pll_locked ( i_pll_locked ), +.o_dbg_ref_req ( o_dbg_ref_req ), +.o_dbg_wr_ack ( o_dbg_wr_ack ), +.o_dbg_rd_ack ( o_dbg_rd_ack ), +.o_dbg_n_CS ( o_dbg_n_CS ), +.o_dbg_n_RAS ( o_dbg_n_RAS ), +.o_dbg_n_CAS ( o_dbg_n_CAS ), +.o_dbg_n_WE ( o_dbg_n_WE ), +.o_dbg_BA ( o_dbg_BA ), +.o_dbg_ADDR ( o_dbg_ADDR ), +.o_dbg_DATA_out ( o_dbg_DATA_out ), +.o_dbg_DATA_in ( o_dbg_DATA_in ), +.o_pll_reset ( o_pll_reset ), +.o_AXI4_AWREADY ( o_AXI4_AWREADY ), +.i_AXI4_AWVALID ( i_AXI4_AWVALID ), +.o_AXI4_WREADY ( o_AXI4_WREADY ), +.i_AXI4_WDATA ( i_AXI4_WDATA ), +.i_AXI4_WSTRB ( i_AXI4_WSTRB ), +.i_AXI4_WLAST ( i_AXI4_WLAST ), +.i_AXI4_WVALID ( i_AXI4_WVALID ), +.o_AXI4_BVALID ( o_AXI4_BVALID ), +.i_AXI4_BREADY ( i_AXI4_BREADY ), +.o_AXI4_ARREADY ( o_AXI4_ARREADY ), +.i_AXI4_ARADDR ( i_AXI4_ARADDR ), +.i_AXI4_RREADY ( i_AXI4_RREADY ), +.o_AXI4_RDATA ( o_AXI4_RDATA ), +.o_AXI4_RLAST ( o_AXI4_RLAST ), +.o_AXI4_RVALID ( o_AXI4_RVALID ), +.i_AXI4_AWID ( i_AXI4_AWID ), +.i_AXI4_AWSIZE ( i_AXI4_AWSIZE ), +.i_AXI4_ARVALID ( i_AXI4_ARVALID ), +.i_AXI4_ARID ( i_AXI4_ARID ), +.i_AXI4_ARLEN ( i_AXI4_ARLEN ), +.i_AXI4_ARSIZE ( i_AXI4_ARSIZE ), +.i_AXI4_ARBURST ( i_AXI4_ARBURST ), +.i_AXI4_AWLEN ( i_AXI4_AWLEN ), +.o_AXI4_RID ( o_AXI4_RID ), +.o_dbg_we ( o_dbg_we ), +.o_dbg_last ( o_dbg_last ), +.o_dbg_addr ( o_dbg_addr ), +.o_dbg_din ( o_dbg_din ), +.o_axi4_wrstate ( o_axi4_wrstate ), +.o_fifo_wr ( o_fifo_wr ), +.o_fifo_full ( o_fifo_full ), +.o_fifo_empty ( o_fifo_empty ), +.o_dbg_fifo_waddr ( o_dbg_fifo_waddr ), +.o_dbg_fifo_re ( o_dbg_fifo_re ), +.o_dbg_fifo_raddr ( o_dbg_fifo_raddr ), +.o_dbg_fifo_we ( o_dbg_fifo_we ), +.o_dbg_axi4_wlast ( o_dbg_axi4_wlast ), +.o_shift_cnt ( o_shift_cnt ), +.o_re_lock ( o_re_lock ), +.o_axi4_rastate ( o_axi4_rastate ), +.o_axi4_nwr ( o_axi4_nwr ), +.o_axi4_arlen ( o_axi4_arlen ), +.o_axi4_rdstate ( o_axi4_rdstate ), +.o_sdr_rd_valid ( o_sdr_rd_valid ), +.o_sdr_dout ( o_sdr_dout ), +.o_dbg_re ( o_dbg_re ), +.o_AXI4_BID ( o_AXI4_BID ), +.i_addr ( i_addr ), +.i_din ( i_din ), +.i_dm ( i_dm ), +.o_dout ( o_dout ), +.o_sdr_state ( o_sdr_state ), +.o_sdr_init_done ( o_sdr_init_done ), +.o_wr_ack ( o_wr_ack ), +.o_rd_ack ( o_rd_ack ), +.o_ref_req ( o_ref_req ), +.o_rd_valid ( o_rd_valid ), +.o_sdr_CKE ( o_sdr_CKE ), +.o_sdr_n_CS ( o_sdr_n_CS ), +.o_sdr_n_RAS ( o_sdr_n_RAS ), +.o_sdr_n_CAS ( o_sdr_n_CAS ), +.o_sdr_n_WE ( o_sdr_n_WE ), +.o_sdr_BA ( o_sdr_BA ), +.o_sdr_ADDR ( o_sdr_ADDR ), +.o_sdr_DATA ( o_sdr_DATA ), +.o_sdr_DATA_oe ( o_sdr_DATA_oe ), +.i_sdr_DATA ( i_sdr_DATA ), +.o_sdr_DQM ( o_sdr_DQM ) +); + +endmodule + +///////////////////////////////////////////////////////////////////////////// +// _____ +// / _______ Copyright (C) 2013-2020 Efinix Inc. All rights reserved. +// / / \ +// / / .. / `IP_MODULE_NAME(axi4_sdram_controller).v +// / / .' / +// __/ /.' / Description: +// __ \ / sdram contronller top with AXI4 interface +// /_/ /\ \_____/ / +// ____/ \_______/ +// +// ******************************* +// Revisions: +// 1.0 Initial rev +// Support ONLY AXI 32-bit data to SDRAM total DQ x16 half rate +// +// ******************************* +///////////////////////////////////////////////////////////////////////////// +// AxSIZE +`define BYTES_TX_1 3'b000 +`define BYTES_TX_2 3'b001 +`define BYTES_TX_4 3'b010 +`define BYTES_TX_8 3'b011 +`define BYTES_TX_16 3'b100 +`define BYTES_TX_32 3'b101 +`define BYTES_TX_64 3'b110 +`define BYTES_TX_128 3'b111 +`define OKAY 2'b00 + +module `IP_MODULE_NAME(axi4_sdram_controller) +#( + parameter AXI_AWADDR_WIDTH = 32, + parameter AXI_WDATA_WIDTH = 32, + parameter AXI_ARADDR_WIDTH = 32, + parameter AXI_RDATA_WIDTH = 32, + + parameter fSYS_MHz = 100, + parameter fCK_MHz = 100, + parameter DDIO_TYPE = "SOFT", + parameter tPWRUP = 100, // 100 us + parameter tRAS = 44, // 44 ns + parameter tRAS_MAX = 120, // 120 us + parameter tRC = 66, // 66 ns + parameter tRCD = 20, // 20 ns + parameter tREF = 64, // 64 ms + parameter tRFC = 66, // 66 ns + parameter tRP = 20, // 20 ns + parameter tWR = 2, // 1 CK+7.5 ns + parameter tMRD = 2, // 2 CK + parameter CL = 3, // 3 CK + parameter BL = 1, + parameter DATA_RATE = 1, + parameter tIORT_u = 2, + parameter BA_WIDTH = 2, + parameter ROW_WIDTH = 10, + parameter COL_WIDTH = 10, + parameter DQ_WIDTH = 8, // x4, x8 + parameter DQ_GROUP = 8, + // x4 x8 x16 x32 + // DQ_WIDTH 4 8 8 8 + // DQ_GROUP 1 1 2 4 + // AXI not support DQ_WIDTH = 4 DQ_GROUP = 1 + + //----- parameter not configurable by user---- + parameter AXI_AWID_WIDTH = 4, + parameter AXI_AWUSER_WIDTH = 2, + parameter AXI_WUSER_WIDTH = 2, + parameter AXI_BID_WIDTH = 4, + parameter AXI_BUSER_WIDTH = 2, + parameter AXI_ARID_WIDTH = 4, + parameter AXI_ARUSER_WIDTH = 2, + parameter AXI_RUSER_WIDTH = 2 +) +( + input i_aresetn, + input i_sysclk, + input i_sdrclk, + input i_tACclk, + input i_pll_locked, + output o_pll_reset, + + // Compulsory + output o_AXI4_AWREADY, + input [AXI_AWADDR_WIDTH-1:0]i_AXI4_AWADDR, + input [2:0]i_AXI4_AWPROT, // Dummy + input i_AXI4_AWVALID, + + output o_AXI4_WREADY, + input [AXI_WDATA_WIDTH/8-1:0]i_AXI4_WSTRB, + input [AXI_WDATA_WIDTH-1:0]i_AXI4_WDATA, + input i_AXI4_WLAST, + input i_AXI4_WVALID, + + output o_AXI4_BVALID, + input i_AXI4_BREADY, + + output o_AXI4_ARREADY, + input [AXI_ARADDR_WIDTH-1:0]i_AXI4_ARADDR, + input [2:0]i_AXI4_ARPROT, // Dummy + input i_AXI4_ARVALID, + + input i_AXI4_RREADY, + output [AXI_RDATA_WIDTH-1:0]o_AXI4_RDATA, + output o_AXI4_RLAST, + output o_AXI4_RVALID, + + // Optional + input [AXI_AWID_WIDTH-1:0]i_AXI4_AWID, + input [3:0]i_AXI4_AWREGION, // Dummy + input [7:0]i_AXI4_AWLEN, // Dummy + input [2:0]i_AXI4_AWSIZE, + input [1:0]i_AXI4_AWBURST, // Dummy + input i_AXI4_AWLOCK, // Dummy + input [3:0]i_AXI4_AWCACHE, // Dummy + input [3:0]i_AXI4_AWQOS, // Dummy + input [AXI_AWUSER_WIDTH-1:0]i_AXI4_AWUSER, // Dummy + + input [AXI_WUSER_WIDTH-1:0]i_AXI4_WUSER, // Dummy + + output [AXI_BID_WIDTH-1:0]o_AXI4_BID, + output [1:0]o_AXI4_BRESP, // Dummy + output [AXI_BUSER_WIDTH-1:0]o_AXI4_BUSER, // Dummy + + input [AXI_ARID_WIDTH-1:0]i_AXI4_ARID, + input [3:0]i_AXI4_ARREGION, // Dummy + input [7:0]i_AXI4_ARLEN, + input [2:0]i_AXI4_ARSIZE, + input [1:0]i_AXI4_ARBURST, // Dummy + input i_AXI4_ARLOCK, // Dummy + input [3:0]i_AXI4_ARCACHE, // Dummy + input [3:0]i_AXI4_ARQOS, // Dummy + input [AXI_ARUSER_WIDTH-1:0]i_AXI4_ARUSER, // Dummy + + output [AXI_ARID_WIDTH-1:0]o_AXI4_RID, + output [1:0]o_AXI4_RRESP, // Dummy + output [AXI_RUSER_WIDTH-1:0]o_AXI4_RUSER, // Dummy + + output [DATA_RATE -1:0] o_sdr_CKE, + output [DATA_RATE -1:0] o_sdr_n_CS, + output [DATA_RATE -1:0] o_sdr_n_RAS, + output [DATA_RATE -1:0] o_sdr_n_CAS, + output [DATA_RATE -1:0] o_sdr_n_WE, + output [DATA_RATE *BA_WIDTH -1:0] o_sdr_BA, + output [DATA_RATE *ROW_WIDTH -1:0] o_sdr_ADDR, + output [DATA_RATE *DQ_GROUP *DQ_WIDTH -1:0] o_sdr_DATA, + output [DATA_RATE *DQ_GROUP *DQ_WIDTH -1:0] o_sdr_DATA_oe, + input [DATA_RATE *DQ_GROUP *DQ_WIDTH -1:0] i_sdr_DATA, + output [DATA_RATE *DQ_GROUP -1:0] o_sdr_DQM, + + // Debug port + output [3:0]o_sdr_state, + output o_dbg_we, + output o_dbg_re, + output o_dbg_last, + output [BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:0]o_dbg_addr, + output [AXI_WDATA_WIDTH-1:0]o_dbg_din, + output o_dbg_wr_ack, + output o_dbg_rd_ack, + output o_sdr_rd_valid, + output o_dbg_ref_req, + output [DATA_RATE*DQ_GROUP*DQ_WIDTH+AXI_ARID_WIDTH:0]o_sdr_dout, + output [1:0]o_axi4_wrstate, + output o_dbg_axi4_wlast, + output [1:0]o_axi4_rastate, + output [1:0]o_axi4_rdstate, + output o_axi4_nwr, + output o_re_lock, + output [6:0]o_shift_cnt, + output [7:0]o_axi4_arlen, + output o_fifo_wr, + output o_fifo_full, + output o_fifo_empty, + output o_dbg_fifo_we, + output [7:0]o_dbg_fifo_waddr, + output o_dbg_fifo_re, + output [7:0]o_dbg_fifo_raddr, + + output [DATA_RATE -1:0] o_dbg_n_CS, + output [DATA_RATE -1:0] o_dbg_n_RAS, + output [DATA_RATE -1:0] o_dbg_n_CAS, + output [DATA_RATE -1:0] o_dbg_n_WE, + output [DATA_RATE *BA_WIDTH -1:0] o_dbg_BA, + output [DATA_RATE *ROW_WIDTH -1:0] o_dbg_ADDR, + output [DATA_RATE *DQ_GROUP *DQ_WIDTH -1:0] o_dbg_DATA_out, + output [DATA_RATE *DQ_GROUP *DQ_WIDTH -1:0] o_dbg_DATA_in +); + +function integer log2; + input integer val; + integer i; + begin + log2 = 0; + for (i=0; 2**i= AXI_BID_WIDTH) + r_AXI4_BID_1P <= i_AXI4_AWID[AXI_BID_WIDTH-1:0]; + else + r_AXI4_BID_1P <= {{AXI_BID_WIDTH-AXI_AWID_WIDTH{1'b0}}, i_AXI4_AWID}; + + r_we_1P <= 1'b1; + // TODO AXI different width support + if (SDR_BWIDTH > AXI_WDATA_WIDTH) + begin + r_addr_1P[0+:BA_WIDTH+ROW_WIDTH+COL_WIDTH-(0-SDR_BWIDTH/AXI_WDATA_WIDTH+1)] <= i_AXI4_AWADDR[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:0-SDR_BWIDTH/AXI_WDATA_WIDTH+1]; + // $display("foo_gt\n"); + end + else if (SDR_BWIDTH == AXI_WDATA_WIDTH) + begin + r_addr_1P <= {i_AXI4_AWADDR[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:COL_WIDTH], {(DATA_RATE-1){1'b0}}, i_AXI4_AWADDR[COL_WIDTH-1:DATA_RATE-1]}; + //r_addr_1P <= {{(DATA_RATE-1){1'b0}},i_AXI4_AWADDR[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:DATA_RATE-1]}; + // $display("foo_eq\n"); + end + + if (SDR_BWIDTH > AXI_WDATA_WIDTH) + begin + //r_AXI4_WREADY_c <= 1'b1; + r_size_1P <= SDR_BWIDTH/AXI_WDATA_WIDTH-1'b1; + r_shift_cnt_1P <= SDR_BWIDTH/AXI_WDATA_WIDTH-1'b1; + // $display("SDR_BWIDTH %d > AXI_WDATA_WIDTH %d\n", SDR_BWIDTH, AXI_WDATA_WIDTH); + end + else if (SDR_BWIDTH == AXI_WDATA_WIDTH) + begin + if (i_AXI4_WLAST) + begin + r_din_1P <= i_AXI4_WDATA; + r_dm_1P <= i_AXI4_WSTRB ^ {(AXI_WDATA_WIDTH/8){1'b1}}; //bitwise XOR to inver the bit + r_last_1P <= 1'b1; + end + r_size_1P <= SDR_BWIDTH/AXI_WDATA_WIDTH-1'b1; + r_shift_cnt_1P <= {7{1'b0}}; + // $display("SDR_BWIDTH %d = AXI_WDATA_WIDTH %d\n", SDR_BWIDTH, AXI_WDATA_WIDTH); + end + else + begin + //r_AXI4_WREADY_c <= 1'b1; + r_size_1P <= AXI_WDATA_WIDTH/SDR_BWIDTH-1'b1; + r_shift_cnt_1P <= AXI_WDATA_WIDTH/SDR_BWIDTH-1'b1; + // $display("SDR_BWIDTH %d < AXI_WDATA_WIDTH %d\n", SDR_BWIDTH, AXI_WDATA_WIDTH); + end + end + end + + s_WR_SHIFT: + begin + if (SDR_BWIDTH > AXI_WDATA_WIDTH) + begin + if (r_shift_cnt_1P != 7'd0) + begin + if (r_AXI4_WREADY_c) + r_shift_cnt_1P <= r_shift_cnt_1P-1'b1; + end + else + begin + r_shift_cnt_1P <= r_size_1P; + end + end + else if (SDR_BWIDTH == AXI_WDATA_WIDTH) + begin + if (r_AXI4_WREADY_2P) + r_addr_1P <= r_addr_1P+c_addr_increment; + + if (r_AXI4_WREADY_c) + begin + r_din_1P <= i_AXI4_WDATA; + r_dm_1P <= i_AXI4_WSTRB ^ {(AXI_WDATA_WIDTH/8){1'b1}}; //bitwise XOR to inver the bit; + end + + if (~r_AXI4_WREADY_c & r_AXI4_WREADY_2P & i_AXI4_WLAST) + begin + r_din_1P <= i_AXI4_WDATA; + r_dm_1P <= i_AXI4_WSTRB ^ {(AXI_WDATA_WIDTH/8){1'b1}}; //bitwise XOR to inver the bit; + end + end + + if (w_wr_ack) + begin + /*if (SDR_BWIDTH < AXI_WDATA_WIDTH) + begin + if (r_size_1P != `BYTES_TX_1) + r_addr_1P <= r_addr_1P+c_addr_increment; + else if (~r_wr_ack_1P) + r_addr_1P <= r_addr_1P+c_addr_increment; + else if (r_AXI4_WREADY_2P) + r_addr_1P <= r_addr_1P+c_addr_increment; + + r_shift_cnt_1P <= r_shift_cnt_1P-1'b1; + if (r_AXI4_WLAST_1P && r_shift_cnt_1P == 7'd1) + r_last_1P <= 1'b1; + end + else if (SDR_BWIDTH == AXI_WDATA_WIDTH) + begin + r_AXI4_WREADY_c <= 1'b1; + end + else + begin + r_AXI4_WREADY_c <= 1'b1; + + if (r_AXI4_WREADY_c) + r_addr_1P <= r_addr_1P+1'b1; + + if (r_shift_cnt_1P == 7'd1) + begin + if (i_AXI4_WLAST || r_AXI4_WLAST_1P) + begin + r_axi4_wrstate_1P <= s_WR_RESP; + r_AXI4_WREADY_c <= 1'b0; + r_AXI4_WLAST_1P <= 1'b0; + r_AXI4_BVALID_1P <= 1'b1; + + r_last_1P <= 1'b1; + end + end + end*/ + + if (r_shift_cnt_1P == 7'd0) + begin + //r_AXI4_WREADY_c <= 1'b1; + + r_AXI4_WLAST_1P <= i_AXI4_WLAST; + r_shift_cnt_1P <= r_size_1P; + + if (i_AXI4_WLAST && r_size_1P == {7{1'b0}} && r_AXI4_AWLEN_1P) + begin + r_axi4_wrstate_1P <= s_WR_RESP; + //r_AXI4_WREADY_c <= ~r_AXI4_WREADY_c; + r_AXI4_WLAST_1P <= 1'b0; + r_AXI4_BVALID_1P <= 1'b1; + + r_we_1P <= 1'b1; + r_last_1P <= 1'b1; + end + else if (r_AXI4_WLAST_1P) + begin + r_axi4_wrstate_1P <= s_WR_RESP; + //r_AXI4_WREADY_c <= ~r_AXI4_WREADY_c; + r_AXI4_WLAST_1P <= 1'b0; + r_AXI4_BVALID_1P <= 1'b1; + + r_we_1P <= 1'b0; + r_last_1P <= 1'b0; + end + end + end + end + + s_WR_RESP: + begin + r_we_1P <= 1'b0; + r_last_1P <= 1'b0; + + if (i_AXI4_BREADY) + begin + r_axi4_wrstate_1P <= s_IDLE; + r_AXI4_BVALID_1P <= 1'b0; + end + end + endcase + + case (r_axi4_rastate_1P) + s_INIT: + begin + if (w_sdr_init_done) + r_axi4_rastate_1P <= s_IDLE; + end + + s_IDLE: + begin + if (i_AXI4_ARVALID && r_axi4_nwr_1P + && ~r_we_1P && ~w_afull && ~r_AXI4_RVALID_1P) + begin + r_axi4_rastate_1P <= s_RD_ADDR; + r_AXI4_ARREADY_1P <= 1'b1; + r_AXI4_RID_1P <= i_AXI4_ARID; + + r_re_1P <= 1'b1; + r_re_lock_1P <= 1'b1; + if (i_AXI4_ARLEN == 8'd0 && (SDR_BWIDTH == AXI_RDATA_WIDTH)) + r_last_1P <= 1'b1; + + // TODO AXI different width support + if (SDR_BWIDTH > AXI_RDATA_WIDTH) + begin + r_addr_1P[0+:BA_WIDTH+ROW_WIDTH+COL_WIDTH-(0-SDR_BWIDTH/AXI_RDATA_WIDTH+1)] <= i_AXI4_ARADDR[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:0-SDR_BWIDTH/AXI_RDATA_WIDTH+1]; + end + else if (SDR_BWIDTH == AXI_RDATA_WIDTH) + begin + r_addr_1P <= {i_AXI4_ARADDR[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:COL_WIDTH], {(DATA_RATE-1){1'b0}}, i_AXI4_ARADDR[COL_WIDTH-1:DATA_RATE-1]}; + //r_addr_1P <= {{(DATA_RATE-1){1'b0}},i_AXI4_ARADDR[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:DATA_RATE-1]}; + end + + if (SDR_BWIDTH > AXI_WDATA_WIDTH) + begin + r_size_1P <= SDR_BWIDTH/AXI_RDATA_WIDTH-1'b1; + r_shift_cnt_1P <= SDR_BWIDTH/AXI_RDATA_WIDTH-1'b1; + r_addr_cnt_1P <= SDR_BWIDTH/AXI_RDATA_WIDTH-1'b1; + end + else if (SDR_BWIDTH == AXI_WDATA_WIDTH) + begin + r_AXI4_ARLEN_1P <= i_AXI4_ARLEN; + r_size_1P <= 7'd0; + r_shift_cnt_1P <= 7'd0; + r_addr_cnt_1P <= 7'd0; + r_arlen_cnt_1P <= i_AXI4_ARLEN; + end + else + begin + r_AXI4_ARLEN_1P <= i_AXI4_ARLEN; + r_size_1P <= AXI_RDATA_WIDTH/SDR_BWIDTH-1'b1; + r_shift_cnt_1P <= AXI_RDATA_WIDTH/SDR_BWIDTH-1'b1; + r_addr_cnt_1P <= AXI_RDATA_WIDTH/SDR_BWIDTH-1'b1; + r_arlen_cnt_1P <= i_AXI4_ARLEN; + end + end + end + + s_RD_ADDR: + begin + if (~w_afull) + r_re_1P <= 1'b1; + + if (w_rd_ack) + begin + if (w_afull) + r_re_1P <= 1'b0; + if (SDR_BWIDTH < AXI_WDATA_WIDTH) + r_addr_1P <= r_addr_1P+c_addr_increment; + else if (SDR_BWIDTH == AXI_WDATA_WIDTH) + r_addr_1P <= r_addr_1P+c_addr_increment; + else + r_addr_1P <= r_addr_1P+1'b1; + + r_addr_cnt_1P <= r_addr_cnt_1P-1'b1; + if (r_addr_cnt_1P == 7'd0) + begin + r_addr_cnt_1P <= r_size_1P; + r_arlen_cnt_1P <= r_arlen_cnt_1P-1'b1; + end + + if (r_arlen_cnt_1P == 8'd1 && (SDR_BWIDTH == AXI_RDATA_WIDTH)) + r_last_1P <= 1'b1; + + if (r_arlen_cnt_1P == 8'd0) + begin + if (r_addr_cnt_1P == 8'd1) + r_last_1P <= 1'b1; + + if (r_addr_cnt_1P == 8'd0) + begin + r_axi4_rastate_1P <= s_IDLE; + + r_re_1P <= 1'b0; + r_last_1P <= 1'b0; + r_re_lock_1P <= 1'b0; + end + end + end + end + endcase + + if (w_rd_valid) + begin + if (SDR_BWIDTH >= AXI_RDATA_WIDTH) + begin + r_dout_1P[DOUT_WIDTH-1:0] <= w_dout; + end + + r_dout_1P[DOUT_WIDTH+AXI_ARID_WIDTH-1:DOUT_WIDTH] <= r_AXI4_RID[CL+tIORT+1]; + + r_shift_cnt_1P <= r_shift_cnt_1P-1'b1; + + if (r_shift_cnt_1P == 7'd0) + begin + r_fifo_wr_1P <= 1'b1; + + if (arlen_cnt == r_AXI4_ARLEN_1P) begin + arlen_cnt <= {9{1'b0}}; + end + else begin + arlen_cnt <= arlen_cnt+1'b1; + end + + if (arlen_cnt == r_AXI4_ARLEN_1P) + r_dout_1P[DOUT_WIDTH+AXI_ARID_WIDTH] <= 1'b1; + else + r_dout_1P[DOUT_WIDTH+AXI_ARID_WIDTH] <= 1'b0; + r_shift_cnt_1P <= r_size_1P; + end + end + + case (r_axi4_rdstate_1P) + s_INIT: + begin + if (w_sdr_init_done) + r_axi4_rdstate_1P <= s_IDLE; + end + + s_IDLE: + begin + if (~w_empty & r_dout_1P[DOUT_WIDTH+AXI_ARID_WIDTH]) + begin + r_axi4_rdstate_1P <= s_RD_SHIFT; + r_fifo_rd_1P <= 1'b1; + r_dout_1P[DOUT_WIDTH+AXI_ARID_WIDTH] <= 1'b0; + end + end + + s_RD_SHIFT: + begin + r_AXI4_RVALID_1P <= 1'b1; + + if (i_AXI4_RREADY) + begin + if (w_empty) + begin + r_axi4_rdstate_1P <= s_IDLE; + r_AXI4_RVALID_1P <= 1'b0; + end + + if (rd_last) + begin + r_axi4_rdstate_1P <= s_IDLE; + r_AXI4_RVALID_1P <= 1'b0; + end + end + end + endcase + end +end + +genvar i; +generate + for (i=0; i 1) begin + `IP_MODULE_NAME(sdram_io_block) + #( + .DATA_RATE (DATA_RATE), + .BA_WIDTH (BA_WIDTH), + .ROW_WIDTH (ROW_WIDTH), + .COL_WIDTH (COL_WIDTH), + .DQ_WIDTH (DQ_WIDTH), + .DQ_GROUP (DQ_GROUP) + ) + inst_sdram_io_block + ( + .i_arst (i_arst), + .i_sysclk (i_sysclk), + .i_sdrclk (i_sdrclk), + .i_tACclk (i_tACclk), + .i_pll_locked (i_pll_locked), + + .i_sdr_CKE_core (w_sdr_CKE), + .i_sdr_n_CS_core (w_sdr_n_CS), + .i_sdr_n_RAS_core (w_sdr_n_RAS), + .i_sdr_n_CAS_core (w_sdr_n_CAS), + .i_sdr_n_WE_core (w_sdr_n_WE), + .i_sdr_BA_core (w_sdr_BA), + .i_sdr_ADDR_core (w_sdr_ADDR), + .i_sdr_DATA_core (w_sdr_DATA_out), + .i_sdr_DATA_oe_core (w_sdr_DATA_oe), + .o_sdr_DATA_core (w_sdr_DATA_in), + .i_sdr_DQM_core (w_sdr_DQM), + + .o_sdr_CKE_pad (o_sdr_CKE), + .o_sdr_n_CS_pad (o_sdr_n_CS), + .o_sdr_n_RAS_pad (o_sdr_n_RAS), + .o_sdr_n_CAS_pad (o_sdr_n_CAS), + .o_sdr_n_WE_pad (o_sdr_n_WE), + .o_sdr_BA_pad (o_sdr_BA), + .o_sdr_ADDR_pad (o_sdr_ADDR), + .o_sdr_DATA_pad (o_sdr_DATA), + .o_sdr_DATA_oe_pad (o_sdr_DATA_oe), + .i_sdr_DATA_pad (i_sdr_DATA), + .o_sdr_DQM_pad (o_sdr_DQM) + ); +end +else begin + reg [DATA_RATE *DQ_GROUP *DQ_WIDTH -1:0]r_sdr_DATA_in_tACclk_1P; + + always@(posedge i_arst or posedge i_tACclk) + begin + if (i_arst) + r_sdr_DATA_in_tACclk_1P <= {DATA_RATE*DQ_GROUP*DQ_WIDTH{1'b0}}; + else + r_sdr_DATA_in_tACclk_1P <= i_sdr_DATA; + end + + assign w_sdr_DATA_in = r_sdr_DATA_in_tACclk_1P; + assign o_sdr_CKE = w_sdr_CKE; + assign o_sdr_n_CS = w_sdr_n_CS; + assign o_sdr_n_RAS = w_sdr_n_RAS; + assign o_sdr_n_CAS = w_sdr_n_CAS; + assign o_sdr_n_WE = w_sdr_n_WE; + assign o_sdr_BA = w_sdr_BA; + assign o_sdr_ADDR = w_sdr_ADDR; + assign o_sdr_DATA = w_sdr_DATA_out; + assign o_sdr_DATA_oe = w_sdr_DATA_oe; + assign o_sdr_DQM = w_sdr_DQM; +end +endgenerate + +assign o_dbg_DATA_out = w_sdr_DATA_out; +assign o_dbg_DATA_in = w_sdr_DATA_in; + +endmodule + +////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2019 Efinix Inc. All rights reserved. +// +// This document contains proprietary information which is +// protected by copyright. All rights are reserved. This notice +// refers to original work by Efinix, Inc. which may be derivitive +// of other work distributed under license of the authors. In the +// case of derivative work, nothing in this notice overrides the +// original author's license agreement. Where applicable, the +// original license agreement is included in it's original +// unmodified form immediately below this header. +// +// WARRANTY DISCLAIMER. +// THE DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND +// EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH +// RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, +// INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR +// PURPOSE. SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED +// WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE. +// +// LIMITATION OF LIABILITY. +// NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY +// INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT +// MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY +// OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, +// SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY +// CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF +// GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR +// MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN +// THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER +// (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE +// BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO +// NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR +// CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT +// APPLY TO LICENSEE. +// +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// _____ +// / _______ Copyright (C) 2013-2020 Efinix Inc. All rights reserved. +// / / \ +// / / .. / `IP_MODULE_NAME(sdram_fsm).v +// / / .' / +// __/ /.' / Description: +// __ \ / sdram controller state machine +// /_/ /\ \_____/ / +// ____/ \_______/ +// +// ******************************* +// Revisions: +// 1.0 Initial rev +// +// ******************************* + +module `IP_MODULE_NAME(sdram_fsm) +#( + parameter fSYS_MHz = 100, + parameter fCK_MHz = 200, // MHz + parameter DLY_CNT_A_WIDTH = 6, + parameter DLY_CNT_B_WIDTH = 6, + parameter CHECK_ACT_BA = 4, + parameter REF_LATENCY = 2, // + + parameter tPWRUP = 200, // 100 us + parameter tRAS = 44, // 44 ns + parameter tRAS_MAX = 120000, // 120 us + parameter tRC = 66, // 66 ns + parameter tRCD = 20, // 20 ns + parameter tREF = 64, // 64 ms + parameter tRFC = 66, // 66 ns + parameter tRP = 20, // 20 ns + parameter tWR = 2, // 1 CK+7.5 ns + parameter tMRD = 2, // 2 CK + parameter CL = 3, // 3 CK + parameter BL = 1, + parameter tIORT = 2, + parameter DDIO_TYPE = "SOFT", + parameter DATA_RATE = 2, + parameter BA_WIDTH = 2, + parameter ROW_WIDTH = 13, + parameter COL_WIDTH = 10, + parameter DQ_WIDTH = 8, // x4, x8 + parameter DQ_GROUP = 4 + // x4 x8 x16 x32 + // DQ_WIDTH 4 8 8 8 + // DQ_GROUP 1 1 2 4 +) +( + input i_arst, + input i_sysclk, + input i_pll_locked, + + input i_we, + input i_re, + input i_last, + input [ (BA_WIDTH+ROW_WIDTH+COL_WIDTH) -1:0] i_addr, + input [DATA_RATE *DQ_GROUP *DQ_WIDTH -1:0] i_din, + input [(DATA_RATE *DQ_GROUP) -1:0] i_dm, + output [DATA_RATE *DQ_GROUP *DQ_WIDTH -1:0] o_dout, + output [3:0]o_sdr_state, + output o_sdr_init_done, + output o_wr_ack, + output o_rd_ack, + output o_ref_req, + output o_rd_valid, + + output [DATA_RATE -1:0] o_sdr_CKE, + output [DATA_RATE -1:0] o_sdr_n_CS, + output [DATA_RATE -1:0] o_sdr_n_RAS, + output [DATA_RATE -1:0] o_sdr_n_CAS, + output [DATA_RATE -1:0] o_sdr_n_WE, + output [DATA_RATE *BA_WIDTH -1:0] o_sdr_BA, + output [DATA_RATE *ROW_WIDTH -1:0] o_sdr_ADDR, + output [DATA_RATE *DQ_GROUP *DQ_WIDTH -1:0] o_sdr_DATA, + output [DATA_RATE *DQ_GROUP *DQ_WIDTH -1:0] o_sdr_DATA_oe, + input [DATA_RATE *DQ_GROUP *DQ_WIDTH -1:0] i_sdr_DATA, + output [DATA_RATE *DQ_GROUP -1:0] o_sdr_DQM, + + output [5:0]o_dbg_dly_cnt_b, + output o_dbg_tRCD_done, + output o_dbg_tRTW_done, + output o_dbg_ref_req, + output o_dbg_wr_ack, + output o_dbg_rd_ack, + output [DATA_RATE -1:0] o_dbg_n_CS, + output [DATA_RATE -1:0] o_dbg_n_RAS, + output [DATA_RATE -1:0] o_dbg_n_CAS, + output [DATA_RATE -1:0] o_dbg_n_WE, + output [DATA_RATE *BA_WIDTH -1:0] o_dbg_BA, + output [DATA_RATE *ROW_WIDTH -1:0] o_dbg_ADDR +); + +function integer log2; + input integer val; + integer i; + begin + log2 = 0; + for (i=0; 2**i> b; + end + end + end + + r_sdr_dq_1P <= i_din; + r_sdr_dm_1P <= i_dm; + r_sdr_dqoe_1P <= {DATA_RATE*DQ_GROUP*DQ_WIDTH{1'b1}}; + + r_dly_cnt_b_1P <= {DLY_CNT_B_WIDTH{1'b0}}; + r_tWR_done_1P <= 1'b0; + + r_wr_ack_1P <= ~r_ref_req_1P[0]; + + if (REF_LATENCY > 2) begin + if (r_ref_req_1P[1] || r_tRAS_MAX_done_1P[1] || (i_last & r_wr_ack_1P)) // + begin + r_sdr_cmd_1P <= {DATA_RATE{c_NOP}}; + r_sdr_dqoe_1P <= {DATA_RATE*DQ_GROUP*DQ_WIDTH{1'b0}}; + r_wr_ack_1P <= 1'b0; + end + end + else begin + if (r_ref_req_1P[REF_LATENCY-2] || r_tRAS_MAX_done_1P[REF_LATENCY-2] || (i_last & r_wr_ack_1P)) + begin + r_sdr_cmd_1P <= {DATA_RATE{c_NOP}}; + r_sdr_dqoe_1P <= {DATA_RATE*DQ_GROUP*DQ_WIDTH{1'b0}}; + r_wr_ack_1P <= 1'b0; + end + end + + end + else if (~i_we && i_re) + begin + if (DATA_RATE == 1) + begin + r_sdr_cmd_1P <= c_RD; + r_sdr_ba_2P <= i_addr[BA_MSB:BA_LSB]; + r_sdr_addr_2P <= i_addr[COL_MSB:COL_LSB]; + end + else + begin + for (c=0; c> b; + end + end + end + + r_dly_cnt_b_1P <= {DLY_CNT_B_WIDTH{1'b0}}; + r_tRTW_done_1P <= 1'b0; + r_tRC_done_1P <= 1'b0; + + r_rd_ack_P[0] <= ~r_ref_req_1P[0]; + + if (REF_LATENCY > 2) begin + if (r_ref_req_1P[1] || r_tRAS_MAX_done_1P[1] || (i_last & r_rd_ack_P[0])) + begin + if (r_rd_ack_P[0]) + begin + r_sdr_cmd_1P <= {DATA_RATE{c_NOP}}; + r_sdr_dqoe_1P <= {DATA_RATE*DQ_GROUP*DQ_WIDTH{1'b0}}; + r_rd_ack_P[0] <= 1'b0; + end + end + end + else begin + if (r_ref_req_1P[REF_LATENCY-2] || r_tRAS_MAX_done_1P[REF_LATENCY-2] || (i_last & r_rd_ack_P[0])) + begin + if (r_rd_ack_P[0]) + begin + r_sdr_cmd_1P <= {DATA_RATE{c_NOP}}; + r_sdr_dqoe_1P <= {DATA_RATE*DQ_GROUP*DQ_WIDTH{1'b0}}; + r_rd_ack_P[0] <= 1'b0; + end + end + end + end + end + end + end + + s_PRE: + begin + if (r_dly_cnt_a_1P == nRP-1'b1) + begin + if (r_ref_req_1P[REF_LATENCY-1]) + begin + if (r_pre_allbank) // check if the previous PRE is ALL_BANK or SINGLE_BANK + begin + r_sdr_state_1P <= s_REF; + r_sdr_cmd_1P[CYC_A+:4] <= c_REF; + r_pre_allbank <= 1'b0; + r_dly_cnt_a_1P <= {DLY_CNT_A_WIDTH{1'b0}}; + end + else + begin // if the previous PRE is SINGLE_BANK, issue PRE to ALL_BANK before trigger AUTO-refresh + r_sdr_state_1P <= s_PRE; + r_sdr_cmd_1P[CYC_A+:4] <= c_PRE; + r_sdr_addr_1P[CYC_A+10] <= PRE_ALL; + r_pre_allbank <= 1'b1; + if (CHECK_ACT_BA == 4) + begin + r_act_row_1P[0][ROW_WIDTH] <= 1'b0; + r_act_row_1P[1][ROW_WIDTH] <= 1'b0; + r_act_row_1P[2][ROW_WIDTH] <= 1'b0; + r_act_row_1P[3][ROW_WIDTH] <= 1'b0; + end + r_dly_cnt_a_1P <= {DLY_CNT_A_WIDTH{1'b0}}; + end + end + else + begin + r_sdr_state_1P <= s_IDLE; + end + end + end + + s_REF: + begin + if (r_dly_cnt_a_1P == nRFC) + begin + r_sdr_state_1P <= s_IDLE; + r_ref_req_1P[0] <= 1'b0; + r_dly_cnt_d_1P <= {DLY_CNT_D_WIDTH{1'b0}}; + end + end + endcase + end +end + +assign o_sdr_state = r_sdr_state_1P; +assign o_sdr_init_done = r_sdr_init_done_1P; +assign o_wr_ack = r_wr_ack_1P; +genvar i; +generate + for (i=1; i<=RD_PIPE; i=i+1) + begin: readback + always@(posedge i_arst or posedge i_sysclk) + begin + if (i_arst) + r_rd_ack_P[i] <= 1'b0; + else + r_rd_ack_P[i] <= r_rd_ack_P[i-1]; + end + end +endgenerate +assign o_rd_ack = r_rd_ack_P[0]; +assign o_ref_req = r_ref_req_1P[0]; +assign o_rd_valid = r_rd_ack_P[RD_PIPE]; +assign o_dout = r_sdr_dqin_1P; + +assign o_sdr_CKE = r_sdr_cke_1P; +genvar j; +generate + for (j=0; j i_aresetn, +i_AXI4_AWADDR => i_AXI4_AWADDR, +i_sysclk => i_sysclk, +i_sdrclk => i_sdrclk, +i_tACclk => i_tACclk, +i_pll_locked => i_pll_locked, +o_dbg_ref_req => o_dbg_ref_req, +o_dbg_wr_ack => o_dbg_wr_ack, +o_dbg_rd_ack => o_dbg_rd_ack, +o_dbg_n_CS => o_dbg_n_CS, +o_dbg_n_RAS => o_dbg_n_RAS, +o_dbg_n_CAS => o_dbg_n_CAS, +o_dbg_n_WE => o_dbg_n_WE, +o_dbg_BA => o_dbg_BA, +o_dbg_ADDR => o_dbg_ADDR, +o_dbg_DATA_out => o_dbg_DATA_out, +o_dbg_DATA_in => o_dbg_DATA_in, +o_pll_reset => o_pll_reset, +o_AXI4_AWREADY => o_AXI4_AWREADY, +i_AXI4_AWVALID => i_AXI4_AWVALID, +o_AXI4_WREADY => o_AXI4_WREADY, +i_AXI4_WDATA => i_AXI4_WDATA, +i_AXI4_WSTRB => i_AXI4_WSTRB, +i_AXI4_WLAST => i_AXI4_WLAST, +i_AXI4_WVALID => i_AXI4_WVALID, +o_AXI4_BVALID => o_AXI4_BVALID, +i_AXI4_BREADY => i_AXI4_BREADY, +o_AXI4_ARREADY => o_AXI4_ARREADY, +i_AXI4_ARADDR => i_AXI4_ARADDR, +i_AXI4_RREADY => i_AXI4_RREADY, +o_AXI4_RDATA => o_AXI4_RDATA, +o_AXI4_RLAST => o_AXI4_RLAST, +o_AXI4_RVALID => o_AXI4_RVALID, +i_AXI4_AWID => i_AXI4_AWID, +i_AXI4_AWSIZE => i_AXI4_AWSIZE, +i_AXI4_ARVALID => i_AXI4_ARVALID, +i_AXI4_ARID => i_AXI4_ARID, +i_AXI4_ARLEN => i_AXI4_ARLEN, +i_AXI4_ARSIZE => i_AXI4_ARSIZE, +i_AXI4_ARBURST => i_AXI4_ARBURST, +i_AXI4_AWLEN => i_AXI4_AWLEN, +o_AXI4_RID => o_AXI4_RID, +o_dbg_we => o_dbg_we, +o_dbg_last => o_dbg_last, +o_dbg_addr => o_dbg_addr, +o_dbg_din => o_dbg_din, +o_axi4_wrstate => o_axi4_wrstate, +o_fifo_wr => o_fifo_wr, +o_fifo_full => o_fifo_full, +o_fifo_empty => o_fifo_empty, +o_dbg_fifo_waddr => o_dbg_fifo_waddr, +o_dbg_fifo_re => o_dbg_fifo_re, +o_dbg_fifo_raddr => o_dbg_fifo_raddr, +o_dbg_fifo_we => o_dbg_fifo_we, +o_dbg_axi4_wlast => o_dbg_axi4_wlast, +o_shift_cnt => o_shift_cnt, +o_re_lock => o_re_lock, +o_axi4_rastate => o_axi4_rastate, +o_axi4_nwr => o_axi4_nwr, +o_axi4_arlen => o_axi4_arlen, +o_axi4_rdstate => o_axi4_rdstate, +o_sdr_rd_valid => o_sdr_rd_valid, +o_sdr_dout => o_sdr_dout, +o_dbg_re => o_dbg_re, +o_AXI4_BID => o_AXI4_BID, +i_addr => i_addr, +i_din => i_din, +i_dm => i_dm, +o_dout => o_dout, +o_sdr_state => o_sdr_state, +o_sdr_init_done => o_sdr_init_done, +o_wr_ack => o_wr_ack, +o_rd_ack => o_rd_ack, +o_ref_req => o_ref_req, +o_rd_valid => o_rd_valid, +o_sdr_CKE => o_sdr_CKE, +o_sdr_n_CS => o_sdr_n_CS, +o_sdr_n_RAS => o_sdr_n_RAS, +o_sdr_n_CAS => o_sdr_n_CAS, +o_sdr_n_WE => o_sdr_n_WE, +o_sdr_BA => o_sdr_BA, +o_sdr_ADDR => o_sdr_ADDR, +o_sdr_DATA => o_sdr_DATA, +o_sdr_DATA_oe => o_sdr_DATA_oe, +i_sdr_DATA => i_sdr_DATA, +o_sdr_DQM => o_sdr_DQM); +------------------------ End INSTANTIATION Template --------- diff --git a/hw/super6502_fpga/ip/sdram_controller/settings.json b/hw/super6502_fpga/ip/sdram_controller/settings.json new file mode 100644 index 0000000..a021290 --- /dev/null +++ b/hw/super6502_fpga/ip/sdram_controller/settings.json @@ -0,0 +1,44 @@ +{ + "args": [ + "-o", + "sdram_controller", + "--base_path", + "/home/byron/Projects/super6502/hw/super6502_fpga/ip", + "--vlnv", + { + "vendor": "efinixinc.com", + "library": "memory_controller", + "name": "efx_sdram_controller", + "version": "5.0" + } + ], + "conf": { + "fCK_MHz": "200", + "tIORT_u": "2", + "CL": "3", + "DDIO_TYPE": "\"SOFT\"", + "DQ_GROUP": "2", + "ROW_WIDTH": "13", + "COL_WIDTH": "9", + "tPWRUP": "200000", + "tRAS": "44", + "tRAS_MAX": "120000", + "tRC": "66", + "tRCD": "20", + "tREF": "64000000", + "tRFC": "66", + "tRP": "20", + "SDRAM_MODE": "\"AXI4\"", + "DATA_RATE": "2" + }, + "output": { + "external_source_source": [ + "/home/byron/Projects/super6502/hw/super6502_fpga/ip/sdram_controller/sdram_controller_tmpl.v", + "/home/byron/Projects/super6502/hw/super6502_fpga/ip/sdram_controller/sdram_controller.v", + "/home/byron/Projects/super6502/hw/super6502_fpga/ip/sdram_controller/sdram_controller_tmpl.vhd", + "/home/byron/Projects/super6502/hw/super6502_fpga/ip/sdram_controller/sdram_controller_define.vh" + ] + }, + "sw_version": "2023.1.150", + "generated_date": "2024-03-04T01:51:33.450281" +} \ No newline at end of file diff --git a/hw/super6502_fpga/sources.list b/hw/super6502_fpga/sources.list index e717faa..b9113d1 100644 --- a/hw/super6502_fpga/sources.list +++ b/hw/super6502_fpga/sources.list @@ -11,4 +11,4 @@ src/sub/rtl-common/src/rtl/axi4_lite_rom.sv src/sub/rtl-common/src/rtl/ff_cdc.sv src/sub/rtl-common/src/rtl/shallow_async_fifo.sv src/sub/rtl-common/src/rtl/sync_fifo.sv - +ip/sdram_controller/sdram_controller.v diff --git a/hw/super6502_fpga/src/rtl/super_6502_fpga.sv b/hw/super6502_fpga/src/rtl/super_6502_fpga.sv index 62429b3..84cdee6 100644 --- a/hw/super6502_fpga/src/rtl/super_6502_fpga.sv +++ b/hw/super6502_fpga/src/rtl/super_6502_fpga.sv @@ -12,6 +12,19 @@ module super6502_fpga( input i_pll_locked, output logic o_pll_reset, + output logic o_sdr_CKE, + output logic o_sdr_n_CS, + output logic o_sdr_n_WE, + output logic o_sdr_n_RAS, + output logic o_sdr_n_CAS, + output logic [1:0] o_sdr_BA, + output logic [12:0] o_sdr_ADDR, + input logic [15:0] i_sdr_DATA, + output logic [15:0] o_sdr_DATA, + output logic [15:0] o_sdr_DATA_oe, + output logic [1:0] o_sdr_DQM, + + input [7:0] i_cpu0_data_from_cpu, input i_cpu0_sync, input i_cpu0_rwb, @@ -38,10 +51,21 @@ assign o_clk_phi2 = clk_cpu; assign o_cpu0_data_oe = {8{i_cpu0_rwb}}; +logic vio0_reset; +assign vio0_reset = '1; logic master_reset; +logic sdram_ready; +logic [3:0] w_sdr_state; + +logic pre_reset; + +assign pre_reset = button_reset & vio0_reset; + +assign sdram_ready = |w_sdr_state; + +assign master_reset = pre_reset & sdram_ready; -assign master_reset = button_reset; logic cpu0_AWVALID; logic cpu0_AWREADY; @@ -98,6 +122,24 @@ logic rom_rready; logic [DATA_WIDTH-1:0] rom_rdata; logic [1:0] rom_rresp; +logic sdram_AWVALID; +logic sdram_AWREADY; +logic [ADDR_WIDTH-1:0] sdram_AWADDR; +logic sdram_WVALID; +logic sdram_WREADY; +logic [DATA_WIDTH-1:0] sdram_WDATA; +logic [DATA_WIDTH/8-1:0] sdram_WSTRB; +logic sdram_BVALID; +logic sdram_BREADY; +logic [1:0] sdram_BRESP; +logic sdram_ARVALID; +logic sdram_ARREADY; +logic [ADDR_WIDTH-1:0] sdram_ARADDR; +logic sdram_RVALID; +logic sdram_RREADY; +logic [DATA_WIDTH-1:0] sdram_RDATA; +logic [1:0] sdram_RRESP; + cpu_wrapper u_cpu_wrapper_0( .i_clk_cpu (clk_cpu), @@ -145,7 +187,7 @@ cpu_wrapper u_cpu_wrapper_0( axi_crossbar #( .N_INITIATORS(1), - .N_TARGETS(2) + .N_TARGETS(3) ) u_crossbar ( .clk(i_sysclk), .rst(~master_reset), @@ -168,23 +210,24 @@ axi_crossbar #( .ini_bvalid ({cpu0_BVALID }), .ini_bready ({cpu0_BREADY }), - .tgt_araddr ({ram_araddr, rom_araddr }), - .tgt_arvalid ({ram_arvalid, rom_arvalid }), - .tgt_arready ({ram_arready, rom_arready }), - .tgt_rdata ({ram_rdata, rom_rdata }), - .tgt_rresp ({ram_rresp, rom_rresp }), - .tgt_rvalid ({ram_rvalid, rom_rvalid }), - .tgt_rready ({ram_rready, rom_rready }), - .tgt_awaddr ({ram_awaddr, rom_awaddr }), - .tgt_awvalid ({ram_awvalid, rom_awvalid }), - .tgt_awready ({ram_awready, rom_awready }), - .tgt_wdata ({ram_wdata, rom_wdata }), - .tgt_wvalid ({ram_wvalid, rom_wvalid }), - .tgt_wready ({ram_wready, rom_wready }), - .tgt_wstrb ({ram_wstrb, rom_wstrb }), - .tgt_bresp ({ram_bresp, rom_bresp }), - .tgt_bvalid ({ram_bvalid, rom_bvalid }), - .tgt_bready ({ram_bready, rom_bready }) + .tgt_araddr ({ram_araddr, rom_araddr, sdram_ARADDR }), + .tgt_arvalid ({ram_arvalid, rom_arvalid, sdram_ARVALID }), + .tgt_arready ({ram_arready, rom_arready, sdram_ARREADY }), + .tgt_rdata ({ram_rdata, rom_rdata, sdram_RDATA }), + .tgt_rresp ({ram_rresp, rom_rresp, sdram_RRESP }), + .tgt_rvalid ({ram_rvalid, rom_rvalid, sdram_RVALID }), + .tgt_rready ({ram_rready, rom_rready, sdram_RREADY }), + .tgt_awaddr ({ram_awaddr, rom_awaddr, sdram_AWADDR }), + .tgt_awvalid ({ram_awvalid, rom_awvalid, sdram_AWVALID }), + .tgt_awready ({ram_awready, rom_awready, sdram_AWREADY }), + .tgt_wdata ({ram_wdata, rom_wdata, sdram_WDATA }), + .tgt_wvalid ({ram_wvalid, rom_wvalid, sdram_WVALID }), + .tgt_wready ({ram_wready, rom_wready, sdram_WREADY }), + .tgt_wstrb ({ram_wstrb, rom_wstrb, sdram_WSTRB }), + .tgt_bresp ({ram_bresp, rom_bresp, sdram_BRESP }), + .tgt_bvalid ({ram_bvalid, rom_bvalid, sdram_BVALID }), + .tgt_bready ({ram_bready, rom_bready, sdram_BREADY }) + ); axi4_lite_rom #( @@ -252,6 +295,79 @@ axi4_lite_ram #( .i_WSTRB(ram_wstrb) ); +logic [1:0] w_sdr_CKE; +logic [1:0] w_sdr_n_CS; +logic [1:0] w_sdr_n_RAS; +logic [1:0] w_sdr_n_CAS; +logic [1:0] w_sdr_n_WE; +logic [3:0] w_sdr_BA; +logic [25:0] w_sdr_ADDR; +logic [31:0] w_sdr_DATA; +logic [31:0] w_sdr_DATA_oe; +logic [3:0] w_sdr_DQM; + +assign o_sdr_CKE = w_sdr_CKE[0]; //Using SOFT ddio, ignore second cycle +assign o_sdr_n_CS = w_sdr_n_CS[0]; +assign o_sdr_n_RAS = w_sdr_n_RAS[0]; +assign o_sdr_n_CAS = w_sdr_n_CAS[0]; +assign o_sdr_n_WE = w_sdr_n_WE[0]; +assign o_sdr_BA = w_sdr_BA[0+:2]; +assign o_sdr_ADDR = w_sdr_ADDR[0+:13]; +assign o_sdr_DATA = w_sdr_DATA[0+:16]; +assign o_sdr_DATA_oe = w_sdr_DATA_oe[0+:16]; +assign o_sdr_DQM = w_sdr_DQM[0+:2]; + +sdram_controller u_sdram_controller( + .i_aresetn (pre_reset), + .i_sysclk (i_sysclk), + .i_sdrclk (i_sdrclk), + .i_tACclk (i_tACclk), + .o_pll_reset (), + .i_pll_locked ('1), + + .o_sdr_state (w_sdr_state), + + .i_AXI4_AWVALID (sdram_AWVALID), + .o_AXI4_AWREADY (sdram_AWREADY), + .i_AXI4_AWADDR (sdram_AWADDR[23:0]), + .i_AXI4_WVALID (sdram_WVALID), + .o_AXI4_WREADY (sdram_WREADY), + .i_AXI4_WDATA (sdram_WDATA), + .i_AXI4_WSTRB (sdram_WSTRB), + .o_AXI4_BVALID (sdram_BVALID), + .i_AXI4_BREADY (sdram_BREADY), + .i_AXI4_ARVALID (sdram_ARVALID), + .o_AXI4_ARREADY (sdram_ARREADY), + .i_AXI4_ARADDR (sdram_ARADDR[23:0]), + .o_AXI4_RVALID (sdram_RVALID), + .i_AXI4_RREADY (sdram_RREADY), + .o_AXI4_RDATA (sdram_RDATA), + + .i_AXI4_WLAST (sdram_WVALID), + .o_AXI4_RLAST (), + .i_AXI4_AWID ('0), + .i_AXI4_AWSIZE ('0), + .i_AXI4_ARID ('0), + .i_AXI4_ARLEN ('0), + .i_AXI4_ARSIZE ('0), + .i_AXI4_ARBURST ('0), + .i_AXI4_AWLEN ('0), + .o_AXI4_RID (), + .o_AXI4_BID (), + + .o_sdr_CKE (w_sdr_CKE), + .o_sdr_n_CS (w_sdr_n_CS), + .o_sdr_n_RAS (w_sdr_n_RAS), + .o_sdr_n_CAS (w_sdr_n_CAS), + .o_sdr_n_WE (w_sdr_n_WE), + .o_sdr_BA (w_sdr_BA), + .o_sdr_ADDR (w_sdr_ADDR), + .o_sdr_DATA (w_sdr_DATA), + .o_sdr_DATA_oe (w_sdr_DATA_oe), + .i_sdr_DATA ({{16'b0}, {i_sdr_DATA}}), + .o_sdr_DQM (w_sdr_DQM) +); + endmodule \ No newline at end of file diff --git a/hw/super6502_fpga/src/sim/Makefile b/hw/super6502_fpga/src/sim/Makefile index 1dccbe3..5c25611 100644 --- a/hw/super6502_fpga/src/sim/Makefile +++ b/hw/super6502_fpga/src/sim/Makefile @@ -4,17 +4,21 @@ SIM_SRCS_LIST=sources.list SUPER6502_FPGA_SOURCES=$(foreach file, $(shell cat $(FPGA_SRCS_LIST)), ../../$(file)) SIM_SOURCES=$(shell cat $(SIM_SRCS_LIST)) +INCLUDE=include/sdram_controller_define.vh + TB_NAME=sim_top COPY_FILES=addr_map.mem init_hex.mem +FLAGS=-DSIM -DRTL_SIM + all: waves waves: $(TB_NAME) ./$(TB_NAME) -fst $(TB_NAME): $(SUPER6502_FPGA_SOURCES) $(SIM_SOURCES) $(COPY_FILES) - iverilog -g2005-sv $(FLAGS) -s $@ -o $@ $(SUPER6502_FPGA_SOURCES) $(SIM_SOURCES) -I ../../ + iverilog -g2005-sv $(FLAGS) -s $@ -o $@ $(INCLUDE) $(SUPER6502_FPGA_SOURCES) $(SIM_SOURCES) -I ../../ $(COPY_FILES): ../../$@ cp ../../$@ . @@ -23,4 +27,4 @@ $(COPY_FILES): ../../$@ clean: rm -rf $(COPY_FILES) rm -rf $(TB_NAME) - rm -rf sim_top.vcd \ No newline at end of file + rm -rf sim_top.vcd diff --git a/hw/super6502_fpga/src/sim/hvl/sim_top.sv b/hw/super6502_fpga/src/sim/hvl/sim_top.sv index 0afa07f..c4c29c8 100644 --- a/hw/super6502_fpga/src/sim/hvl/sim_top.sv +++ b/hw/super6502_fpga/src/sim/hvl/sim_top.sv @@ -2,6 +2,8 @@ module sim_top(); +`include "include/sdram_controller_define.vh" + localparam ADDR_WIDTH = 32; localparam DATA_WIDTH = 32; @@ -71,11 +73,48 @@ cpu_65c02 u_cpu0 ( .SYNC (w_cpu0_sync) ); +logic w_sdr_CKE; +logic w_sdr_n_CS; +logic w_sdr_n_WE; +logic w_sdr_n_RAS; +logic w_sdr_n_CAS; +logic [BA_WIDTH -1:0] w_sdr_BA; +logic [ROW_WIDTH -1:0] w_sdr_ADDR; +logic [DQ_GROUP *DQ_WIDTH -1:0] w_sdr_DATA; +logic [DQ_GROUP *DQ_WIDTH -1:0] w_sdr_DATA_oe; +logic [DQ_GROUP -1:0] w_sdr_DQM; +wire [DQ_GROUP *DQ_WIDTH -1:0] w_sdr_DQ; +// ^ Has to be wire because of tristate/inout stuff + +genvar i, j; +generate + for (i=0; i= tRAS) && // Case 1 + (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [0] >= 1) || // Case 2 + (Burst_length_2 == 1'b1 && Count_precharge [0] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge [0] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge [0] >= 8))) || + (RW_interrupt_write[0] == 1'b1 && RW_interrupt_counter[0] >= 1)) begin // Case 3 + Auto_precharge[0] = 1'b0; + Write_precharge[0] = 1'b0; + RW_interrupt_write[0] = 1'b0; + Pc_b0 = 1'b1; + Act_b0 = 1'b0; + RP_chk0 = $time + tWRa; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time); + end + end + end + if ((Auto_precharge[1] == 1'b1) && (Write_precharge[1] == 1'b1)) begin + if ((($time - RAS_chk1 >= tRAS) && // Case 1 + (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [1] >= 1) || // Case 2 + (Burst_length_2 == 1'b1 && Count_precharge [1] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge [1] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge [1] >= 8))) || + (RW_interrupt_write[1] == 1'b1 && RW_interrupt_counter[1] >= 1)) begin // Case 3 + Auto_precharge[1] = 1'b0; + Write_precharge[1] = 1'b0; + RW_interrupt_write[1] = 1'b0; + Pc_b1 = 1'b1; + Act_b1 = 1'b0; + RP_chk1 = $time + tWRa; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time); + end + end + end + if ((Auto_precharge[2] == 1'b1) && (Write_precharge[2] == 1'b1)) begin + if ((($time - RAS_chk2 >= tRAS) && // Case 1 + (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [2] >= 1) || // Case 2 + (Burst_length_2 == 1'b1 && Count_precharge [2] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge [2] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge [2] >= 8))) || + (RW_interrupt_write[2] == 1'b1 && RW_interrupt_counter[2] >= 1)) begin // Case 3 + Auto_precharge[2] = 1'b0; + Write_precharge[2] = 1'b0; + RW_interrupt_write[2] = 1'b0; + Pc_b2 = 1'b1; + Act_b2 = 1'b0; + RP_chk2 = $time + tWRa; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time); + end + end + end + if ((Auto_precharge[3] == 1'b1) && (Write_precharge[3] == 1'b1)) begin + if ((($time - RAS_chk3 >= tRAS) && // Case 1 + (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [3] >= 1) || // Case 2 + (Burst_length_2 == 1'b1 && Count_precharge [3] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge [3] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge [3] >= 8))) || + (RW_interrupt_write[3] == 1'b1 && RW_interrupt_counter[3] >= 1)) begin // Case 3 + Auto_precharge[3] = 1'b0; + Write_precharge[3] = 1'b0; + RW_interrupt_write[3] = 1'b0; + Pc_b3 = 1'b1; + Act_b3 = 1'b0; + RP_chk3 = $time + tWRa; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time); + end + end + end + + // Read with Auto Precharge Calculation + // The device start internal precharge: + // 1. Meet minimum tRAS requirement + // and 2. CAS Latency - 1 cycles before last burst + // or 3. Interrupt by a Read or Write (with or without AutoPrecharge) + if ((Auto_precharge[0] == 1'b1) && (Read_precharge[0] == 1'b1)) begin + if ((($time - RAS_chk0 >= tRAS) && // Case 1 + ((Burst_length_1 == 1'b1 && Count_precharge[0] >= 1) || // Case 2 + (Burst_length_2 == 1'b1 && Count_precharge[0] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge[0] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge[0] >= 8))) || + (RW_interrupt_read[0] == 1'b1)) begin // Case 3 + Pc_b0 = 1'b1; + Act_b0 = 1'b0; + RP_chk0 = $time; + Auto_precharge[0] = 1'b0; + Read_precharge[0] = 1'b0; + RW_interrupt_read[0] = 1'b0; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time); + end + end + end + if ((Auto_precharge[1] == 1'b1) && (Read_precharge[1] == 1'b1)) begin + if ((($time - RAS_chk1 >= tRAS) && + ((Burst_length_1 == 1'b1 && Count_precharge[1] >= 1) || + (Burst_length_2 == 1'b1 && Count_precharge[1] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge[1] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge[1] >= 8))) || + (RW_interrupt_read[1] == 1'b1)) begin + Pc_b1 = 1'b1; + Act_b1 = 1'b0; + RP_chk1 = $time; + Auto_precharge[1] = 1'b0; + Read_precharge[1] = 1'b0; + RW_interrupt_read[1] = 1'b0; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time); + end + end + end + if ((Auto_precharge[2] == 1'b1) && (Read_precharge[2] == 1'b1)) begin + if ((($time - RAS_chk2 >= tRAS) && + ((Burst_length_1 == 1'b1 && Count_precharge[2] >= 1) || + (Burst_length_2 == 1'b1 && Count_precharge[2] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge[2] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge[2] >= 8))) || + (RW_interrupt_read[2] == 1'b1)) begin + Pc_b2 = 1'b1; + Act_b2 = 1'b0; + RP_chk2 = $time; + Auto_precharge[2] = 1'b0; + Read_precharge[2] = 1'b0; + RW_interrupt_read[2] = 1'b0; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time); + end + end + end + if ((Auto_precharge[3] == 1'b1) && (Read_precharge[3] == 1'b1)) begin + if ((($time - RAS_chk3 >= tRAS) && + ((Burst_length_1 == 1'b1 && Count_precharge[3] >= 1) || + (Burst_length_2 == 1'b1 && Count_precharge[3] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge[3] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge[3] >= 8))) || + (RW_interrupt_read[3] == 1'b1)) begin + Pc_b3 = 1'b1; + Act_b3 = 1'b0; + RP_chk3 = $time; + Auto_precharge[3] = 1'b0; + Read_precharge[3] = 1'b0; + RW_interrupt_read[3] = 1'b0; + if (Debug) begin + $display("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time); + end + end + end + + // Internal Precharge or Bst + if (Command[0] == `PRECH) begin // Precharge terminate a read with same bank or all banks + if (Bank_precharge[0] == Bank || A10_precharge[0] == 1'b1) begin + if (Data_out_enable == 1'b1) begin + Data_out_enable = 1'b0; + end + end + end else if (Command[0] == `BST) begin // BST terminate a read to current bank + if (Data_out_enable == 1'b1) begin + Data_out_enable = 1'b0; + end + end + + if (Data_out_enable == 1'b0) begin + Dq_reg <= #tOH {DQ_BITS{1'bz}}; + end + + // Detect Read or Write command + if (Command[0] == `READ) begin + Bank = Bank_addr[0]; + Col = Col_addr[0]; + Col_brst = Col_addr[0]; + case (Bank_addr[0]) + 2'b00 : Row = B0_row_addr; + 2'b01 : Row = B1_row_addr; + 2'b10 : Row = B2_row_addr; + 2'b11 : Row = B3_row_addr; + endcase + Burst_counter = 0; + Data_in_enable = 1'b0; + Data_out_enable = 1'b1; + end else if (Command[0] == `WRITE) begin + Bank = Bank_addr[0]; + Col = Col_addr[0]; + Col_brst = Col_addr[0]; + case (Bank_addr[0]) + 2'b00 : Row = B0_row_addr; + 2'b01 : Row = B1_row_addr; + 2'b10 : Row = B2_row_addr; + 2'b11 : Row = B3_row_addr; + endcase + Burst_counter = 0; + Data_in_enable = 1'b1; + Data_out_enable = 1'b0; + end + + // DQ buffer (Driver/Receiver) + if (Data_in_enable == 1'b1) begin // Writing Data to Memory + // Array buffer + case (Bank) + 2'b00 : Dq_dqm = Bank0 [{Row, Col}]; + 2'b01 : Dq_dqm = Bank1 [{Row, Col}]; + 2'b10 : Dq_dqm = Bank2 [{Row, Col}]; + 2'b11 : Dq_dqm = Bank3 [{Row, Col}]; + endcase + + // Dqm operation +`ifdef x4 + if (Dqm[0] == 1'b0) begin + Dq_dqm [ 3 : 0] = Dq [ 3 : 0]; + end +`elsif x8 + if (Dqm[0] == 1'b0) begin + Dq_dqm [ 7 : 0] = Dq [ 7 : 0]; + end +`elsif x16 + if (Dqm[0] == 1'b0) begin + Dq_dqm [ 7 : 0] = Dq [ 7 : 0]; + end + if (Dqm[1] == 1'b0) begin + Dq_dqm [15 : 8] = Dq [15 : 8]; + end +`endif + + // Write to memory + case (Bank) + 2'b00 : Bank0 [{Row, Col}] = Dq_dqm; + 2'b01 : Bank1 [{Row, Col}] = Dq_dqm; + 2'b10 : Bank2 [{Row, Col}] = Dq_dqm; + 2'b11 : Bank3 [{Row, Col}] = Dq_dqm; + endcase + + // Display debug message + if (Dqm !== 2'b11) begin + // Record tWR for manual precharge + WR_chkm [Bank] = $time; + + if (Debug) begin + $display("%m : at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = %h", $time, Bank, Row, Col, Dq_dqm); + end + end else begin + if (Debug) begin + $display("%m : at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col); + end + end + + // Advance burst counter subroutine + #tHZ Burst_decode; + + end else if (Data_out_enable == 1'b1) begin // Reading Data from Memory + // Array buffer + case (Bank) + 2'b00 : Dq_dqm = Bank0[{Row, Col}]; + 2'b01 : Dq_dqm = Bank1[{Row, Col}]; + 2'b10 : Dq_dqm = Bank2[{Row, Col}]; + 2'b11 : Dq_dqm = Bank3[{Row, Col}]; + endcase + + // Dqm operation +`ifdef x4 + if (Dqm_reg0 [0] == 1'b1) begin + Dq_dqm [ 3 : 0] = 4'bz; + end +`elsif x8 + if (Dqm_reg0 [0] == 1'b1) begin + Dq_dqm [ 7 : 0] = 8'bz; + end +`elsif x16 + if (Dqm_reg0 [0] == 1'b1) begin + Dq_dqm [ 7 : 0] = 8'bz; + end + if (Dqm_reg0 [1] == 1'b1) begin + Dq_dqm [15 : 8] = 8'bz; + end +`endif + + // Display debug message + Dq_reg = #tAC Dq_dqm; + if (Debug) begin + $display("%m : at time %t READ : Bank = %d Row = %d, Col = %d, Dqm = %b, Data = %h", $time, Bank, Row, Col, Dqm_reg0, Dq_reg); + end + + // Advance burst counter subroutine + Burst_decode; + end + end + + // Burst counter decode + task Burst_decode; + begin + // Advance Burst Counter + Burst_counter = Burst_counter + 1; + + // Burst Type + if (Mode_reg[3] == 1'b0) begin // Sequential Burst + Col_temp = Col + 1; + end else if (Mode_reg[3] == 1'b1) begin // Interleaved Burst + Col_temp[2] = Burst_counter[2] ^ Col_brst[2]; + Col_temp[1] = Burst_counter[1] ^ Col_brst[1]; + Col_temp[0] = Burst_counter[0] ^ Col_brst[0]; + end + + // Burst Length + if (Burst_length_2) begin // Burst Length = 2 + Col [0] = Col_temp [0]; + end else if (Burst_length_4) begin // Burst Length = 4 + Col [1 : 0] = Col_temp [1 : 0]; + end else if (Burst_length_8) begin // Burst Length = 8 + Col [2 : 0] = Col_temp [2 : 0]; + end else begin // Burst Length = FULL + Col = Col_temp; + end + + // Burst Read Single Write + if (Write_burst_mode == 1'b1) begin + Data_in_enable = 1'b0; + end + + // Data Counter + if (Burst_length_1 == 1'b1) begin + if (Burst_counter >= 1) begin + Data_in_enable = 1'b0; + Data_out_enable = 1'b0; + end + end else if (Burst_length_2 == 1'b1) begin + if (Burst_counter >= 2) begin + Data_in_enable = 1'b0; + Data_out_enable = 1'b0; + end + end else if (Burst_length_4 == 1'b1) begin + if (Burst_counter >= 4) begin + Data_in_enable = 1'b0; + Data_out_enable = 1'b0; + end + end else if (Burst_length_8 == 1'b1) begin + if (Burst_counter >= 8) begin + Data_in_enable = 1'b0; + Data_out_enable = 1'b0; + end + end + end + endtask + + // Timing Parameters for -75 (133 MHz @ CL3) + specify + specparam + tAH = 0.8, // Addr, Ba Hold Time + tAS = 1.5, // Addr, Ba Setup Time + `ifdef CLK_166 + tCK3 = 6, + `elsif CLK_133 + tCK3 = 7.5, + `elsif CLK_100 + tCK3 = 10, + `elsif CLK_200 + tCK3 = 5, + `endif + tCH = 2.5, // Clock High-Level Width + tCL = 2.5, // Clock Low-Level Width + tCKH = 0.8, // CKE Hold Time + tCKS = 1.5, // CKE Setup Time + tCMH = 0.8, // CS#, RAS#, CAS#, WE#, DQM# Hold Time + tCMS = 1.5, // CS#, RAS#, CAS#, WE#, DQM# Setup Time + tDH = 0.8, // Data-in Hold Time + tDS = 1.5; // Data-in Setup Time + $width (posedge Clk, tCH); + $width (negedge Clk, tCL); + $period (negedge Clk, tCK3); + $period (posedge Clk, tCK3); + $setuphold(posedge Clk, Cke, tCKS, tCKH); + $setuphold(posedge Clk, Cs_n, tCMS, tCMH); + $setuphold(posedge Clk, Cas_n, tCMS, tCMH); + $setuphold(posedge Clk, Ras_n, tCMS, tCMH); + $setuphold(posedge Clk, We_n, tCMS, tCMH); + $setuphold(posedge Clk, Addr, tAS, tAH); + $setuphold(posedge Clk, Ba, tAS, tAH); + $setuphold(posedge Clk, Dqm, tCMS, tCMH); + $setuphold(posedge Dq_chk, Dq, tDS, tDH); + endspecify + +endmodule diff --git a/hw/super6502_fpga/super6502_fpga.peri.xml b/hw/super6502_fpga/super6502_fpga.peri.xml index a664a30..2141ac8 100644 --- a/hw/super6502_fpga/super6502_fpga.peri.xml +++ b/hw/super6502_fpga/super6502_fpga.peri.xml @@ -133,9 +133,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hw/super6502_fpga/super6502_fpga.xml b/hw/super6502_fpga/super6502_fpga.xml index 7d569ac..1dcda00 100644 --- a/hw/super6502_fpga/super6502_fpga.xml +++ b/hw/super6502_fpga/super6502_fpga.xml @@ -1,4 +1,4 @@ - + @@ -24,7 +24,11 @@ - + + + + + @@ -51,6 +55,7 @@ + diff --git a/sw/test_code/loop_test/main.s b/sw/test_code/loop_test/main.s index 60aebb7..fbd3b02 100644 --- a/sw/test_code/loop_test/main.s +++ b/sw/test_code/loop_test/main.s @@ -6,8 +6,7 @@ .addr _init ; Reset vector .addr _irq_int ; IRQ/BRK vector -.zeropage -tmp: .res 1 +SDRAM= $200 .code @@ -17,8 +16,8 @@ _irq_int: _init: lda #$00 @start: - sta tmp - cmp tmp + sta SDRAM + cmp SDRAM bne @end ina bra @start