diff options
Diffstat (limited to 'projects/U50-HBM/verilog/HBM_interface.v')
| -rw-r--r-- | projects/U50-HBM/verilog/HBM_interface.v | 628 |
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 + + |
