aboutsummaryrefslogtreecommitdiffstats
path: root/projects/VU095/verilog/ddr4_mc_odt.v
diff options
context:
space:
mode:
Diffstat (limited to 'projects/VU095/verilog/ddr4_mc_odt.v')
-rw-r--r--projects/VU095/verilog/ddr4_mc_odt.v130
1 files changed, 130 insertions, 0 deletions
diff --git a/projects/VU095/verilog/ddr4_mc_odt.v b/projects/VU095/verilog/ddr4_mc_odt.v
new file mode 100644
index 0000000..d8b4940
--- /dev/null
+++ b/projects/VU095/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