// ============================================================================= // 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 _8fa1502251ff4c338cc5b2fd6c7f050a `define IP_NAME_CONCAT(a,b) a``b `define IP_MODULE_NAME(name) `IP_NAME_CONCAT(name,`IP_UUID) module sdram_controller ( input i_we, input i_sysclk, input i_arst, input i_sdrclk, input i_tACclk, input i_pll_locked, input i_re, input i_last, output o_dbg_tRTW_done, 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, 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, output [5:0] o_dbg_dly_cnt_b, output o_dbg_tRCD_done ); `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 ("Native"), .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_we ( i_we ), .i_sysclk ( i_sysclk ), .i_arst ( i_arst ), .i_sdrclk ( i_sdrclk ), .i_tACclk ( i_tACclk ), .i_pll_locked ( i_pll_locked ), .i_re ( i_re ), .i_last ( i_last ), .o_dbg_tRTW_done ( o_dbg_tRTW_done ), .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 ), .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 ), .o_dbg_dly_cnt_b ( o_dbg_dly_cnt_b ), .o_dbg_tRCD_done ( o_dbg_tRCD_done ) ); 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