aboutsummaryrefslogtreecommitdiffstats
path: root/projects/U50-HBM/verilog/HBM_interface.v
diff options
context:
space:
mode:
authorAtaberk <olgunataberk@gmail.com>2024-05-02 17:22:05 +0200
committerAtaberk <olgunataberk@gmail.com>2024-05-02 17:22:05 +0200
commit7721980589f4c7fa811689e815a77d63f2556497 (patch)
treeded507bcfb0aeddb7ef647dd3888ef93ff12e630 /projects/U50-HBM/verilog/HBM_interface.v
parent82b4ae69fa5fa8728b7aa9a513a9a27fb14a5f78 (diff)
downloaddram-bender-7721980589f4c7fa811689e815a77d63f2556497.tar.gz
Add sources for U50 HBM2
Diffstat (limited to 'projects/U50-HBM/verilog/HBM_interface.v')
-rw-r--r--projects/U50-HBM/verilog/HBM_interface.v628
1 files changed, 628 insertions, 0 deletions
diff --git a/projects/U50-HBM/verilog/HBM_interface.v b/projects/U50-HBM/verilog/HBM_interface.v
new file mode 100644
index 0000000..3600f2b
--- /dev/null
+++ b/projects/U50-HBM/verilog/HBM_interface.v
@@ -0,0 +1,628 @@
+`include "project.vh"
+`include "parameters.vh"
+
+// This module takes 2 DDR commands as input at every dfi_clock cycle
+// The HBM is 2x dfi_clock, which means that it can process 2 commands per dfi_clock cycle
+
+module HBM_interface # (
+ parameter ROW_ADDR_WIDTH = 14,
+ parameter COL_ADDR_WIDTH = 5,
+ parameter BA_ADDR_WIDTH = 4,
+ // these are used for MRS
+ parameter P_DRIVE_PRECHARGE_CMD = 114,
+ parameter P_DRIVE_ACT_CMD = 240,
+ parameter P_MRS_CNT = 8'hc0
+ )(
+
+ // USER INPUTS
+ input [2*`ROW_ADDR_WIDTH-1:0] row_addr,
+ input [2*`COL_ADDR_WIDTH-1:0] col_addr,
+ input [2*`BA_ADDR_WIDTH-1:0] ba_addr,
+ input [2*`WR_DATA_WIDTH-1:0] i_wrdata,
+ input [2*`CMD_TYPE_WIDTH-1:0] cmd_type,
+ input [2*`PC_WIDTH-1:0] BA4, // indicates target PC
+
+ // DFI INTERFACE SIGNALS
+ input dfi_clk,
+ input dfi_rst_n,
+ input dfi_rst_buf_n,
+
+ // Get these from output of PHY. Not used by this module in example design.
+ input dfi_ctrlupd_req,
+ input dfi_phyupd_ack,
+ input apb_complete_0,
+ input apb_complete_1,
+ input DRAM_0_STAT_CATTRIP,
+ input [6:0] DRAM_0_STAT_TEMP,
+ input DRAM_1_STAT_CATTRIP,
+ input [6:0] DRAM_1_STAT_TEMP,
+
+ input dfi_init_complete,
+
+ output dfi_init_start,
+ output [1:0] dfi_aw_ck_p0,
+ output [1:0] dfi_aw_cke_p0,
+ output [11:0] dfi_aw_row_p0,
+ output [15:0] dfi_aw_col_p0,
+ output [255:0] dfi_dw_wrdata_p0,
+
+ output [31:0] dfi_dw_wrdata_mask_p0,
+ output [31:0] dfi_dw_wrdata_dbi_p0,
+ output [7:0] dfi_dw_wrdata_par_p0,
+ output [7:0] dfi_dw_wrdata_dq_en_p0,
+ output [7:0] dfi_dw_wrdata_par_en_p0,
+
+ output [1:0] dfi_aw_ck_p1,
+ output [1:0] dfi_aw_cke_p1,
+ output [11:0] dfi_aw_row_p1,
+ output [15:0] dfi_aw_col_p1,
+ output [255:0] dfi_dw_wrdata_p1,
+
+ output [31:0] dfi_dw_wrdata_mask_p1,
+ output [31:0] dfi_dw_wrdata_dbi_p1,
+ output [7:0] dfi_dw_wrdata_par_p1,
+ output [7:0] dfi_dw_wrdata_dq_en_p1,
+ output [7:0] dfi_dw_wrdata_par_en_p1,
+
+ output dfi_aw_ck_dis,
+ output dfi_lp_pwr_e_req,
+ output dfi_lp_sr_e_req,
+ output dfi_lp_pwr_x_e_req,
+ output dfi_aw_tx_indx_ld,
+ output dfi_dw_tx_indx_ld,
+ output dfi_dw_rx_indx_ld,
+ output dfi_ctrlupd_ack,
+ output dfi_phyupd_req,
+
+ output ready
+
+ );
+
+
+ // FSM states
+ localparam IDLE_S = 2'b00;
+ localparam MRS_S = 2'b01;
+ localparam READY_S = 2'b10;
+
+ // Row Commands
+ localparam CMD_RNOP = 3'b111;
+ localparam CMD_ACT = 3'b010; // 3rd bit is SID0, set to 0 for this HBM configuration.
+ localparam CMD_PRE = 3'b011;
+ localparam CMD_PREA = 3'b011;
+ localparam CMD_REFSB = 3'b100;
+ localparam CMD_REF = 3'b100;
+ localparam CMD_PDE = 3'b111; // Not needed
+ localparam CMD_SRE = 3'b100; // Not needed
+ localparam CMD_PDX_SRX = 3'b111; // Not needed
+
+ // Column Commands
+ localparam CMD_CNOP = 4'b1111;
+ localparam CMD_RD = 4'b0101;
+ localparam CMD_RDA = 4'b1101;
+ localparam CMD_WR = 4'b0001;
+ localparam CMD_WRA = 4'b1001;
+ localparam CMD_MRS = 3'b000;
+
+ // Other parameters
+ localparam PAR = 1'b1; // Parity signal
+ localparam BA4_0 = 1'b0; // Direct commands to PC0
+ localparam BA4_1 = 1'b1; // Direct commands to PC1
+
+ localparam LP_MRS0_A = 4'b0001;
+ localparam LP_MRS1_A = 4'b0001;
+ localparam LP_MRS2_A = 4'b0010;
+ localparam LP_MRS3_A = 4'b0011;
+ localparam LP_MRS4_A = 4'b0100;
+ localparam LP_MRS5_A = 4'b0101;
+ localparam LP_MRS6_A = 4'b0110;
+ localparam LP_MRS7_A = 4'b0111;
+
+
+ // Wires declaration
+ wire w_fsm_rst_b;
+ wire w_mrs_lat_cnt_done;
+ wire w_precharge_lat_done;
+
+ // Registers declaration
+ reg r_fsm_rst_b;
+ reg [3:0] r_fsm_ps;
+ reg [3:0] r_fsm_ns;
+
+ reg [11:0] r_row_cmd [1:0];
+ reg [15:0] r_col_cmd [1:0];
+
+ reg r_dfi_init_start;
+ reg [1:0] r_dfi_aw_ck_p0;
+ reg [1:0] r_dfi_aw_cke_p0;
+ reg [1:0] r_dfi_aw_ck_p1;
+ reg [1:0] r_dfi_aw_cke_p1;
+ reg [3:0] cke_cnt;
+
+ reg [7:0] r_mrs_reg_cnt;
+ reg [11:0] r_activate_lat_cnt;
+ reg [11:0] r_precharge_lat_cnt;
+ reg r_precharge_lat_done;
+ reg r_mrs_lat_cnt_done;
+
+
+ reg [`CMD_TYPE_WIDTH-1:0] r_cmd_type_ps [1:0];
+ reg [2*`ROW_ADDR_WIDTH-1:0] r_row_addr;
+ reg [2*`COL_ADDR_WIDTH-1:0] r_col_addr;
+ reg [2*`BA_ADDR_WIDTH-1:0] r_ba_addr;
+ reg [2*`WR_DATA_WIDTH-1:0] r_wrdata;
+ reg [2*`PC_WIDTH-1:0] r_BA4;
+
+ reg r_ready;
+
+ integer i;
+
+ // Unused signals
+ assign dfi_dw_wrdata_mask_p0 = 32'h0000_0000;
+ assign dfi_dw_wrdata_dbi_p0 = 32'h0000_0000;
+ assign dfi_dw_wrdata_par_p0 = 8'h00;
+ assign dfi_dw_wrdata_dq_en_p0 = 8'h00;
+ assign dfi_dw_wrdata_par_en_p0 = 8'h00;
+
+ assign dfi_dw_wrdata_mask_p1 = 32'h0000_0000;
+ assign dfi_dw_wrdata_dbi_p1 = 32'h0000_0000;
+ assign dfi_dw_wrdata_par_p1 = 8'h00;
+ assign dfi_dw_wrdata_dq_en_p1 = 8'h00;
+ assign dfi_dw_wrdata_par_en_p1 = 8'h00;
+
+ assign dfi_aw_ck_dis = 1'b0;
+ assign dfi_lp_pwr_e_req = 1'b0;
+ assign dfi_lp_sr_e_req = 1'b0;
+ assign dfi_lp_pwr_x_e_req = 1'b0;
+ assign dfi_aw_tx_indx_ld = 1'b0;
+ assign dfi_dw_tx_indx_ld = 1'b0;
+ assign dfi_dw_rx_indx_ld = 1'b0;
+ assign dfi_ctrlupd_ack = 1'b0; // left as Z in example design
+ assign dfi_phyupd_req = 1'b0;
+
+ // Output mapping
+ assign dfi_init_start = r_dfi_init_start;
+
+ assign dfi_aw_ck_p0 = r_dfi_aw_ck_p0;
+ assign dfi_aw_cke_p0 = r_dfi_aw_cke_p0;
+ assign dfi_aw_row_p0 = r_row_cmd[0];
+ assign dfi_aw_col_p0 = r_col_cmd[0];
+ // other version
+ //assign dfi_dw_wrdata_p0 = r_wrdata[0 +: `WR_DATA_WIDTH];
+ assign dfi_dw_wrdata_p0 = {r_wrdata[192 +: 64], r_wrdata[128 +: 64], r_wrdata[64 +: 64], r_wrdata[0 +: 64]};
+
+ assign dfi_aw_ck_p1 = r_dfi_aw_ck_p1;
+ assign dfi_aw_cke_p1 = r_dfi_aw_cke_p1;
+ assign dfi_aw_row_p1 = r_row_cmd[1];
+ assign dfi_aw_col_p1 = r_col_cmd[1];
+
+ // other version
+ //assign dfi_dw_wrdata_p1 = r_wrdata[`WR_DATA_WIDTH +: `WR_DATA_WIDTH];
+ assign dfi_dw_wrdata_p1 = {r_wrdata[448 +: 64], r_wrdata[384 +: 64], r_wrdata[320 +: 64], r_wrdata[256 +: 64]};
+
+
+ assign ready = r_ready;
+
+
+ // Counter to wait for driving CKE signal
+ // We basically wait for initialization to complete, and then drive CKE and CK
+ // After that, we can start performing regular writes/reads
+
+ always @ (posedge dfi_clk or negedge dfi_rst_n) begin
+ if (~dfi_rst_n) begin
+ cke_cnt <= 4'h0;
+ end else if (dfi_init_complete == 1'b1 && cke_cnt != 4'hf) begin
+ cke_cnt <= cke_cnt + 1'b1;
+ end
+ end
+
+ always @ (posedge dfi_clk or negedge dfi_rst_n) begin
+ if (~dfi_rst_n) begin
+ r_dfi_aw_cke_p0 <= 2'b00;
+ r_dfi_aw_cke_p1 <= 2'b00;
+ r_dfi_aw_ck_p0 <= 2'b00;
+ r_dfi_aw_ck_p1 <= 2'b00;
+ end else if (cke_cnt == 4'he) begin
+ r_dfi_aw_cke_p0 <= 2'b11;
+ r_dfi_aw_cke_p1 <= 2'b11;
+ r_dfi_aw_ck_p0 <= 2'b01;
+ r_dfi_aw_ck_p1 <= 2'b01;
+ end
+ end
+
+
+ // Driving init_start signal after APB initialization sequence is complete
+ // We read the dfi_rst_buf_n coming from the HBM IP to determine when initialization completes
+ // We can use dfi_rst_buf_n or dfi_init_complete (dfi_rst_buf_n is set by the HBM IP 1CC after dfi_init_complete)
+
+ always @ (posedge dfi_clk or negedge dfi_rst_n) begin
+ if (~dfi_rst_n) begin
+ r_dfi_init_start <= 1'b0;
+ end else if (dfi_rst_buf_n == 1'b1) begin
+ r_dfi_init_start <= 1'b1;
+ end
+ end
+
+ // Counter to count pre-charge latency before issuing Mode Registers commands
+ // This makes sure that we correctly set the mode registers
+
+ always @ (posedge dfi_clk or negedge dfi_rst_n) begin
+ if (~dfi_rst_n) begin
+ r_precharge_lat_cnt <= 12'h000;
+ r_precharge_lat_done <= 1'b0;
+ end else
+ begin
+ r_precharge_lat_done <= w_precharge_lat_done;
+ if (r_fsm_ps == IDLE_S && dfi_init_complete == 1'b1 && r_precharge_lat_cnt != P_DRIVE_PRECHARGE_CMD) begin
+ r_precharge_lat_cnt <= r_precharge_lat_cnt + 1'b1;
+ end
+ end
+ end
+
+ assign w_precharge_lat_done = (r_precharge_lat_cnt >= P_DRIVE_PRECHARGE_CMD) ? 1'b1 : 1'b0;
+
+ // FSM is in IDLE_S state until initialization completes
+ // After that, we move to the MRS_S state where we can initialize the mode registers
+ assign w_fsm_rst_b = r_precharge_lat_done && dfi_init_complete;
+
+
+ // Counter to count activate latency before issuing ACT command for correct operation
+ // We are using this for the purpose of appropriately setting the Mode Registers
+ // After that, we move to the READY_S state, where we can start sending arbitrary DDR commands
+
+ always @ (posedge dfi_clk or negedge dfi_rst_n) begin
+ if (~dfi_rst_n) begin
+ r_activate_lat_cnt <= 12'h000;
+ r_mrs_lat_cnt_done <= 1'b0;
+ end else
+ begin
+ r_mrs_lat_cnt_done <= w_mrs_lat_cnt_done;
+ if (r_fsm_ps == MRS_S && ( r_mrs_reg_cnt == P_MRS_CNT) && r_activate_lat_cnt != P_DRIVE_ACT_CMD) begin
+ r_activate_lat_cnt <= r_activate_lat_cnt + 1'b1;
+ end
+ end
+ end
+
+ assign w_mrs_lat_cnt_done = (r_activate_lat_cnt >= P_DRIVE_ACT_CMD) ? 1'b1 : 0;
+
+ // Counter to count the MR commands sent
+ // Also used to induce tMRC latency between back-to-back MRS commands
+
+ always @ (posedge dfi_clk or negedge dfi_rst_n) begin
+ if (~dfi_rst_n) begin
+ r_mrs_reg_cnt <= 8'h00;
+ end else if ((r_fsm_ps == MRS_S) && (r_mrs_reg_cnt != P_MRS_CNT)) begin
+ r_mrs_reg_cnt <= r_mrs_reg_cnt + 1'b1;
+ end
+ end
+
+
+
+ // Registers Assignment
+ always @ ( posedge dfi_clk or negedge dfi_rst_n )
+ begin
+ if( dfi_rst_n == 1'b0 )
+ begin
+ r_fsm_ps <= IDLE_S;
+ r_fsm_rst_b <= 1'b0;
+
+ r_cmd_type_ps[0] <= {4{1'b1}};
+ r_cmd_type_ps[1] <= {4{1'b1}};
+ r_row_addr <= {2*ROW_ADDR_WIDTH{1'b0}};
+ r_col_addr <= {2*COL_ADDR_WIDTH{1'b0}};
+ r_ba_addr <= {2*BA_ADDR_WIDTH{1'b0}};
+ r_wrdata <= {2*`WR_DATA_WIDTH{1'b0}};
+ r_BA4 <= 2'b00;
+ end
+ else
+ begin
+ r_fsm_ps <= r_fsm_ns;
+ r_fsm_rst_b <= w_fsm_rst_b;
+
+ r_cmd_type_ps[0] <= cmd_type[`CMD_TYPE_WIDTH*0 +: `CMD_TYPE_WIDTH];
+ r_cmd_type_ps[1] <= cmd_type[`CMD_TYPE_WIDTH*1 +: `CMD_TYPE_WIDTH];
+ r_row_addr <= row_addr;
+ r_col_addr <= col_addr;
+ r_ba_addr <= ba_addr;
+ r_BA4 <= BA4;
+
+ // wrDATA [255:0] corresponds to the data we want to write using the first command
+ // wrDATA [511:256] corresponds to the data we want to write using the second command
+
+ // Each command can target a different PC
+ // Depending on the target PC, we need to write the data accordingly
+
+ // Sent to PC0:
+ // {dfi_dw_wrdata_p1[191:128], dfi_dw_wrdata_p1[63:0], dfi_dw_wrdata_p0[191:128], dfi_dw_wrdata_p0[63:0]}
+ // Sent to PC1:
+ // {dfi_dw_wrdata_p1[255:192], dfi_dw_wrdata_p1[127:64], dfi_dw_wrdata_p0[255:192], dfi_dw_wrdata_p0[127:64]}
+
+ // However, we are still not sure if this is how 256 consecutive bits are stored in memory
+
+ for (i = 0; i < 2; i = i + 1) begin
+ if (r_cmd_type_ps[i] == `WR || r_cmd_type_ps[i] == `WRA) begin
+ // This could be one option
+
+ //r_wrdata[0 + 64*BA4[i] +: 64] <= i_wrdata[`WR_DATA_WIDTH*i + 0 +: 64];
+ //r_wrdata[128 + 64*BA4[i] +: 64] <= i_wrdata[`WR_DATA_WIDTH*i + 64 +: 64];
+ //r_wrdata[256 + 64*BA4[i] +: 64] <= i_wrdata[`WR_DATA_WIDTH*i + 128 +: 64];
+ //r_wrdata[384 + 64*BA4[i] +: 64] <= i_wrdata[`WR_DATA_WIDTH*i + 192 +: 64];
+
+ // Another option we will use is that we assume wrData [255:0] always targets PC0 and wrData[511:256] always targets PC1
+ r_wrdata[0 + 64*0 +: 64] <= i_wrdata[`WR_DATA_WIDTH*0 + 0 +: 64];
+ r_wrdata[128 + 64*0 +: 64] <= i_wrdata[`WR_DATA_WIDTH*0 + 64 +: 64];
+ r_wrdata[256 + 64*0 +: 64] <= i_wrdata[`WR_DATA_WIDTH*0 + 128 +: 64];
+ r_wrdata[384 + 64*0 +: 64] <= i_wrdata[`WR_DATA_WIDTH*0 + 192 +: 64];
+ r_wrdata[0 + 64*1 +: 64] <= i_wrdata[`WR_DATA_WIDTH*1 + 0 +: 64];
+ r_wrdata[128 + 64*1 +: 64] <= i_wrdata[`WR_DATA_WIDTH*1 + 64 +: 64];
+ r_wrdata[256 + 64*1 +: 64] <= i_wrdata[`WR_DATA_WIDTH*1 + 128 +: 64];
+ r_wrdata[384 + 64*1 +: 64] <= i_wrdata[`WR_DATA_WIDTH*1 + 192 +: 64];
+ end else begin
+ //r_wrdata[`WR_DATA_WIDTH*i +: `WR_DATA_WIDTH] <= r_wrdata[`WR_DATA_WIDTH*i +: `WR_DATA_WIDTH];
+ end
+ end
+ end
+ end
+
+ // State Transition
+ always @ (*)
+ begin
+ case( r_fsm_ps )
+ IDLE_S:
+ begin
+ if( r_fsm_rst_b == 1'b0 ) begin
+ r_fsm_ns = IDLE_S;
+ end
+ else begin
+ r_fsm_ns = MRS_S;
+ end
+ end
+ MRS_S:
+ begin
+ if( r_fsm_rst_b == 1'b0 ) begin
+ r_fsm_ns = IDLE_S;
+ end
+ else begin
+ if( r_mrs_lat_cnt_done == 1'b1 ) begin
+ r_fsm_ns = READY_S;
+ end
+ else begin
+ r_fsm_ns = MRS_S;
+ end
+ end
+ end
+ READY_S:
+ begin
+ if( r_fsm_rst_b == 1'b0 ) begin
+ r_fsm_ns = IDLE_S;
+ end
+ else begin
+ r_fsm_ns = READY_S;
+ end
+ end
+ default:
+ begin
+ r_fsm_ns = IDLE_S;
+ end
+ endcase
+ end
+
+ // assert ready signal so that other modules know when to start running user program
+ // We cannot use the dfi_init_complete or dfi_0_out_rst_n for this purpose
+ // since we also need to wait for the MRS sequence to complete
+
+ always @ ( posedge dfi_clk or negedge dfi_rst_n )
+ begin
+ if( dfi_rst_n == 1'b0 )
+ begin
+ r_ready <= 1'b0;
+ end else begin
+ if (r_fsm_ps == READY_S) begin
+ r_ready <= 1'b1;
+ end else begin
+ r_ready <= 1'b0;
+ end
+ end
+ end
+
+ // Row Commands
+ always @ ( posedge dfi_clk or negedge dfi_rst_n )
+ begin
+ if( dfi_rst_n == 1'b0 )
+ begin
+ r_row_cmd[0] <= 12'hfff;
+ r_row_cmd[1] <= 12'hfff;
+ end
+ else
+ begin
+ case( r_fsm_ps )
+ IDLE_S:
+ begin
+ r_row_cmd[0] <= 12'hfff;
+ r_row_cmd[1] <= 12'hfff;
+ end
+ MRS_S: // Initialize Mode Registers
+ begin
+ r_row_cmd[0] <= 12'hfff;
+ r_row_cmd[1] <= 12'hfff;
+ end
+ READY_S: // Ready to start performing regular operations
+ begin
+ // Handle ACT command
+ // Since we can only issue a single ACT per DFI_CLK cycle, any other command alongside an ACT will be ignored
+ if (r_cmd_type_ps[0] == `ACTT) begin
+ // CC1
+ r_row_cmd[0] <= {r_ba_addr[`BA_ADDR_WIDTH*0 + 3], r_row_addr[`ROW_ADDR_WIDTH*0 + 13], r_BA4[0], PAR, r_row_addr[`ROW_ADDR_WIDTH*0+11 +: 2], r_ba_addr[`BA_ADDR_WIDTH*0 +: 3], CMD_ACT};
+ // CC2
+ r_row_cmd[1] <= {r_row_addr[`ROW_ADDR_WIDTH*0+2 +: 3], PAR, r_row_addr[`ROW_ADDR_WIDTH*0 +: 2], r_row_addr[`ROW_ADDR_WIDTH*0+5 +: 6]};
+ end else if (r_cmd_type_ps[1] == `ACTT) begin
+ // CC1
+ r_row_cmd[0] <= {r_ba_addr[`BA_ADDR_WIDTH*1 + 3], r_row_addr[`ROW_ADDR_WIDTH*1 + 13], r_BA4[1], PAR, r_row_addr[`ROW_ADDR_WIDTH*1+11 +: 2], r_ba_addr[`BA_ADDR_WIDTH*1 +: 3], CMD_ACT};
+ // CC2
+ r_row_cmd[1] <= {r_row_addr[`ROW_ADDR_WIDTH*1+2 +: 3], PAR, r_row_addr[`ROW_ADDR_WIDTH*1 +: 2], r_row_addr[`ROW_ADDR_WIDTH*1+5 +: 6]};
+ end else begin
+ for (i = 0; i < 2; i = i + 1) begin
+ case (r_cmd_type_ps[i])
+ `RNOP:
+ begin
+ r_row_cmd[i] <= {3'b111, PAR, 5'b11111, CMD_RNOP};
+ end
+ `PREE:
+ begin
+ r_row_cmd[i] <= {r_ba_addr[`BA_ADDR_WIDTH*i + 3], 1'b0, r_BA4[i], PAR, 2'b11, r_ba_addr[`BA_ADDR_WIDTH*i +: 3], CMD_PRE};
+ end
+ `PREA:
+ begin
+ r_row_cmd[i] <= {2'b11, r_BA4[i], PAR, 5'b11111, CMD_PREA};
+ end
+ `REFSB:
+ begin
+ r_row_cmd[i] <= {r_ba_addr[`BA_ADDR_WIDTH*i + 3], 1'b0, r_BA4[i], PAR, 2'b11, r_ba_addr[`BA_ADDR_WIDTH*i +: 3], CMD_REFSB};
+ end
+ `REFF:
+ begin
+ r_row_cmd[i] <= {2'b11, r_BA4[i], PAR, 5'b11111, CMD_REF};
+ end
+ // Not sure how we can use the following commands or if they work
+ // They are not necessary for the purpose of DRAM Bender
+ `PDE:
+ begin
+ r_row_cmd[i] <= {3'b111, PAR, 5'b11111, CMD_PDE};
+ end
+ `SREE:
+ begin
+ r_row_cmd[i] <= {3'b111, PAR, 5'b11111, CMD_SRE};
+ end
+ `PDX_SRX:
+ begin
+ r_row_cmd[i] <= 12'hfff;
+ end
+ default:
+ begin
+ r_row_cmd[i] <= 12'hfff;
+ end
+ endcase
+ end
+ end
+ end
+ default:
+ begin
+ r_row_cmd[0] <= 12'hfff;
+ r_row_cmd[1] <= 12'hfff;
+ end
+ endcase
+ end
+ end
+
+
+ // Col Commands
+ always @ ( posedge dfi_clk or negedge dfi_rst_n )
+ begin
+ if( dfi_rst_n == 1'b0 )
+ begin
+ r_col_cmd[0] <= 16'hffff;
+ r_col_cmd[1] <= 16'hffff;
+ end
+ else
+ begin
+ case( r_fsm_ps )
+ IDLE_S:
+ begin
+ r_col_cmd[0] <= 16'hffff;
+ r_col_cmd[1] <= 16'hffff;
+ end
+ MRS_S: // Initialize Mode Registers
+ begin
+ case (r_mrs_reg_cnt)
+ 8'h00: begin
+ r_col_cmd[0] <= 16'h0000; //MR-0
+ r_col_cmd[1] <= 16'hffff;
+ end
+ 8'h10: begin
+ r_col_cmd[0] <= 16'hffff;
+ //r_col_cmd_p1 <= 16'hea10; //MR-1
+ r_col_cmd[1] <= 16'ha010; //MR-1
+ end
+ 8'h20: begin
+ //r_col_cmd_p0 <= 16'h2e28; //w_T_WL_MRS2 MR-2
+ r_col_cmd[0] <= {4'b0010, 1'b1, PAR, 2'b10, LP_MRS2_A, 1'b1, CMD_MRS}; //MR-2
+ r_col_cmd[1] <= 16'hffff;
+ end
+ 8'h30: begin
+ r_col_cmd[0] <= 16'hffff;
+ //r_col_cmd_p1 <= 16'h4138; //MR-3
+ r_col_cmd[1] <= 16'hc138; //MR-3
+ end
+ 8'h40: begin
+ //r_col_cmd_p0 <= 16'h1c40; //MR-4
+ r_col_cmd[0] <= 16'h0440; //MR-4
+ r_col_cmd[1] <= 16'hffff;
+ end
+ 8'h50: begin
+ r_col_cmd[0] <= 16'hffff;
+ r_col_cmd[1] <= 16'h0050; //MR-5
+ end
+ 8'h60: begin
+ r_col_cmd[0] <= 16'hc060; //MR-6
+ r_col_cmd[1] <= 16'hffff;
+ end
+ 8'h70: begin
+ r_col_cmd[0] <= 16'hffff;
+ r_col_cmd[1] <= 16'h0270; //MR-7
+ end
+ 8'h80: begin
+ r_col_cmd[0] <= 16'h00f0;
+ r_col_cmd[1] <= 16'hffff; //MR-7
+ end
+ default : begin
+ r_col_cmd[0] <= 16'hffff;
+ r_col_cmd[1] <= 16'hffff;
+ end
+ endcase
+ end
+ READY_S: // Ready to start performing regular operations
+ begin
+ for (i = 0; i < 2; i = i + 1) begin
+ case (r_cmd_type_ps[i])
+ `CNOP:
+ begin
+ r_col_cmd[i] <= {5'b11111, PAR, 6'b111111, CMD_CNOP};
+ end
+ `RD:
+ begin
+ // Here we assume the column address is 5 bits.
+ // According to JEDEC, it is 6 bits, but only col_addr[5:1] are used (so its actually 5 bits)
+ // So here col_addr[4:0] corresponds to col_addr[5:1] in the JEDEC standard
+ r_col_cmd[i] <= {r_BA4[i], r_col_addr[`COL_ADDR_WIDTH*i+1 +: 4], PAR, r_col_addr[`COL_ADDR_WIDTH*i], 1'b0, r_ba_addr[`BA_ADDR_WIDTH*i +: 4], CMD_RD};
+ end
+ `RDA:
+ begin
+ r_col_cmd[i] <= {r_BA4[i], r_col_addr[`COL_ADDR_WIDTH*i+1 +: 4], PAR, r_col_addr[`COL_ADDR_WIDTH*i], 1'b0, r_ba_addr[`BA_ADDR_WIDTH*i +: 4], CMD_RDA};
+ end
+ `WR:
+ begin
+ r_col_cmd[i] <= {r_BA4[i], r_col_addr[`COL_ADDR_WIDTH*i+1 +: 4], PAR, r_col_addr[`COL_ADDR_WIDTH*i], 1'b0, r_ba_addr[`BA_ADDR_WIDTH*i +: 4], CMD_WR};
+ end
+ `WRA:
+ begin
+ r_col_cmd[i] <= {r_BA4[i], r_col_addr[`COL_ADDR_WIDTH*i+1 +: 4], PAR, r_col_addr[`COL_ADDR_WIDTH*i], 1'b0, r_ba_addr[`BA_ADDR_WIDTH*i +: 4], CMD_WRA};
+ end
+ // We don't support sending custom MRS commands from the user side in DRAM Bender
+ default:
+ begin
+ r_col_cmd[i] <= 16'hffff;
+ end
+ endcase
+ end
+ end
+ default:
+ begin
+ r_col_cmd[0] <= 16'hffff;
+ r_col_cmd[1] <= 16'hffff;
+ end
+ endcase
+ end
+ end
+
+endmodule
+
+