diff --git a/rtl/ddr3_controller.v b/rtl/ddr3_controller.v index fdb7db1..994c4e8 100644 --- a/rtl/ddr3_controller.v +++ b/rtl/ddr3_controller.v @@ -68,17 +68,18 @@ module ddr3_controller #( SECOND_WISHBONE = 0, //set to 1 if 2nd wishbone is needed WB_ERROR = 0, // set to 1 to support Wishbone error (asserts at ECC double bit error) SKIP_INTERNAL_TEST = 1, // skip built-in self test (would require >2 seconds of internal test right after calibration) + DUAL_RANK_DIMM = 0, // enable dual rank DIMM parameter[1:0] ECC_ENABLE = 0, // set to 1 or 2 to add ECC (1 = Side-band ECC per burst, 2 = Side-band ECC per 8 bursts , 3 = Inline ECC ) (only change when you know what you are doing) parameter[1:0] DIC = 2'b00, //Output Driver Impedance Control (2'b00 = RZQ/6, 2'b01 = RZQ/7, RZQ = 240ohms) (only change when you know what you are doing) parameter[2:0] RTT_NOM = 3'b011, //RTT Nominal (3'b000 = disabled, 3'b001 = RZQ/4, 3'b010 = RZQ/2 , 3'b011 = RZQ/6, RZQ = 240ohms) parameter // The next parameters act more like a localparam (since user does not have to set this manually) but was added here to simplify port declaration serdes_ratio = 4, // this controller is fixed as a 4:1 memory controller (CONTROLLER_CLK_PERIOD/DDR3_CLK_PERIOD = 4) wb_data_bits = DQ_BITS*LANES*serdes_ratio*2, - wb_addr_bits = ROW_BITS + COL_BITS + BA_BITS - $clog2(serdes_ratio*2), + wb_addr_bits = ROW_BITS + COL_BITS + BA_BITS - $clog2(serdes_ratio*2) + DUAL_RANK_DIMM, wb_sel_bits = wb_data_bits / 8, wb2_sel_bits = WB2_DATA_BITS / 8, //4 is the width of a single ddr3 command {cs_n, ras_n, cas_n, we_n} plus 3 (ck_en, odt, reset_n) plus bank bits plus row bits - cmd_len = 4 + 3 + BA_BITS + ROW_BITS, + cmd_len = 4 + 3 + BA_BITS + ROW_BITS + DUAL_RANK_DIMM, lanes_clog2 = $clog2(LANES) == 0? 1: $clog2(LANES), parameter[1:0] row_bank_col = (ECC_ENABLE == 3)? 2 : 1, // memory address mapping: 0 {bank, row, col} , 1 = {row, bank, col} , 2 = {bank[2:1]. row, bank[0], col} FOR ECC parameter[0:0] ECC_TEST = 0 @@ -118,7 +119,7 @@ module ddr3_controller #( (* mark_debug = "true" *) input wire[LANES*serdes_ratio*2 - 1:0] i_phy_iserdes_dqs, input wire[LANES*serdes_ratio*2 - 1:0] i_phy_iserdes_bitslip_reference, input wire i_phy_idelayctrl_rdy, - output wire[cmd_len*serdes_ratio-1:0] o_phy_cmd, + output wire[(cmd_len+DUAL_RANK_DIMM)*serdes_ratio-1:0] o_phy_cmd, output reg o_phy_dqs_tri_control, o_phy_dq_tri_control, output wire o_phy_toggle_dqs, output wire[wb_data_bits-1:0] o_phy_data, @@ -168,15 +169,32 @@ module ddr3_controller #( // ddr3 command partitioning /* verilator lint_off UNUSEDPARAM */ - localparam CMD_CS_N = cmd_len - 1, - CMD_RAS_N = cmd_len - 2, - CMD_CAS_N= cmd_len - 3, - CMD_WE_N = cmd_len - 4, - CMD_ODT = cmd_len - 5, - CMD_CKE = cmd_len - 6, - CMD_RESET_N = cmd_len - 7, - CMD_BANK_START = BA_BITS + ROW_BITS - 1, - CMD_ADDRESS_START = ROW_BITS - 1; + generate + if(DUAL_RANK_DIMM) begin + localparam CMD_CS_N_2 = cmd_len - 1, + CMD_CS_N = cmd_len - 2, + CMD_RAS_N = cmd_len - 3, + CMD_CAS_N= cmd_len - 4, + CMD_WE_N = cmd_len - 5, + CMD_ODT = cmd_len - 6, + CMD_CKE = cmd_len - 7, + CMD_RESET_N = cmd_len - 8, + CMD_BANK_START = BA_BITS + ROW_BITS - 1, + CMD_ADDRESS_START = ROW_BITS - 1, + end + else begin + localparam CMD_CS_N = cmd_len - 1, + CMD_RAS_N = cmd_len - 2, + CMD_CAS_N= cmd_len - 3, + CMD_WE_N = cmd_len - 4, + CMD_ODT = cmd_len - 5, + CMD_CKE = cmd_len - 6, + CMD_RESET_N = cmd_len - 7, + CMD_BANK_START = BA_BITS + ROW_BITS - 1, + CMD_ADDRESS_START = ROW_BITS - 1, + end + endgenerate + /* verilator lint_on UNUSEDPARAM */ localparam READ_SLOT = get_slot(CMD_RD), WRITE_SLOT = get_slot(CMD_WR), @@ -412,9 +430,9 @@ module ddr3_controller #( reg stage2_update = 1; reg stage2_stall = 0; reg stage1_stall = 0; - reg[(1< 10 has different format from <= 10 + cmd_d[WRITE_SLOT] = {!stage2_bank[BA_BITS], stage2_bank[BA_BITS], CMD_WR[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank[BA_BITS-1:0],{{ROW_BITS-32'd12}{1'b0}} , stage2_col[(COL_BITS <= 10) ? 0 : 10] , 1'b0 , stage2_col[9:0]}; + end end - else begin // COL_BITS > 10 has different format from <= 10 - cmd_d[WRITE_SLOT] = {1'b0, CMD_WR[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank,{{ROW_BITS-32'd12}{1'b0}} , stage2_col[(COL_BITS <= 10) ? 0 : 10] , 1'b0 , stage2_col[9:0]}; + else begin + if(COL_BITS <= 10) begin + cmd_d[WRITE_SLOT] = {1'b0, CMD_WR[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank,{{ROW_BITS-32'd11}{1'b0}} , 1'b0 , stage2_col[9:0]}; + end + else begin // COL_BITS > 10 has different format from <= 10 + cmd_d[WRITE_SLOT] = {1'b0, CMD_WR[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank,{{ROW_BITS-32'd12}{1'b0}} , stage2_col[(COL_BITS <= 10) ? 0 : 10] , 1'b0 , stage2_col[9:0]}; + end end //turn on odt at same time as write cmd cmd_d[0][CMD_ODT] = cmd_odt; @@ -1549,19 +1600,30 @@ module ddr3_controller #( end delay_before_read_counter_d[stage2_bank] = READ_TO_READ_DELAY; delay_before_write_counter_d[stage2_bank] = READ_TO_WRITE_DELAY + 1; //temporary solution since its possible odt to go high already while reading previously - for(index=0; index < (1< 10 has different format from <= 10 + cmd_d[READ_SLOT] = {!stage2_bank[BA_BITS], stage2_bank[BA_BITS], CMD_RD[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank[BA_BITS-1:0], {{ROW_BITS-32'd12}{1'b0}} , stage2_col[(COL_BITS <= 10) ? 0 : 10] , 1'b0 , stage2_col[9:0]}; + end end - else begin // COL_BITS > 10 has different format from <= 10 - cmd_d[READ_SLOT] = {1'b0, CMD_RD[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank, {{ROW_BITS-32'd12}{1'b0}} , stage2_col[(COL_BITS <= 10) ? 0 : 10] , 1'b0 , stage2_col[9:0]}; + else begin + if(COL_BITS <= 10) begin + cmd_d[READ_SLOT] = {1'b0, CMD_RD[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank, {{ROW_BITS-32'd11}{1'b0}} , 1'b0 , stage2_col[9:0]}; + end + else begin // COL_BITS > 10 has different format from <= 10 + cmd_d[READ_SLOT] = {1'b0, CMD_RD[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank, {{ROW_BITS-32'd12}{1'b0}} , stage2_col[(COL_BITS <= 10) ? 0 : 10] , 1'b0 , stage2_col[9:0]}; + end end + //turn off odt at same time as read cmd cmd_d[0][CMD_ODT] = cmd_odt; cmd_d[1][CMD_ODT] = cmd_odt; @@ -1582,7 +1644,12 @@ module ddr3_controller #( delay_before_write_counter_d[stage2_bank] = ACTIVATE_TO_WRITE_DELAY; end //issue activate command - cmd_d[ACTIVATE_SLOT] = {1'b0, CMD_ACT[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank , stage2_row}; + if(DUAL_RANK_DIMM) begin + cmd_d[ACTIVATE_SLOT] = {!stage2_bank[BA_BITS], stage2_bank[BA_BITS], CMD_ACT[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank[BA_BITS-1:0], stage2_row}; + end + else begin + cmd_d[ACTIVATE_SLOT] = {1'b0, CMD_ACT[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank , stage2_row}; + end //update bank status and active row bank_status_d[stage2_bank] = 1'b1; bank_active_row_d[stage2_bank] = stage2_row; @@ -1593,7 +1660,12 @@ module ddr3_controller #( //set-up delay before activate delay_before_activate_counter_d[stage2_bank] = PRECHARGE_TO_ACTIVATE_DELAY; //issue precharge command - cmd_d[PRECHARGE_SLOT] = {1'b0, CMD_PRE[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank, { {{ROW_BITS-32'd11}{1'b0}} , 1'b0 , stage2_row[9:0] } }; + if(DUAL_RANK_DIMM) begin + cmd_d[PRECHARGE_SLOT] = {!stage2_bank[BA_BITS], stage2_bank[BA_BITS], CMD_PRE[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank[BA_BITS-1:0], { {{ROW_BITS-32'd11}{1'b0}} , 1'b0 , stage2_row[9:0] } }; + end + else begin + cmd_d[PRECHARGE_SLOT] = {1'b0, CMD_PRE[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage2_bank, { {{ROW_BITS-32'd11}{1'b0}} , 1'b0 , stage2_row[9:0] } }; + end //update bank status and active row bank_status_d[stage2_bank] = 1'b0; end @@ -1615,8 +1687,13 @@ module ddr3_controller #( // Thus stage 1 anticipate makes sure smooth burst operation that jumps banks if(bank_status_q[stage1_next_bank] && bank_active_row_q[stage1_next_bank] != stage1_next_row && delay_before_precharge_counter_q[stage1_next_bank] ==0 && !precharge_slot_busy) begin //set-up delay before read and write - delay_before_activate_counter_d[stage1_next_bank] = PRECHARGE_TO_ACTIVATE_DELAY; - cmd_d[PRECHARGE_SLOT] = {1'b0, CMD_PRE[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage1_next_bank, { {{ROW_BITS-32'd11}{1'b0}} , 1'b0 , stage1_next_row[9:0] } }; + delay_before_activate_counter_d[stage1_next_bank] = PRECHARGE_TO_ACTIVATE_DELAY; + if(DUAL_RANK_DIMM) begin + cmd_d[PRECHARGE_SLOT] = {!stage1_next_bank[BA_BITS], stage1_next_bank[BA_BITS], CMD_PRE[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage1_next_bank, { {{ROW_BITS-32'd11}{1'b0}} , 1'b0 , stage1_next_row[9:0] } }; + end + else begin + cmd_d[PRECHARGE_SLOT] = {1'b0, CMD_PRE[2:0], cmd_odt, cmd_ck_en, cmd_reset_n, stage1_next_bank, { {{ROW_BITS-32'd11}{1'b0}} , 1'b0 , stage1_next_row[9:0] } }; + end bank_status_d[stage1_next_bank] = 1'b0; end //end of anticipate precharge @@ -1630,7 +1707,12 @@ module ddr3_controller #( if(delay_before_write_counter_d[stage1_next_bank] <= ACTIVATE_TO_WRITE_DELAY) begin // if current delay is > ACTIVATE_TO_WRITE_DELAY, then updating it to the lower delay will cause the previous delay to be violated delay_before_write_counter_d[stage1_next_bank] = ACTIVATE_TO_WRITE_DELAY; end - cmd_d[ACTIVATE_SLOT] = {1'b0, CMD_ACT[2:0] , cmd_odt, cmd_ck_en, cmd_reset_n, stage1_next_bank , stage1_next_row}; + if(DUAL_RANK_DIMM) begin + cmd_d[ACTIVATE_SLOT] = {!stage1_next_bank[BA_BITS], stage1_next_bank[BA_BITS], CMD_ACT[2:0] , cmd_odt, cmd_ck_en, cmd_reset_n, stage1_next_bank , stage1_next_row}; + end + else begin + cmd_d[ACTIVATE_SLOT] = {1'b0, CMD_ACT[2:0] , cmd_odt, cmd_ck_en, cmd_reset_n, stage1_next_bank , stage1_next_row}; + end bank_status_d[stage1_next_bank] = 1'b1; bank_active_row_d[stage1_next_bank] = stage1_next_row; end //end of anticipate activate @@ -2027,6 +2109,7 @@ module ddr3_controller #( write_by_byte_counter <= 0; initial_calibration_done <= 1'b0; final_calibration_done <= 1'b0; + reset_after_rank_1 <= 1'b0; for(index = 0; index < LANES; index = index + 1) begin added_read_pipe[index] <= 0; data_start_index[index] <= 0; @@ -2052,7 +2135,8 @@ module ddr3_controller #( /* verilator lint_on WIDTH */ idelay_data_cntvaluein_prev <= idelay_data_cntvaluein[lane]; reset_from_calibrate <= 0; - + reset_after_rank_1 <= 0; // reset for dual rank + if(wb2_update) begin odelay_data_cntvaluein[wb2_write_lane] <= wb2_phy_odelay_data_ld[wb2_write_lane]? wb2_phy_odelay_data_cntvaluein : odelay_data_cntvaluein[wb2_write_lane]; odelay_dqs_cntvaluein[wb2_write_lane] <= wb2_phy_odelay_dqs_ld[wb2_write_lane]? wb2_phy_odelay_dqs_cntvaluein : odelay_dqs_cntvaluein[wb2_write_lane]; @@ -2609,7 +2693,13 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin calib_stb <= 0; if(train_delay == 0) begin state_calibrate <= DONE_CALIBRATE; - final_calibration_done <= 1'b1; + if(DUAL_RANK_DIMM) begin + final_calibration_done <= current_rank; // calibration is only done after calibration of 2nd rank + reset_after_rank_1 <= !current_rank; // reset only if current rank is 1st rank + end + else begin + final_calibration_done <= 1'b1; + end end end @@ -2651,7 +2741,23 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin write_test_address_counter <= 0; end end - end + end + + generate + if(DUAL_RANK_DIMM) begin + // logic for current_rank to track if rank 1 or rank 2 is being calibrated + always @(posedge i_controller_clk) begin + if(sync_rst_controller && !reset_after_rank_1) begin // dont reset at reset_after_rank_1 + current_rank <= 1'b0; // start at rank 1 + end + else begin + if(reset_after_rank_1) begin + current_rank <= 1'b1; // switch to 2nd rank after reset + end + end + end + endgenerate + assign issue_read_command = (state_calibrate == MPR_READ && delay_before_read_data == 0); assign o_phy_odelay_data_cntvaluein = odelay_data_cntvaluein[lane]; assign o_phy_odelay_dqs_cntvaluein = odelay_dqs_cntvaluein[lane]; diff --git a/testbench/ddr3.sv b/testbench/ddr3.sv index c6f1fba..db292bf 100644 --- a/testbench/ddr3.sv +++ b/testbench/ddr3.sv @@ -96,7 +96,7 @@ `timescale 1ps / 1ps `define den8192Mb `define sg125 -`define x16 +`define x8 `default_nettype wire module ddr3 ( diff --git a/testbench/ddr3_dimm_micron_sim.sv b/testbench/ddr3_dimm_micron_sim.sv index 3640673..82de706 100644 --- a/testbench/ddr3_dimm_micron_sim.sv +++ b/testbench/ddr3_dimm_micron_sim.sv @@ -31,8 +31,8 @@ `define sg125 `define x16 //`define USE_CLOCK_WIZARD -`define TWO_LANES_x8 -//`define EIGHT_LANES_x8 +//`define TWO_LANES_x8 +`define EIGHT_LANES_x8 `define RAM_8Gb module ddr3_dimm_micron_sim; @@ -57,7 +57,7 @@ module ddr3_dimm_micron_sim; `ifdef EIGHT_LANES_x8 localparam BYTE_LANES = 8, - ODELAY_SUPPORTED = 1; + ODELAY_SUPPORTED = 0; `endif @@ -95,7 +95,7 @@ module ddr3_dimm_micron_sim; wire[$bits(ddr3_top.io_ddr3_dq)-1:0] dq; wire[$bits(ddr3_top.io_ddr3_dqs)-1:0] dqs; wire[$bits(ddr3_top.io_ddr3_dqs_n)-1:0] dqs_n; - wire o_ddr3_clk_p, o_ddr3_clk_n; + wire[1:0] o_ddr3_clk_p, o_ddr3_clk_n; integer index; // Wishbone 2 (PHY) inputs reg i_wb2_cyc; //bus cycle active (1 = normal operation, 0 = all ongoing transaction are to be cancelled) @@ -201,11 +201,11 @@ ddr3_top #( .o_wb2_ack(o_wb2_ack), //1 = read/write request has completed .o_wb2_data(o_wb2_data), //read data, for a 4:1 controller data width is 8 times the number of pins on the device // PHY Interface (to be added later) - .o_ddr3_clk_p(o_ddr3_clk_p), - .o_ddr3_clk_n(o_ddr3_clk_n), - .o_ddr3_cke(ck_en[0]), // CKE - .o_ddr3_cs_n(cs_n[0]), // chip select signal - .o_ddr3_odt(odt[0]), // on-die termination + .o_ddr3_clk_p(o_ddr3_clk_p[1]), + .o_ddr3_clk_n(o_ddr3_clk_n[1]), + .o_ddr3_cke(ck_en[1]), // CKE + .o_ddr3_cs_n(cs_n[1]), // chip select signal + .o_ddr3_odt(odt[1]), // on-die termination .o_ddr3_ras_n(ras_n), // RAS# .o_ddr3_cas_n(cas_n), // CAS# .o_ddr3_we_n(we_n), // WE# @@ -225,8 +225,8 @@ ddr3_top #( // 1 lane DDR3 ddr3 ddr3_0( .rst_n(reset_n), - .ck(o_ddr3_clk_p), - .ck_n(o_ddr3_clk_n), + .ck(o_ddr3_clk_p[0]), + .ck_n(o_ddr3_clk_n[0]), .cke(ck_en[0]), .cs_n(cs_n[0]), .ras_n(ras_n), @@ -241,30 +241,32 @@ ddr3_top #( .tdqs_n(), .odt(odt[0]) ); - assign ck_en[1]=0, - cs_n[1]=1, - odt[1]=0; `endif `ifdef EIGHT_LANES_x8 // DDR3 Device ddr3_module ddr3_module( .reset_n(reset_n), - .ck(o_ddr3_clk_p), - .ck_n(o_ddr3_clk_n), - .cke(ck_en), - .s_n(cs_n), + .ck(o_ddr3_clk_p), //[1:0] + .ck_n(o_ddr3_clk_n), //[1:0] + .cke(ck_en), //[1:0] + .s_n(cs_n), //[1:0] .ras_n(ras_n), .cas_n(cas_n), .we_n(we_n), .ba(ba_addr), .addr(addr), - .odt(odt), + .odt(odt), //[1:0] .dqs({ddr3_dm[0], ddr3_dm,ddr3_dm[0],dqs}), //ddr3_module uses last 8 MSB [16:9] as datamask .dqs_n(dqs_n), .dq(dq) ); + assign ck_en[0]=0, + cs_n[0]=1, + odt[0]=0; `endif + + reg[ddr3_top.ddr3_controller_inst.wb_data_bits-1:0] orig_phy_data; // Force change for ECC tests // Uncommented since there is ECC_TEST parameter inside ddr3_controller to test ECC @@ -945,9 +947,9 @@ ddr3_top #( reg[31:0] time_now; reg[3:0] repeats = 0; //display commands issued - always @(posedge o_ddr3_clk_p) begin - if(!cs_n[0]) begin //command is center-aligned to positive edge of clock, a valid command always has low cs_n - case({cs_n[0], ras_n, cas_n, we_n}) + always @(posedge o_ddr3_clk_p[1]) begin + if(!cs_n[1]) begin //command is center-aligned to positive edge of clock, a valid command always has low cs_n + case({cs_n[1], ras_n, cas_n, we_n}) 4'b0000: command_used = "MRS"; 4'b0001: command_used = "REF"; 4'b0010: command_used = "PRE";