aboutsummaryrefslogtreecommitdiffstats
path: root/projects/XUPVVH/verilog
diff options
context:
space:
mode:
Diffstat (limited to 'projects/XUPVVH/verilog')
-rw-r--r--projects/XUPVVH/verilog/ddr4_adapter.v359
-rw-r--r--projects/XUPVVH/verilog/ddr4_mc_odt.v130
-rw-r--r--projects/XUPVVH/verilog/project.vh11
-rw-r--r--projects/XUPVVH/verilog/softmc_top.v588
4 files changed, 1088 insertions, 0 deletions
diff --git a/projects/XUPVVH/verilog/ddr4_adapter.v b/projects/XUPVVH/verilog/ddr4_adapter.v
new file mode 100644
index 0000000..88eec7e
--- /dev/null
+++ b/projects/XUPVVH/verilog/ddr4_adapter.v
@@ -0,0 +1,359 @@
+`include "parameters.vh"
+`include "project.vh"
+// Convert MC emitted DFI signals to a specific DDR4 PHY interface (mem_clock = 4xfab_clk)
+// Note that this is a bit hardcoded, but it could be made more flexible to satisfy
+// wider (can issue more than 4 commands each fab cycle) PHY interfaces.
+// DBUF_WIDTH specifies how many bursts of data will be buffered
+// before being issued to DRAM.
+
+`define ADDR_WIDTH 17
+
+module ddr4_adapter #(parameter CKE_WIDTH = 1, RANK_WIDTH = 1, DQ_WIDTH = 64, DRAM_CMD_SLOTS = 4,
+ DATA_BUF_ADDR_WIDTH = 5, DBUF_WIDTH = 4, DQ_BURST = 8)
+
+(
+ // common signals
+ input clk,
+ input rst,
+
+ //other control signals
+ input init_calib_complete,
+ //input process_iseq,
+
+ // ddr_pipeline <-> outer module if
+ input [3:0] ddr_write,
+ input [3:0] ddr_read,
+ input [3:0] ddr_pre,
+ input [3:0] ddr_act,
+ input [3:0] ddr_ref,
+ input [3:0] ddr_zq,
+ input [3:0] ddr_nop,
+ input [3:0] ddr_ap,
+ input [3:0] ddr_half_bl,
+ input [3:0] ddr_pall,
+ input [4*`BG_WIDTH-1:0] ddr_bg,
+ input [4*`BANK_WIDTH-1:0] ddr_bank,
+ input [4*`COL_WIDTH-1:0] ddr_col,
+ input [4*`ROW_WIDTH-1:0] ddr_row,
+ input [511:0] ddr_wdata,
+
+ // periodic maintenance signals
+ input ddr_maint_read, // next read will be a maintenance read
+
+ // DDR4-PHY signals
+ output [DATA_BUF_ADDR_WIDTH-1:0] dBufAdr, // Reserved. Should be tied low.
+ output [DQ_WIDTH*8-1:0] wrData, // DRAM write data. There are 8 bits for each DQ lane on the DRAM bus.
+ output [DQ_WIDTH-1:0] wrDataMask,// DRAM write DM/DBI port.There is one bit for each byte of the wrData port.
+ input wrDataEn, // Write data Enable. The Phy will assert this port for one cycle for each write CAS command.
+ output [7:0] mc_ACT_n, // DRAM ACT_n command signal for four DRAM clock cycles.
+ output [`ADDR_WIDTH*8-1:0] mc_ADR, // DRAM address. There are 8 bits in the fabric interface for each address bit on the DRAM bus.
+ output [`BANK_WIDTH*8-1:0] mc_BA, // DRAM bank address. 8 bits for each DRAM bank address.
+ output [`BG_WIDTH*8-1:0] mc_BG, // DRAM bank group address.
+ output [`CS_WIDTH*8-1:0] mc_CS_n, // DRAM CS_n
+ //output [`ODT_WIDTH*8-1:0] mc_ODT, // DRAM ODT
+ output mcRdCAS, // Read CAS command issued.
+ output mcWrCAS, // Write CAS command issued.
+ output [1:0] winRank, // Target rank for CAS commands. This value indicates which rank a CAS command is issued to.
+ output [4:0] winBuf, // Optional control signal. When either mcRdCAS or mcWrCAS is asserted, the Phy will store the value on the winBuf signal.
+ // input [DQ_WIDTH*8-1:0] rdData, // DRAM read data.
+ input rdDataEn, // Read data valid. This signal asserts for one fabric cycle for each completed read operation.
+ input rdDataEnd, // Unused. Tied high.
+ output [1:0] mcCasSlot,
+ output mcCasSlot2,
+ output gt_data_ready,
+
+ output iss_dummy_read
+ );
+
+ assign winRank = 2'b0; // single rank -> tie to 0
+ assign winBuf = 4'b0; // TODO don't know how this could be used
+ assign dBufAdr = {DATA_BUF_ADDR_WIDTH{1'b0}};
+
+ reg [DQ_BURST*DQ_WIDTH-1:0] ddr_wdata_r;
+
+ reg [2*DQ_BURST*DQ_WIDTH-1:0] wrDataBuf, wrDataBuf_ns;
+ reg slot1_full, slot1_full_ns;
+ reg slot2_full, slot2_full_ns;
+
+ assign wrData = wrDataBuf[0+:DQ_BURST*DQ_WIDTH];
+
+ reg iss_dummy_read_r, iss_dummy_read_ns;
+ reg read_will_be_dummy_r, read_will_be_dummy_ns;
+
+ assign iss_dummy_read = iss_dummy_read_r;
+
+ reg init_calib_complete_r; // can't issue any commands until this signal is asserted
+
+ reg wrDataEn_r; // to delay wrDataEn by one clock cycle
+ reg [7:0] ACT_n_ns, ACT_n_r;
+ reg [`ADDR_WIDTH*8-1:0] ADR_ns, ADR_r;
+ reg [`BANK_WIDTH*8-1:0] BA_ns, BA_r;
+ reg [`BG_WIDTH*8-1:0] BG_ns, BG_r;
+ reg [`CS_WIDTH*8-1:0] CS_n_ns, CS_n_r;
+ reg [`ODT_WIDTH*8-1:0] ODT_ns, ODT_r;
+ reg RdCAS_ns, RdCAS_r;
+ reg WrCAS_ns, WrCAS_r;
+
+ reg [1:0] mcCasSlot_r, mcCasSlot_ns;
+ reg gt_data_ready_r, gt_data_ready_ns;
+
+ // TODO - PG 150 - page 180
+ // Specifically, the PHY requires the following after calDone asserts:
+ // 1. At least one read command every 1 μs. For a multi-rank system any rank is acceptable.
+ // 2. The gt_data_ready signal is asserted for one system clock cycle after rdDataEn or
+ // per_rd_done signal asserts at least once within each 1 μs interval.
+ // 3. There is a three contiguous system clock cycle period with no read CAS commands
+ // asserted at the PHY interface every 1 μs.
+ // Somehow enforce above requirements to our PHY command stream, if it is not implicitly
+ // handled by the controller's maintenance handler modules.
+ // To drive gt_data_ready
+ assign gt_data_ready = gt_data_ready_r;
+
+ assign mcCasSlot = mcCasSlot_r;
+ assign mcCasSlot2 = mcCasSlot[1];
+
+ assign wrDataMask = {DQ_WIDTH{1'b0}};
+ assign mc_ACT_n = ACT_n_r;
+ assign mc_ADR = ADR_r;
+ assign mc_BA = BA_r;
+ assign mc_BG = BG_r;
+ assign mc_CS_n = CS_n_r;
+ assign mcRdCAS = RdCAS_r;
+ assign mcWrCAS = WrCAS_r;
+
+ integer mc_cmd_i; // iterate over softmc dfi commands
+ integer adr_bit_i; // iterate over dfi address bits
+ integer bank_bit_i; // iterate over bank number bits
+ integer bg_bit_i; // iterate over bank group bits
+ always@* begin
+ wrDataBuf_ns = wrDataBuf;
+ slot1_full_ns = slot1_full;
+ slot2_full_ns = slot2_full;
+ ACT_n_ns = {8{`HIGH}};
+ ADR_ns = {`ROW_WIDTH*8{1'bx}};
+ BA_ns = {`BANK_WIDTH*8{1'bx}};
+ BG_ns = {`BG_WIDTH*8{1'bx}};
+ CS_n_ns = {`CS_WIDTH*8{1'b1}}; // NOP
+ ODT_ns = {`ODT_WIDTH*8{1'bx}};
+ RdCAS_ns = 1'b0;
+ WrCAS_ns = 1'b0;
+ mcCasSlot_ns = 2'b0;
+ iss_dummy_read_ns = iss_dummy_read_r;
+ read_will_be_dummy_ns = ddr_maint_read || read_will_be_dummy_r;
+
+ // assign DDR4 PHY address signals
+ // each pair of bits in a byte corresponds
+ // to each slot's command address bit
+ // e.g. ADR[1:0] is slot0's command address bit 0
+ // ADR[3:2] is slot1's command address bit 0
+ // ADR[9:8] is slot0's command address bit 1...
+
+ // Assume that every command works with column addresses
+ // ACTs will overwrite LSBs later
+ for(mc_cmd_i = 0 ; mc_cmd_i < DRAM_CMD_SLOTS ; mc_cmd_i = mc_cmd_i + 1) begin
+ for(adr_bit_i = 0 ; adr_bit_i < `COL_WIDTH ; adr_bit_i = adr_bit_i + 1) begin
+ ADR_ns[adr_bit_i*8 + mc_cmd_i*2 +: 2] =
+ {2{ddr_col[mc_cmd_i*`COL_WIDTH + adr_bit_i]}};
+ end
+ end
+
+ // ACTs overwriting LSBs here
+ for(mc_cmd_i = 0 ; mc_cmd_i < DRAM_CMD_SLOTS ; mc_cmd_i = mc_cmd_i + 1) begin
+ for(adr_bit_i = 0 ; adr_bit_i < `ROW_WIDTH ; adr_bit_i = adr_bit_i + 1) begin
+ if(ddr_act[mc_cmd_i])
+ ADR_ns[adr_bit_i*8 + mc_cmd_i*2 +: 2] =
+ {2{ddr_row[mc_cmd_i*`ROW_WIDTH + adr_bit_i]}};
+ end
+ end
+
+ // Set bank and bank group signals
+ for(mc_cmd_i = 0 ; mc_cmd_i < DRAM_CMD_SLOTS ; mc_cmd_i = mc_cmd_i + 1) begin
+ for(bank_bit_i = 0 ; bank_bit_i < `BANK_WIDTH ; bank_bit_i = bank_bit_i + 1) begin
+ BA_ns[bank_bit_i*8 + mc_cmd_i*2 +: 2] =
+ {2{ddr_bank[mc_cmd_i*`BANK_WIDTH + bank_bit_i]}};
+ end
+ end
+ for(mc_cmd_i = 0 ; mc_cmd_i < DRAM_CMD_SLOTS ; mc_cmd_i = mc_cmd_i + 1) begin
+ for(bg_bit_i = 0 ; bg_bit_i < `BG_WIDTH ; bg_bit_i = bg_bit_i + 1) begin
+ BG_ns[bg_bit_i*8 + mc_cmd_i*2 +: 2] =
+ {2{ddr_bg[mc_cmd_i*`BG_WIDTH + bg_bit_i]}};
+ end
+ end
+
+ // Set misc. signals (ap, bl4, precharge all)
+ for(mc_cmd_i = 0 ; mc_cmd_i < DRAM_CMD_SLOTS ; mc_cmd_i = mc_cmd_i + 1) begin
+ if(ddr_ap[mc_cmd_i])
+ ADR_ns[10*8 + mc_cmd_i*2 +: 2] = {2{`HIGH}};
+ else if(ddr_write[mc_cmd_i] | ddr_read[mc_cmd_i])
+ ADR_ns[10*8 + mc_cmd_i*2 +: 2] = {2{`LOW}};
+ if(ddr_half_bl[mc_cmd_i])
+ ADR_ns[12*8 + mc_cmd_i*2 +: 2] = {2{`HIGH}};
+ else if(ddr_write[mc_cmd_i] | ddr_read[mc_cmd_i])
+ ADR_ns[12*8 + mc_cmd_i*2 +: 2] = {2{`LOW}};
+ if(ddr_pall[mc_cmd_i])
+ ADR_ns[10*8 + mc_cmd_i*2 +: 2] = {2{`HIGH}};
+ else if(ddr_pre[mc_cmd_i])
+ ADR_ns[10*8 + mc_cmd_i*2 +: 2] = {2{`LOW}};
+ if(ddr_zq[mc_cmd_i]) // ZQ short
+ ADR_ns[10*8 + mc_cmd_i*2 +: 2] = {2{`LOW}};
+ end
+
+ // For each command slot, decode the commands
+ // and hopefully convert those to Xilinx PHY
+ // compatible commands.
+ for(mc_cmd_i = 0 ; mc_cmd_i < DRAM_CMD_SLOTS ; mc_cmd_i = mc_cmd_i + 1) begin
+ if(ddr_nop[mc_cmd_i]) begin // NOP
+ // set chip select to HI
+ CS_n_ns[mc_cmd_i*1*2 +: 1*2] = {1*2{`HIGH}};
+ end
+ else if(ddr_act[mc_cmd_i]) begin // Activate ROW
+ // There seems to be something wrong with the dfi_cs signal widths
+ // coming from the mc. Consider LSBs as valid CS signals for now
+ CS_n_ns[mc_cmd_i*1*2 +: 1*2] = {2*1{`LOW}};
+ ACT_n_ns[mc_cmd_i*2 +: 2] = {2{`LOW}};
+ end // Activate
+ else if(ddr_read[mc_cmd_i] || ddr_write[mc_cmd_i]) begin // DDR Read or Write
+ mcCasSlot_ns = mc_cmd_i[0 +: 2];
+ CS_n_ns[mc_cmd_i*1*2 +: 1*2] = {2*1{`LOW}};
+ if(ddr_write[mc_cmd_i]) begin // Write burst
+ ADR_ns[`ADDR_WIDTH*8-3*8 + mc_cmd_i*2 +: 2] = {2{`LOW}}; // WE
+ ADR_ns[`ADDR_WIDTH*8-2*8 + mc_cmd_i*2 +: 2] = {2{`LOW}}; // CAS
+ ADR_ns[`ADDR_WIDTH*8-8 + mc_cmd_i*2 +: 2] = {2{`HIGH}}; // ~RAS
+ //fifo_wr_en = HIGH;
+ WrCAS_ns = `HIGH;
+ end
+ else begin // Read burst
+ ADR_ns[`ADDR_WIDTH*8-3*8 + mc_cmd_i*2 +: 2] = {2{`HIGH}}; // ~WE
+ ADR_ns[`ADDR_WIDTH*8-2*8 + mc_cmd_i*2 +: 2] = {2{`LOW}}; // CAS
+ ADR_ns[`ADDR_WIDTH*8-8 + mc_cmd_i*2 +: 2] = {2{`HIGH}}; // ~RAS
+ RdCAS_ns = `HIGH;
+ iss_dummy_read_ns = read_will_be_dummy_r;
+ read_will_be_dummy_ns = `LOW;
+ end
+ end // DDR Read-Write
+ else if(ddr_pre[mc_cmd_i]) begin // Precharge
+ CS_n_ns[mc_cmd_i*1*2 +: 1*2] = {2*1{`LOW}};
+ ADR_ns[`ADDR_WIDTH*8-3*8 + mc_cmd_i*2 +: 2] = {2{`LOW}}; // WE
+ ADR_ns[`ADDR_WIDTH*8-2*8 + mc_cmd_i*2 +: 2] = {2{`HIGH}}; // ~CAS
+ ADR_ns[`ADDR_WIDTH*8-8 + mc_cmd_i*2 +: 2] = {2{`LOW}}; // RAS
+ end // Precharge
+ else if(ddr_ref[mc_cmd_i]) begin // Refresh
+ CS_n_ns[mc_cmd_i*1*2 +: 1*2] = {2*1{`LOW}};
+ ADR_ns[`ADDR_WIDTH*8-3*8 + mc_cmd_i*2 +: 2] = {2{`HIGH}}; // ~WE
+ ADR_ns[`ADDR_WIDTH*8-2*8 + mc_cmd_i*2 +: 2] = {2{`LOW}}; // CAS
+ ADR_ns[`ADDR_WIDTH*8-8 + mc_cmd_i*2 +: 2] = {2{`LOW}}; // RAS
+ end
+ else if(ddr_zq[mc_cmd_i]) begin // ZQ Calib
+ CS_n_ns[mc_cmd_i*1*2 +: 1*2] = {2*1{`LOW}};
+ ADR_ns[`ADDR_WIDTH*8-3*8 + mc_cmd_i*2 +: 2] = {2{`LOW}}; // WE
+ ADR_ns[`ADDR_WIDTH*8-2*8 + mc_cmd_i*2 +: 2] = {2{`HIGH}}; // ~CAS
+ ADR_ns[`ADDR_WIDTH*8-8 + mc_cmd_i*2 +: 2] = {2{`HIGH}}; // ~RAS
+ end
+ end // decode block end
+
+ if(WrCAS_r) begin
+ if(slot1_full && slot2_full && wrDataEn_r) begin
+ wrDataBuf_ns[0+:DQ_BURST*DQ_WIDTH] = wrDataBuf[DQ_BURST*DQ_WIDTH +: DQ_BURST*DQ_WIDTH];
+ wrDataBuf_ns[DQ_BURST*DQ_WIDTH+:DQ_BURST*DQ_WIDTH] = ddr_wdata_r;
+ end
+ else if (slot1_full && wrDataEn_r) begin
+ wrDataBuf_ns[0+:DQ_BURST*DQ_WIDTH] = ddr_wdata_r;
+ end
+ else if (slot1_full) begin
+ wrDataBuf_ns[DQ_BURST*DQ_WIDTH+:DQ_BURST*DQ_WIDTH] = ddr_wdata_r;
+ slot2_full_ns = `HIGH;
+ end
+ else begin
+ wrDataBuf_ns[0+:DQ_BURST*DQ_WIDTH] = ddr_wdata_r;
+ slot1_full_ns = `HIGH;
+ end
+ end
+
+ // We handle the cases where a wrDataEn and dfi CAS commands
+ // arrive at the same time
+ if(wrDataEn_r && ~WrCAS_r) begin
+ if(slot1_full && slot2_full) begin
+ wrDataBuf_ns[0+:DQ_BURST*DQ_WIDTH] = wrDataBuf[DQ_BURST*DQ_WIDTH +: DQ_BURST*DQ_WIDTH];
+ slot2_full_ns = `LOW;
+ end
+ else if (slot1_full) begin
+ slot1_full_ns = `LOW;
+ end
+ end
+
+ if(rdDataEn) begin
+ if(RdCAS_r) // issued another CAS read this cycle
+ iss_dummy_read_ns = ddr_maint_read;
+ else
+ iss_dummy_read_ns = `LOW;
+ end
+
+ gt_data_ready_ns = iss_dummy_read_r & rdDataEn;
+ // this assumes CAS_rw_ctr is either 0, 1 or 2
+ //mcCasSlot_ns[1] = CAS_rw_ctr[DRAM_CMD_SLOTS-1][1];
+ //mcCasSlot_ns[0] = CAS_rw_ctr[DRAM_CMD_SLOTS-1][0];
+ end
+
+ always@(posedge clk) begin
+ if(rst) begin
+ wrDataBuf <= {DQ_WIDTH*DQ_BURST{1'b0}};
+ init_calib_complete_r <= 1'b0;
+ iss_dummy_read_r <= 1'b0;
+ read_will_be_dummy_r <= 1'b0;
+ wrDataEn_r <= 1'b0;
+ ACT_n_r <= {8{`HIGH}};
+ ADR_r <= {`ADDR_WIDTH*8{1'bx}};
+ BA_r <= {`BANK_WIDTH*8{1'bx}};
+ BG_r <= {`BG_WIDTH*8{1'bx}};
+ CS_n_r <= {`CS_WIDTH*8{1'b1}}; //NOP
+ ODT_r <= {`ODT_WIDTH*8{1'bx}};
+ //fifo_wr_en_r <= 1'b0;
+ WrCAS_r <= 1'b0;
+ RdCAS_r <= 1'b0;
+ mcCasSlot_r <= 2'b0;
+ slot1_full <= `LOW;
+ slot2_full <= `LOW;
+ gt_data_ready_r <= 1'b0;
+ end
+ else begin
+ if(init_calib_complete_r) begin
+ ddr_wdata_r <= ddr_wdata;
+ slot1_full <= slot1_full_ns;
+ slot2_full <= slot2_full_ns;
+ wrDataBuf <= wrDataBuf_ns;
+ iss_dummy_read_r <= iss_dummy_read_ns;
+ read_will_be_dummy_r <= read_will_be_dummy_ns;
+ wrDataEn_r <= wrDataEn;
+ ACT_n_r <= ACT_n_ns;
+ ADR_r <= ADR_ns;
+ BA_r <= BA_ns;
+ BG_r <= BG_ns;
+ CS_n_r <= CS_n_ns;
+ ODT_r <= ODT_ns;
+ WrCAS_r <= WrCAS_ns;
+ RdCAS_r <= RdCAS_ns;
+ //fifo_wr_en_r <= fifo_wr_en_ns;
+ mcCasSlot_r <= mcCasSlot_ns;
+ gt_data_ready_r <= gt_data_ready_ns;
+ end
+ else begin
+ slot1_full <= `LOW;
+ slot2_full <= `LOW;
+ wrDataBuf <= {DQ_WIDTH*DQ_BURST{1'b0}};
+ init_calib_complete_r <= init_calib_complete_r | init_calib_complete;
+ iss_dummy_read_r <= `LOW;
+ read_will_be_dummy_r <= `LOW;
+ ACT_n_r <= {8{`HIGH}};
+ ADR_r <= {`ADDR_WIDTH*8{1'b1}};
+ BA_r <= {`BANK_WIDTH*8{1'b1}};
+ BG_r <= {`BG_WIDTH*8{1'b1}};
+ CS_n_r <= {`CS_WIDTH*8{1'b1}};
+ WrCAS_r <= 1'b0;
+ RdCAS_r <= 1'b0;
+ //fifo_wr_en_r <= 1'b0;
+ mcCasSlot_r <= 2'b0;
+ gt_data_ready_r <= 1'b0;
+ end
+ end
+ end
+endmodule \ No newline at end of file
diff --git a/projects/XUPVVH/verilog/ddr4_mc_odt.v b/projects/XUPVVH/verilog/ddr4_mc_odt.v
new file mode 100644
index 0000000..fdb5c1f
--- /dev/null
+++ b/projects/XUPVVH/verilog/ddr4_mc_odt.v
@@ -0,0 +1,130 @@
+// Auto-generated, DDR4 SDRAM Example Design source
+// small modifications to issue writes from all command slots
+module ddr4_mc_odt #(parameter
+ ODTWR = 16'h8421
+ ,ODTWRDEL = 5'd9
+ ,ODTWRDUR = 4'd6
+ ,ODTWRODEL = 5'd9
+ ,ODTWRODUR = 4'd6
+
+ ,ODTRD = 16'h8421
+ ,ODTRDDEL = 5'd9
+ ,ODTRDDUR = 4'd6
+ ,ODTRDODEL = 5'd9
+ ,ODTRDODUR = 4'd6
+
+ ,ODTBITS = 4
+ ,ODTNOP = 4'b0000
+ ,TCQ = 0.1
+ )(
+ input clk
+ ,input rst
+
+ ,output [ODTBITS*8-1:0] mc_ODT
+
+ ,input casSlot2
+ ,input [1:0] casSlot
+ ,input [1:0] rank
+ ,input winRead
+ ,input winWrite
+ ,input tranSentC
+ );
+
+ // ==========================================================================================
+ // ODT is a multi-fabric-cycle waveform that needs to assert on the same cycle as write CAS,
+ // and also on the same cycle as read CAS when tCL=tCWL. This block generates the full
+ // multi-cycle ODT waveform in the same cycle that rdCAS or wrCAS is generated, bypassing
+ // the first 8 bits per ODT pin to mc_ODT combinationally, and flopping the remaining bits
+ // in a shift register which are then sent to the XiPhy 8 bits per pin per cycle. If CAS
+ // commands are issued so that the current ODT waveform overlaps with the waveform from
+ // previous commands, the waveforms will be OR'd together.
+ // Note: The original Olympus ODT block had separate timing for the selected rank and
+ // non-target ranks. This version of the code does not support this.
+ // ==========================================================================================
+
+
+ // ==========================================================================================
+ // Signal Declarations
+ // ==========================================================================================
+
+ // Structures holding multi-fabric-cycle ODT pin waveforms for current CAS transaction
+ wire [31:0] odt_array [ ODTBITS-1:0 ];
+ wire [31:0] odt_transent [ ODTBITS-1:0 ];
+
+ // Shift register holding ODT pin waveforms for previous CAS transactions
+ reg [23:0] odt_shift [ ODTBITS-1:0 ];
+ wire [23:0] odt_shift_nxt[ ODTBITS-1:0 ];
+
+ // ODT pin waveform for current fabric cycle, with time going from msb to lsb, reverse for XiPhy order
+ wire [ 7:0] odt_reverse [ ODTBITS-1:0 ];
+
+
+ // ==========================================================================================
+ // Module Code
+ // ==========================================================================================
+
+ // Set up basic write ODT timing waveform. Note that time increases moving from msb to lsb.
+ wire [31:0] odt_pulse_wr_slot0 = 32'hff_ff_ff_ff << (32 - 2*ODTWRDUR);
+ wire [31:0] odt_pulse_wr_slot1 = odt_pulse_wr_slot0 >> 2;
+ wire [31:0] odt_pulse_wr_slot2 = odt_pulse_wr_slot0 >> 4;
+ wire [31:0] odt_pulse_wr_slot3 = odt_pulse_wr_slot0 >> 6;
+
+ // Set up basic read ODT timing waveform. Note that time increases moving from msb to lsb.
+ wire [31:0] odt_pulse_rd_slot0 = ( 32'hff_ff_ff_ff << (32 - 2*ODTRDDUR) ) >> ( 2*( ODTRDDEL - ODTWRDEL ) );
+ wire [31:0] odt_pulse_rd_slot1 = odt_pulse_rd_slot0 >> 2;
+ wire [31:0] odt_pulse_rd_slot2 = odt_pulse_rd_slot0 >> 4;
+ wire [31:0] odt_pulse_rd_slot3 = odt_pulse_rd_slot0 >> 6;
+
+ // Select ODT timing waveform based on winning command type and slot position
+ wire [31:0] win_odt_pulse_slot0 = winRead ? odt_pulse_rd_slot0 : odt_pulse_wr_slot0;
+ wire [31:0] win_odt_pulse_slot1 = winRead ? odt_pulse_rd_slot1: odt_pulse_wr_slot1;
+ wire [31:0] win_odt_pulse_slot2 = winRead ? odt_pulse_rd_slot2 : odt_pulse_wr_slot2;
+ wire [31:0] win_odt_pulse_slot3 = winRead ? odt_pulse_rd_slot3 : odt_pulse_wr_slot3;
+ wire [31:0] win_odt_pulse = casSlot2 ? (casSlot[0] ? win_odt_pulse_slot3 : win_odt_pulse_slot2)
+ : (casSlot[0] ? win_odt_pulse_slot1 : win_odt_pulse_slot0);
+
+ // Select ODT pin pattern based on winning command type and rank
+ wire [15:0] win_odt_cmd_pat = winRead ? ODTRD : ODTWR;
+ wire [ 3:0] win_odt_pat = { 4 { winRead | winWrite } } & win_odt_cmd_pat[ 4*rank +:4 ]; // spyglass disable W498
+
+ genvar odt_pin;
+ generate
+ for (odt_pin = 0; odt_pin < ODTBITS; odt_pin = odt_pin + 1) begin
+ // Combine selected waveform and pattern to generate full ODT output for the current winning CAS command
+ assign odt_array[odt_pin] = { 32 { win_odt_pat[ odt_pin ] } } & win_odt_pulse;
+
+ // Qualify with tranSendC
+ assign odt_transent[odt_pin] = { 32 { tranSentC } } & odt_array[ odt_pin ];
+
+ // Parallel load lower 24 bits of qualified ODT output into shift register
+ assign odt_shift_nxt[odt_pin] = odt_transent[odt_pin][23:0] | { odt_shift[odt_pin][15:0], 8'b0 };
+
+ // Combine the upper 8 bits of the odt output for the new transaction (bypass path) with
+ // the upper 8 bits of the shift register output to generate the odt block's output
+ assign odt_reverse[odt_pin] = odt_transent[odt_pin][31:24] | odt_shift[odt_pin][23:16];
+
+ // Reverse the msb/lsb order. XiPhy wants increasing time going from lsb to msb
+ assign mc_ODT[odt_pin*8+:8] = { odt_reverse[odt_pin][0], odt_reverse[odt_pin][1], odt_reverse[odt_pin][2], odt_reverse[odt_pin][3],
+ odt_reverse[odt_pin][4], odt_reverse[odt_pin][5], odt_reverse[odt_pin][6], odt_reverse[odt_pin][7] };
+ end
+ endgenerate
+
+
+ // ==========================================================================================
+ // Reset flops
+ // ==========================================================================================
+
+ integer i;
+ always @(posedge clk) begin
+ if (rst) begin
+ for (i = 0; i < ODTBITS; i = i + 1) begin
+ odt_shift[i] <= #TCQ 28'b0;
+ end
+ end else begin
+ for (i = 0; i < ODTBITS; i = i + 1) begin
+ odt_shift[i] <= #TCQ odt_shift_nxt[i];
+ end
+ end
+ end
+
+endmodule \ No newline at end of file
diff --git a/projects/XUPVVH/verilog/project.vh b/projects/XUPVVH/verilog/project.vh
new file mode 100644
index 0000000..4084e1d
--- /dev/null
+++ b/projects/XUPVVH/verilog/project.vh
@@ -0,0 +1,11 @@
+`define XUPP3R_x4// MIG does not support DM|DBI w/ RDIMMs.
+`define DQ_WIDTH 72
+
+// DIMM related - x8 double ranks
+`ifdef XUPP3R_x4
+// DEFAULT CONFIGS USE BELOW
+`define ODT_WIDTH 2
+`define CS_WIDTH 2
+`define CKE_WIDTH 2
+`define CK_WIDTH 1
+`endif \ No newline at end of file
diff --git a/projects/XUPVVH/verilog/softmc_top.v b/projects/XUPVVH/verilog/softmc_top.v
new file mode 100644
index 0000000..88fbb37
--- /dev/null
+++ b/projects/XUPVVH/verilog/softmc_top.v
@@ -0,0 +1,588 @@
+`include "parameters.vh"
+`include "project.vh"
+
+`ifdef XUPP3R_x4
+ `define XUPP3R
+`elsif XUPP3R_x8
+ `define XUPP3R
+`elsif XUPP3R_x8_1R_UDIMM
+ `define XUPP3R
+`endif
+
+
+module softmc_top #(parameter tCK = 1500, SIM = "false")
+ (
+ // common signals
+ input c0_sys_clk_p,
+ input c0_sys_clk_n,
+ input sys_rst_l,
+
+ // iob <> ddr4 sdram ip signals
+ output c0_ddr4_act_n,
+ output [16:0] c0_ddr4_adr,
+ output [1:0] c0_ddr4_ba,
+ output [1:0] c0_ddr4_bg,
+ output [`CKE_WIDTH-1:0] c0_ddr4_cke,
+ output [`ODT_WIDTH-1:0] c0_ddr4_odt,
+ output [`CS_WIDTH-1:0] c0_ddr4_cs_n,
+ output [`CK_WIDTH-1:0] c0_ddr4_ck_t,
+ output [`CK_WIDTH-1:0] c0_ddr4_ck_c,
+ output c0_ddr4_reset_n,
+ `ifdef XUPP3R_x4
+ inout [17:0] c0_ddr4_dqs_c,
+ inout [17:0] c0_ddr4_dqs_t,
+ inout [71:0] c0_ddr4_dq,
+ output c0_ddr4_parity,
+ `endif
+ // xdma signals
+ input clk_ref_p,
+ input clk_ref_n,
+ input pcie_rst,
+ output [7:0] pci_exp_txp,
+ output [7:0] pci_exp_txn,
+ input [7:0] pci_exp_rxp,
+ input [7:0] pci_exp_rxn,
+
+ output icc
+
+ );
+
+ // Frontend control signals
+ wire softmc_fin;
+ wire user_rst;
+
+ // Frontend <-> Fetch signals
+ wire [`IMEM_ADDR_WIDTH-1:0] fr_addr_in;
+ wire fr_valid_in;
+ wire [`INSTR_WIDTH-1:0] fr_data_out;
+ wire fr_valid_out;
+ wire [`IMEM_ADDR_WIDTH-1:0] fr_addr_out;
+ wire fr_ready_out;
+
+ // Frontend <-> misc. control signals
+ wire per_rd_init;
+ wire per_zq_init;
+ wire per_ref_init;
+ wire rbe_switch_mode;
+ wire toggle_dll;
+
+ // AXI streaming ports
+ wire [`XDMA_AXI_DATA_WIDTH-1:0] m_axis_h2c_tdata_0,xdma_h2c_tdata_0;
+ wire m_axis_h2c_tlast_0, xdma_h2c_tlast_0;
+ wire m_axis_h2c_tvalid_0, xdma_h2c_tvalid_0;
+ wire m_axis_h2c_tready_0, xdma_h2c_tready_0;
+ wire [`XDMA_AXI_DATA_WIDTH/8-1:0] m_axis_h2c_tkeep_0, xdma_h2c_tkeep_0;
+ wire [`XDMA_AXI_DATA_WIDTH-1:0] s_axis_c2h_tdata_0, xdma_c2h_tdata_0;
+ wire s_axis_c2h_tlast_0, xdma_c2h_tlast_0;
+ wire s_axis_c2h_tvalid_0, xdma_c2h_tvalid_0;
+ wire s_axis_c2h_tready_0, xdma_c2h_tready_0;
+ wire [`XDMA_AXI_DATA_WIDTH/8-1:0] s_axis_c2h_tkeep_0, xdma_c2h_tkeep_0;
+
+ // ddr_pipeline <-> outer module if
+ wire [3:0] ddr_write;
+ wire [3:0] ddr_read;
+ wire [3:0] ddr_pre;
+ wire [3:0] ddr_act;
+ wire [3:0] ddr_ref;
+ wire [3:0] ddr_zq;
+ wire [3:0] ddr_nop;
+ wire [3:0] ddr_ap;
+ wire [3:0] ddr_pall;
+ wire [3:0] ddr_half_bl;
+ wire [4*`BG_WIDTH-1:0] ddr_bg;
+ wire [4*`BANK_WIDTH-1:0] ddr_bank;
+ wire [4*`COL_WIDTH-1:0] ddr_col;
+ wire [4*`ROW_WIDTH-1:0] ddr_row;
+ wire [511:0] ddr_wdata;
+
+ // periodic maintenance signals
+ wire ddr_maint_read;
+
+ // phy <-> ddr adapter and xdma app signals
+ // dlltoggler
+ wire clk_sel = 0;
+ wire [7:0] dllt_mc_ACT_n;
+ wire [135:0] dllt_mc_ADR;
+ wire [15:0] dllt_mc_BA;
+ wire [15:0] dllt_mc_BG;
+ wire [7:0] dllt_mc_CKE;
+ wire [7:0] dllt_mc_CS_n;
+ wire dllt_done;
+ // ddr adapter
+ wire [4:0] dBufAdr;
+ wire [`DQ_WIDTH*8-1:0] wrData;
+ wire [`DQ_WIDTH-1:0] wrDataMask;
+ wire [511:0] rdData;
+ wire [4:0] rdDataAddr;
+ wire [0:0] rdDataEn;
+ wire [0:0] rdDataEnd;
+ wire [0:0] per_rd_done;
+ wire [0:0] rmw_rd_done;
+ wire [4:0] wrDataAddr;
+ wire [0:0] wrDataEn;
+ wire [7:0] mc_ACT_n;
+ wire [135:0] mc_ADR;
+ wire [15:0] mc_BA;
+ wire [15:0] mc_BG;
+ wire [`CKE_WIDTH*8-1:0] mc_CKE;
+ wire [`CS_WIDTH*8-1:0] mc_CS_n;
+ wire [`ODT_WIDTH*8-1:0] mc_ODT;
+ wire [0:0] mcRdCAS;
+ wire [0:0] mcWrCAS;
+ wire [0:0] winInjTxn;
+ wire [0:0] winRmw;
+ wire [4:0] winBuf;
+ wire [1:0] winRank;
+ wire [5:0] tCWL;
+ wire dbg_clk;
+ wire c0_wr_rd_complete;
+ wire c0_ddr4_clk;
+ wire c0_ddr4_dll_off_clk;
+ wire ddr4_ui_clk;
+ wire c0_ddr4_rst;
+ wire [511:0] dbg_bus;
+ wire [1:0] mcCasSlot;
+ wire mcCasSlot2;
+ wire gt_data_ready;
+
+ wire read_seq_incoming; // next few instructions will read from DRAM
+ wire [11:0] incoming_reads; // how many reads next few instructions will issue
+ wire [11:0] buffer_space; // remaining buffer size
+
+ wire sys_rst = ~sys_rst_l; // low active signal
+ wire c0_init_calib_complete;
+
+ // There is a possibility that these signals are on
+ // the critical path as observed in
+ // the previous iteration of SoftMC
+ reg c0_init_calib_complete_r, sys_rst_r;
+ wire iq_full, processing_iseq, rdback_fifo_empty;
+
+ always @(posedge c0_ddr4_clk) begin
+ c0_init_calib_complete_r <= c0_init_calib_complete;
+ sys_rst_r <= sys_rst;
+ end
+
+ reg dllt_active = 1'b0;
+
+ `ifdef ENABLE_DLL_TOGGLER
+ always @(posedge c0_ddr4_clk) begin
+ if(toggle_dll) begin
+ dllt_active <= ~dllt_active;
+ end
+ if(dllt_done) begin
+ dllt_active <= ~dllt_active;
+ end
+ end
+ `endif
+
+ phy_ddr4 phy_ddr4_i(
+ .sys_rst (sys_rst),
+ .c0_sys_clk_p (c0_sys_clk_p),
+ .c0_sys_clk_n (c0_sys_clk_n),
+
+ `ifdef ENABLE_DLL_TOGGLER
+ .c0_ddr4_ui_clk (ddr4_ui_clk),
+ .addn_ui_clkout1 (c0_ddr4_dll_off_clk),
+ `else
+ .c0_ddr4_ui_clk (c0_ddr4_clk),
+ `endif
+ .c0_ddr4_ui_clk_sync_rst (c0_ddr4_rst),
+ .c0_init_calib_complete (c0_init_calib_complete),
+ .dbg_clk (dbg_clk),
+ .c0_ddr4_act_n (c0_ddr4_act_n),
+ .c0_ddr4_adr (c0_ddr4_adr),
+ .c0_ddr4_ba (c0_ddr4_ba),
+ .c0_ddr4_bg (c0_ddr4_bg),
+ .c0_ddr4_cke (c0_ddr4_cke),
+ .c0_ddr4_odt (c0_ddr4_odt),
+ .c0_ddr4_cs_n (c0_ddr4_cs_n),
+ .c0_ddr4_ck_t (c0_ddr4_ck_t),
+ .c0_ddr4_ck_c (c0_ddr4_ck_c),
+ .c0_ddr4_reset_n (c0_ddr4_reset_n),
+ .c0_ddr4_parity (c0_ddr4_parity),
+ .c0_ddr4_dq (c0_ddr4_dq),
+ .c0_ddr4_dqs_c (c0_ddr4_dqs_c),
+ .c0_ddr4_dqs_t (c0_ddr4_dqs_t),
+
+ .dBufAdr (dBufAdr),
+ .wrData (wrData),
+ .rdData (rdData),
+ .rdDataAddr (rdDataAddr),
+ .rdDataEn (rdDataEn),
+ .rdDataEnd (rdDataEnd),
+ .per_rd_done (per_rd_done),
+ .rmw_rd_done (rmw_rd_done),
+ .wrDataAddr (wrDataAddr),
+ .wrDataEn (wrDataEn),
+
+ .mc_ACT_n (dllt_active ? dllt_mc_ACT_n : mc_ACT_n),
+ .mc_ADR (dllt_active ? dllt_mc_ADR : mc_ADR),
+ .mc_BA (dllt_active ? dllt_mc_BA : mc_BA),
+ .mc_BG (dllt_active ? dllt_mc_BG : mc_BG),
+ // DRAM CKE. 8 bits for each DRAM pin. The mc_CKE signal is always set to '1'.
+ .mc_CKE (dllt_active ? dllt_mc_CKE : {8{1'b1}}),
+ .mc_CS_n (dllt_active ? dllt_mc_CS_n : mc_CS_n),
+ .mc_ODT (mc_ODT),
+ // CAS command slot select. Slot0 is enabled for example design.
+ .mcCasSlot (dllt_active ? 0 : mcCasSlot),
+ // CAS slot 2 select. mcCasSlot2 serves a similar purpose as the mcCasSlot[1:0] signal, but mcCasSlot2 is used in timing
+ // critical logic in the Phy. Slot0 is enabled for example design.
+ .mcCasSlot2 (dllt_active ? 0 : mcCasSlot2),
+ .mcRdCAS (dllt_active ? 0 : mcRdCAS),
+ .mcWrCAS (dllt_active ? 0 : mcWrCAS),
+ // Optional read command type indication. The winInjTxn signal is set to '0' for example design.
+ .winInjTxn ({1{1'b0}}),
+ // Optional read command type indication. The winRmw signal is set to '0' for example design.
+ .winRmw ({1{1'b0}}),
+ // Update VT Tracking. The gt_data_ready signal is set to '0' in this example design.
+ // This signal must be asserted periodically to keep the DQS Gate aligned as voltage and temperature drift.
+ // For more information, Refer to PG150 document.
+ .gt_data_ready (gt_data_ready),
+ .winBuf (winBuf),
+ .winRank (winRank),
+ .tCWL (tCWL),
+ // Debug Port
+ .dbg_bus (dbg_bus)
+ );
+
+ softmc_pipeline pipeline(
+ .clk(c0_ddr4_clk),
+ .rst(c0_ddr4_rst || user_rst),
+
+ .softmc_end(softmc_fin),
+ .read_size(incoming_reads),
+ .read_seq_incoming(read_seq_incoming),
+ .buffer_space(buffer_space),
+
+ .addr_out(fr_addr_in),
+ .valid_out(fr_valid_in),
+ .data_in(fr_data_out),
+ .valid_in(fr_valid_out),
+ .addr_in(fr_addr_out),
+ .ready_out(fr_ready_out),
+
+ .ddr_write(ddr_write),
+ .ddr_read(ddr_read),
+ .ddr_pre(ddr_pre),
+ .ddr_act(ddr_act),
+ .ddr_ref(ddr_ref),
+ .ddr_zq(ddr_zq),
+ .ddr_nop(ddr_nop),
+ .ddr_ap(ddr_ap),
+ .ddr_pall(ddr_pall),
+ .ddr_half_bl(ddr_half_bl),
+ .ddr_bg(ddr_bg),
+ .ddr_bank(ddr_bank),
+ .ddr_col(ddr_col),
+ .ddr_row(ddr_row),
+ .ddr_wdata(ddr_wdata)
+ );
+
+ `ifdef ENABLE_DLL_TOGGLER
+ //BUFGMUX:GeneralClockMuxBuffer
+ //UltraScale
+ //XilinxHDLLibrariesGuide, version2014.4
+ BUFGMUX#(.CLK_SEL_TYPE("SYNC") //ASYNC,SYNC
+ )BUFGMUX_inst(
+ .O(c0_ddr4_clk), //1-bitoutput:Clockoutput
+ .I0(ddr4_ui_clk), //1-bitinput:Clockinput(S=0)
+ .I1(c0_ddr4_dll_off_clk), //1-bitinput:Clockinput(S=1)
+ .S(clk_sel) //1-bitinput:Clockselect
+ );
+ //End of BUFGMUX_inst instantiation
+ `endif
+
+ assign icc = c0_init_calib_complete_r;
+
+ wire frontend_ready;
+
+ frontend #(.SIM_MEM(SIM)) frontend(
+ .clk(c0_ddr4_clk),
+ .rst(c0_ddr4_rst),
+
+ .init_calib_complete(c0_init_calib_complete_r),
+ .softmc_fin(softmc_fin),
+ .user_rst(user_rst),
+
+ .dllt_begin(toggle_dll),
+
+ // indicates read_back unit is ready for the next iseq
+ .frontend_ready(frontend_ready),
+
+ // frontend <-> fetch stage if
+ .addr_in(fr_addr_in),
+ .valid_in(fr_valid_in),
+ .data_out(fr_data_out),
+ .valid_out(fr_valid_out),
+ .addr_out(fr_addr_out),
+ .ready_in(fr_ready_out),
+
+ // frontend <-> xdma interface
+ .h2c_tdata_0(m_axis_h2c_tdata_0),
+ .h2c_tlast_0(m_axis_h2c_tlast_0),
+ .h2c_tvalid_0(m_axis_h2c_tvalid_0),
+ .h2c_tready_0(m_axis_h2c_tready_0),
+ .h2c_tkeep_0(m_axis_h2c_tkeep_0),
+
+ .per_rd_init(per_rd_init),
+ .per_zq_init(per_zq_init),
+ .per_ref_init(per_ref_init),
+ .rbe_switch_mode(rbe_switch_mode)
+ );
+
+ ddr4_adapter#(
+ `ifdef XUPP3R
+ `ifdef XUPP3R_x8_1R_UDIMM
+ .DQ_WIDTH(64)
+ `else
+ .DQ_WIDTH(72)
+ `endif
+ `endif
+ ) ddr4_adapter
+ (
+ .clk(c0_ddr4_clk),
+ .rst(c0_ddr4_rst || user_rst),
+ .init_calib_complete(c0_init_calib_complete_r),
+ //.io_config_strobe,
+ //.io_config,
+ .dBufAdr(dBufAdr), // Reserved. Should be tied low.
+ .wrData(wrData), // DRAM write data. There are 8 bits for each DQ lane on the DRAM bus.
+ .wrDataMask(wrDataMask),// DRAM write DM/DBI port.There is one bit for each byte of the wrData port.
+ .wrDataEn(wrDataEn), // Write data Enable. The Phy will assert this port for one cycle for each write CAS command.
+ .mc_ACT_n(mc_ACT_n), // DRAM ACT_n command signal for four DRAM clock cycles.
+ .mc_ADR(mc_ADR), // DRAM address. There are 8 bits in the fabric interface for each address bit on the DRAM bus.
+ .mc_BA(mc_BA), // DRAM bank address. 8 bits for each DRAM bank address.
+ .mc_BG(mc_BG), // DRAM bank group address.
+ .mc_CS_n(mc_CS_n), // DRAM CS_n
+ //.mc_ODT(mc_ODT), // DRAM ODT
+ .mcRdCAS(mcRdCAS), // Read CAS command issued.
+ .mcWrCAS(mcWrCAS), // Write CAS command issued.
+ .winRank(winRank), // Target rank for CAS commands. This value indicates which rank a CAS command is issued to.
+ .winBuf(winBuf), // Optional control signal. When either mcRdCAS or mcWrCAS is asserted, the Phy will store the value on the winBuf signal.
+ //.rdData(rdData), // DRAM read data.
+ .rdDataEn(rdDataEn), // Read data valid. This signal asserts for one fabric cycle for each completed read operation.
+ .rdDataEnd(rdDataEnd), // Unused. Tied high.
+ .mcCasSlot(mcCasSlot),
+ .mcCasSlot2(mcCasSlot2),
+ .gt_data_ready(gt_data_ready),
+ .ddr_write(ddr_write),
+ .ddr_read(ddr_read),
+ .ddr_pre(ddr_pre),
+ .ddr_act(ddr_act),
+ .ddr_ref(ddr_ref),
+ .ddr_zq(ddr_zq),
+ .ddr_nop(ddr_nop),
+ .ddr_ap(ddr_ap),
+ .ddr_pall(ddr_pall),
+ .ddr_half_bl(ddr_half_bl),
+ .ddr_bg(ddr_bg),
+ .ddr_bank(ddr_bank),
+ .ddr_col(ddr_col),
+ .ddr_row(ddr_row),
+ .ddr_wdata(ddr_wdata),
+
+ .ddr_maint_read(per_rd_init)
+ );
+
+ localparam ODTWRDEL = 5'd9;
+ localparam ODTWRDUR = 4'd6;
+ localparam ODTWRODEL = 5'd9;
+ localparam ODTWRODUR = 4'd6;
+ localparam ODTRDDEL = 5'd10;
+ localparam ODTRDDUR = 4'd6;
+ localparam ODTRDODEL = 5'd9;
+ localparam ODTRDODUR = 4'd6;
+ localparam ODTNOP = 16'h0000;
+ localparam ODTWR = 16'h0001;
+ localparam ODTRD = 16'h0000;
+
+ wire tranSentC;
+ assign tranSentC = mcRdCAS | mcWrCAS;
+
+ //synthesis translate_on
+ //*******************************************************************************
+ ddr4_mc_odt # (
+ .ODTWR (ODTWR)
+ ,.ODTWRDEL (ODTWRDEL)
+ ,.ODTWRDUR (ODTWRDUR)
+ ,.ODTWRODEL (ODTWRODEL)
+ ,.ODTWRODUR (ODTWRODUR)
+
+ ,.ODTRD (ODTRD)
+ ,.ODTRDDEL (ODTRDDEL)
+ ,.ODTRDDUR (ODTRDDUR)
+ ,.ODTRDODEL (ODTRDODEL)
+ ,.ODTRDODUR (ODTRDODUR)
+
+ ,.ODTNOP (ODTNOP)
+ ,.ODTBITS (`ODT_WIDTH)
+ ,.TCQ (0.1)
+ )u_ddr_tb_odt(
+ .clk (c0_ddr4_clk)
+ ,.rst (c0_ddr4_rst)
+ ,.mc_ODT (mc_ODT)
+ ,.casSlot (mcCasSlot)
+ ,.casSlot2 (mcCasSlot2)
+ ,.rank (winRank)
+ ,.winRead (mcRdCAS)
+ ,.winWrite (mcWrCAS)
+ ,.tranSentC (tranSentC)
+ );
+
+ wire sys_clk, sys_clk_gt;
+ wire [2:0] msi_vector_width;
+ wire msi_enable;
+ wire user_lnk_up, usr_irq_req, usr_irq_ack;
+ `ifdef XUPP3R
+ IBUFDS_GTE4 refclk_ibuf (.O(sys_clk_gt), .ODIV2(sys_clk), .I(clk_ref_p), .CEB(1'b0), .IB(clk_ref_n));
+ `else
+ IBUFDS_GTE3 # (.REFCLK_HROW_CK_SEL(2'b01)) refclk_ibuf (.O(sys_clk_gt), .ODIV2(sys_clk), .I(clk_ref_p), .CEB(1'b0), .IB(clk_ref_n));
+ `endif
+ wire axi_clk, axi_rst;
+
+ xdma xdma_i
+ (
+ //---------------------------------------------------------------------------------------//
+ // PCI Express (pci_exp) Interface //
+ //---------------------------------------------------------------------------------------//
+ .sys_rst_n ( pcie_rst ),
+ .sys_clk ( sys_clk ),
+ .sys_clk_gt ( sys_clk_gt),
+
+ // Tx
+ .pci_exp_txn ( pci_exp_txn ),
+ .pci_exp_txp ( pci_exp_txp ),
+
+ // Rx
+ .pci_exp_rxn ( pci_exp_rxn ),
+ .pci_exp_rxp ( pci_exp_rxp ),
+
+ // AXI streaming ports
+ .s_axis_c2h_tdata_0(xdma_c2h_tdata_0),
+ .s_axis_c2h_tlast_0(xdma_c2h_tlast_0),
+ .s_axis_c2h_tvalid_0(xdma_c2h_tvalid_0),
+ .s_axis_c2h_tready_0(xdma_c2h_tready_0),
+ .s_axis_c2h_tkeep_0(xdma_c2h_tkeep_0),
+ .m_axis_h2c_tdata_0(xdma_h2c_tdata_0),
+ .m_axis_h2c_tlast_0(xdma_h2c_tlast_0),
+ .m_axis_h2c_tvalid_0(xdma_h2c_tvalid_0),
+ .m_axis_h2c_tready_0(xdma_h2c_tready_0),
+ .m_axis_h2c_tkeep_0(xdma_h2c_tkeep_0),
+
+ .usr_irq_req (1'b0),
+ .usr_irq_ack (usr_irq_ack),
+ .msi_enable (msi_enable),
+ .msi_vector_width (msi_vector_width),
+
+
+ // Config managemnet interface
+ .cfg_mgmt_addr ( 19'b0 ),
+ .cfg_mgmt_write ( 1'b0 ),
+ .cfg_mgmt_write_data ( 32'b0 ),
+ .cfg_mgmt_byte_enable ( 4'b0 ),
+ .cfg_mgmt_read ( 1'b0 ),
+ .cfg_mgmt_read_data (),
+ .cfg_mgmt_read_write_done (),
+ `ifndef XUPP3R
+ .cfg_mgmt_type1_cfg_reg_access ( 1'b0 ),
+ //---------- Shared Logic Internal -------------------------
+ .int_qpll1lock_out ( ),
+ .int_qpll1outrefclk_out ( ),
+ .int_qpll1outclk_out ( ),
+ `endif
+
+ //-- AXI Global
+ .axi_aclk (axi_clk), // AXI i-face clock driven from pcie clk
+ .axi_aresetn (axi_rst), // reset synchronous to axi_clk
+
+ .user_lnk_up ( user_lnk_up )
+ );
+
+ // Clock converter for the c2h interface
+ axis_clock_converter axis_clk_conv_i0
+ (
+ .s_axis_tvalid(s_axis_c2h_tvalid_0),
+ .s_axis_tlast(s_axis_c2h_tlast_0),
+ .s_axis_tdata(s_axis_c2h_tdata_0),
+ .s_axis_tkeep(s_axis_c2h_tkeep_0),
+ .s_axis_tready(s_axis_c2h_tready_0),
+ .m_axis_tvalid(xdma_c2h_tvalid_0),
+ .m_axis_tlast(xdma_c2h_tlast_0),
+ .m_axis_tdata(xdma_c2h_tdata_0),
+ .m_axis_tkeep(xdma_c2h_tkeep_0),
+ .m_axis_tready(xdma_c2h_tready_0),
+ .s_axis_aresetn(~c0_ddr4_rst),
+ .s_axis_aclk(c0_ddr4_clk),
+ .m_axis_aresetn(axi_rst),
+ .m_axis_aclk(axi_clk)
+ );
+
+ // Clock converter for the h2c interface
+ axis_clock_converter axis_clk_conv_i1
+ (
+ .m_axis_tvalid(m_axis_h2c_tvalid_0),
+ .m_axis_tlast(m_axis_h2c_tlast_0),
+ .m_axis_tdata(m_axis_h2c_tdata_0),
+ .m_axis_tkeep(m_axis_h2c_tkeep_0),
+ .m_axis_tready(m_axis_h2c_tready_0),
+ .s_axis_tvalid(xdma_h2c_tvalid_0),
+ .s_axis_tlast(xdma_h2c_tlast_0),
+ .s_axis_tdata(xdma_h2c_tdata_0),
+ .s_axis_tkeep(xdma_h2c_tkeep_0),
+ .s_axis_tready(xdma_h2c_tready_0),
+ .m_axis_aresetn(~c0_ddr4_rst),
+ .m_axis_aclk(c0_ddr4_clk),
+ .s_axis_aresetn(axi_rst),
+ .s_axis_aclk(axi_clk)
+ );
+
+ readback_engine rbe(
+
+ // common signals
+ .clk(c0_ddr4_clk),
+ .rst(c0_ddr4_rst || user_rst),
+
+ // other ctrl signals
+ .flush(frontend_ready),
+ .switch_mode(rbe_switch_mode),
+ .read_seq_incoming(read_seq_incoming), // next few instructions will read from DRAM
+ .incoming_reads(incoming_reads), // how many reads next few instructions will issue
+ .buffer_space(buffer_space), // remaining buffer size
+ // DRAM <-> engine if
+ .rd_data(rdData),
+ .rd_valid(rdDataEn),
+
+ // rbe <-> rf interface
+ .ddr_wdata(ddr_wdata),
+
+ .per_rd_init(per_rd_init),
+ .per_zq_init(per_zq_init),
+ .per_ref_init(per_ref_init),
+
+ // rbe <-> xdma if
+ .c2h_tdata_0(s_axis_c2h_tdata_0),
+ .c2h_tlast_0(s_axis_c2h_tlast_0),
+ .c2h_tvalid_0(s_axis_c2h_tvalid_0),
+ .c2h_tready_0(s_axis_c2h_tready_0),
+ .c2h_tkeep_0(s_axis_c2h_tkeep_0)
+
+ );
+
+ `ifdef ENABLE_DLL_TOGGLER
+ dll_toggler dllt
+ (
+ .clk(c0_ddr4_clk),
+ .rst(c0_ddr4_rst || user_rst || ~c0_init_calib_complete_r),
+ .toggle_valid(toggle_dll),
+ .mc_ACT_n(dllt_mc_ACT_n), // DRAM ACT_n command signal for four DRAM clock cycles.
+ .mc_ADR(dllt_mc_ADR), // DRAM address. There are 8 bits in the fabric interface for each address bit on the DRAM bus.
+ .mc_BA(dllt_mc_BA), // DRAM bank address. 8 bits for each DRAM bank address.
+ .mc_BG(dllt_mc_BG), // DRAM bank group address.
+ .mc_CS_n(dllt_mc_CS_n), // DRAM CS_n
+ .mc_CKE(dllt_mc_CKE),
+ .clk_sel(clk_sel),
+ .dllt_done(dllt_done)
+ );
+ `endif
+endmodule