diff options
| author | Ataberk <olgunataberk@gmail.com> | 2022-09-25 17:22:03 +0200 |
|---|---|---|
| committer | Ataberk <olgunataberk@gmail.com> | 2022-09-25 17:22:03 +0200 |
| commit | dc0b3db1b4f1895a07e5fe280ee3790e87f97b9f (patch) | |
| tree | b47203aa281bdd959def4451c84d310cd9cf2e12 /projects/XUPVVH/verilog | |
| download | dram-bender-dc0b3db1b4f1895a07e5fe280ee3790e87f97b9f.tar.gz | |
Initial commit
Diffstat (limited to 'projects/XUPVVH/verilog')
| -rw-r--r-- | projects/XUPVVH/verilog/ddr4_adapter.v | 359 | ||||
| -rw-r--r-- | projects/XUPVVH/verilog/ddr4_mc_odt.v | 130 | ||||
| -rw-r--r-- | projects/XUPVVH/verilog/project.vh | 11 | ||||
| -rw-r--r-- | projects/XUPVVH/verilog/softmc_top.v | 588 |
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 |
