add logic for write wb_ack, wb_sel, and aux

This commit is contained in:
AngeloJacobo 2023-06-22 19:49:05 +08:00
parent f4b138ff77
commit 0ffdacf6e7
1 changed files with 488 additions and 143 deletions

View File

@ -35,17 +35,18 @@
// PRE_STALL_DELAY
module ddr3_controller #(
parameter ROW_BITS = 14, //width of row address
COL_BITS = 10, //width of column address
BA_BITS = 3, //width of bank address
DQ_BITS = 8, //width of DQ
LANES = 8, //8 lanes of DQ
CONTROLLER_CLK_PERIOD = 10, //ns, period of clock input to this DDR3 controller module
DDR3_CLK_PERIOD = 2.5, //ns, period of clock input to DDR3 RAM device
OPT_LOWPOWER = 1, //1 = low power, 0 = low logic
OPT_BUS_ABORT = 1, //1 = can abort bus, 0 = no abort (i_wb_cyc will be ignored, ideal for an AXI implementation which cannot abort transaction)
// 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
parameter real CONTROLLER_CLK_PERIOD = 10, //syntax error, unexpected TOK_ID, expecting ',' or '=' or ')' //ns, period of clock input to this DDR3 controller module
DDR3_CLK_PERIOD = 2.5, //ns, period of clock input to DDR3 RAM device
parameter ROW_BITS = 14, //width of row address
COL_BITS = 10, //width of column address
BA_BITS = 3, //width of bank address
DQ_BITS = 8, //width of DQ
LANES = 8, //8 lanes of DQ
AUX_WIDTH = 16,
parameter[0:0] OPT_LOWPOWER = 1, //1 = low power, 0 = low logic
OPT_BUS_ABORT = 1, //1 = can abort bus, 0 = no abort (i_wb_cyc will be ignored, ideal for an AXI implementation which cannot abort transaction)
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 = $rtoi(CONTROLLER_CLK_PERIOD/DDR3_CLK_PERIOD),
wb_addr_bits = ROW_BITS + COL_BITS + BA_BITS - $clog2(DQ_BITS*(serdes_ratio)*2 / 8),
wb_data_bits = DQ_BITS*LANES*serdes_ratio*2,
@ -63,12 +64,12 @@ module ddr3_controller #(
input wire[wb_addr_bits - 1:0] i_wb_addr, //burst-addressable {row,bank,col}
input wire[wb_data_bits - 1:0] i_wb_data, //write data, for a 4:1 controller data width is 8 times the number of pins on the device
input wire[wb_sel_bits - 1:0] i_wb_sel, //byte strobe for write (1 = write the byte)
input wire i_aux, //for AXI-interface compatibility (given upon strobe)
input wire[AUX_WIDTH - 1:0] i_aux, //for AXI-interface compatibility (given upon strobe)
// Wishbone outputs
output reg o_wb_stall, //1 = busy, cannot accept requests
output wire o_wb_ack, //1 = read/write request has completed
output wire[wb_data_bits - 1:0] o_wb_data, //read data, for a 4:1 controller data width is 8 times the number of pins on the device
output reg o_aux, //for AXI-interface compatibility (returned upon ack)
output wire[AUX_WIDTH - 1:0] o_aux, //for AXI-interface compatibility (returned upon ack)
// PHY interface
input wire[DQ_BITS*LANES*8-1:0] i_phy_iserdes_data,
input wire[LANES*8-1:0] i_phy_iserdes_dqs,
@ -78,6 +79,7 @@ module ddr3_controller #(
output wire 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,
output wire[wb_sel_bits-1:0] o_phy_dm,
output wire[4:0] o_phy_odelay_data_cntvaluein, o_phy_odelay_dqs_cntvaluein,
output wire[4:0] o_phy_idelay_data_cntvaluein, o_phy_idelay_dqs_cntvaluein,
output reg[LANES-1:0] o_phy_odelay_data_ld, o_phy_odelay_dqs_ld,
@ -156,7 +158,7 @@ module ddr3_controller #(
`ifdef DDR3_1600_11_11_11 //DDR3-1600 (11-11-11) speed bin
localparam tRCD = 13.750; // ns Active to Read/Write command time
localparam tRP = 13.750; // ns Precharge command period
localparam tRAS = 35; // ns ACT to PRE command period
`endif
`ifdef RAM_1Gb
@ -194,6 +196,7 @@ module ddr3_controller #(
/********************************************************** Computed Delay Parameters **********************************************************/
localparam PRECHARGE_TO_ACTIVATE_DELAY = find_delay(ns_to_nCK(tRP), PRECHARGE_SLOT, ACTIVATE_SLOT); //3
localparam ACTIVATE_TO_PRECHARGE_DELAY = find_delay(ns_to_nCK(tRAS), ACTIVATE_SLOT, PRECHARGE_SLOT);
localparam ACTIVATE_TO_WRITE_DELAY = find_delay(ns_to_nCK(tRCD), ACTIVATE_SLOT, WRITE_SLOT); //3
localparam ACTIVATE_TO_READ_DELAY = find_delay(ns_to_nCK(tRCD), ACTIVATE_SLOT, READ_SLOT); //2
localparam READ_TO_WRITE_DELAY = find_delay((CL_nCK + tCCD + 3'd2 - CWL_nCK), READ_SLOT, WRITE_SLOT); //2
@ -209,8 +212,17 @@ module ddr3_controller #(
//Also, worscase is when the anticipated bank still has the leftover of the
//WRITE_TO_PRECHARGE_DELAY thus consider also this.
localparam MARGIN_BEFORE_ANTICIPATE = PRECHARGE_TO_ACTIVATE_DELAY + ACTIVATE_TO_WRITE_DELAY + WRITE_TO_PRECHARGE_DELAY;
localparam STAGE2_DATA_DEPTH = ($rtoi($floor((CWL_nCK - (3 - WRITE_SLOT + 1))/4.0 ))) + 1; //this is always >= 1
localparam STAGE2_DATA_DEPTH = (CWL_nCK - (3 - WRITE_SLOT + 1))/4 + 1; //this is always >= 1 (5 - (3 - 3 + 1))/4.0 -> floor(1) + 1 = floor(4
`ifdef FORMAL
wire stage2_data_depth;
assign stage2_data_depth = STAGE2_DATA_DEPTH;
always @* begin
assert(STAGE2_DATA_DEPTH-2 >= 0);
end
`endif
localparam READ_DELAY = $rtoi($floor((CL_nCK - (3 - READ_SLOT + 1))/4.0 ));
localparam READ_ACK_PIPE_WIDTH = READ_DELAY + 1 + 2 + 1 + 1;
localparam MAX_ADDED_READ_ACK_DELAY = 16;
localparam DELAY_BEFORE_WRITE_LEVEL_FEEDBACK = STAGE2_DATA_DEPTH + ns_to_cycles(tWLO+tWLOE) + 10; //plus 10 controller clocks for possible bus latency and
//the delay for receiving feedback DQ from IOBUF -> IDELAY -> ISERDES
/*********************************************************************************************************************************************/
@ -300,8 +312,10 @@ module ddr3_controller #(
//pipeline stage 1 regs
reg stage1_pending = 0;
reg[AUX_WIDTH-1:0] stage1_aux = 0;
reg stage1_we = 0;
reg[wb_data_bits - 1:0] stage1_data = 0;
reg[wb_sel_bits - 1:0] stage1_dm = 0;
reg[COL_BITS-1:0] stage1_col = 0;
reg[BA_BITS-1:0] stage1_bank = 0;
reg[ROW_BITS-1:0] stage1_row = 0;
@ -311,10 +325,14 @@ module ddr3_controller #(
//pipeline stage 2 regs
reg stage2_pending = 0;
reg[AUX_WIDTH-1:0] stage2_aux = 0;
reg stage2_we = 0;
reg [wb_data_bits - 1:0] stage2_data [STAGE2_DATA_DEPTH-1:0];
reg [wb_data_bits - 1:0] stage2_data_unaligned = 0;
reg[wb_sel_bits - 1:0] stage2_dm_unaligned = 0;
reg[wb_sel_bits - 1:0] stage2_dm[STAGE2_DATA_DEPTH-1:0];
reg[wb_data_bits - 1:0] stage2_data_unaligned = 0;
reg[wb_data_bits - 1:0] stage2_data[STAGE2_DATA_DEPTH-1:0];
reg [DQ_BITS*8 - 1:0] unaligned_data[LANES-1:0];
reg [8 - 1:0] unaligned_dm[LANES-1:0];
reg[COL_BITS-1:0] stage2_col = 0;
reg[BA_BITS-1:0] stage2_bank = 0;
reg[ROW_BITS-1:0] stage2_row = 0;
@ -364,14 +382,17 @@ module ddr3_controller #(
reg[3:0] added_read_pipe_max = 0;
reg[3:0] added_read_pipe[LANES - 1:0];
reg[(READ_DELAY + 1 + 2 + 1):0] shift_reg_read_pipe_q, shift_reg_read_pipe_d; ///1=issue command delay (OSERDES delay), 2 = ISERDES delay
//contains the ack shift reg for both read and write
reg[AUX_WIDTH:0] shift_reg_read_pipe_q[READ_ACK_PIPE_WIDTH-1:0];
reg[AUX_WIDTH:0] shift_reg_read_pipe_d[READ_ACK_PIPE_WIDTH-1:0]; //1=issue command delay (OSERDES delay), 2 = ISERDES delay
reg index_read_pipe; //tells which delay_read_pipe will be updated
reg[1:0] index_wb_data; //tells which o_wb_data_q will be sent to o_wb_data
reg[15:0] delay_read_pipe[1:0]; //delay when each lane will retrieve i_phy_iserdes_data
reg[wb_data_bits - 1:0] o_wb_data_q[1:0]; //store data retrieved from i_phy_iserdes_data to be sent to o_wb_data
reg[15:0] o_wb_ack_read_q;
reg[AUX_WIDTH:0] o_wb_ack_read_q[MAX_ADDED_READ_ACK_DELAY-1:0];
reg write_calib_stb = 0;
reg[AUX_WIDTH-1:0] write_calib_aux = 0;
reg write_calib_we = 0;
reg[3:0] write_calib_col = 0;
reg[wb_data_bits-1:0] write_calib_data = 0;
@ -387,7 +408,8 @@ module ddr3_controller #(
reg[4:0] idelay_data_cntvaluein[LANES-1:0];
reg[4:0] idelay_data_cntvaluein_prev;
reg[4:0] idelay_dqs_cntvaluein[LANES-1:0];
wire[31:0] read_ack_width;
assign read_ack_width = READ_ACK_PIPE_WIDTH;
// initial block for all regs
initial begin
for(index=0; index < (1<<BA_BITS); index=index+1) begin
@ -399,6 +421,7 @@ module ddr3_controller #(
for(index = 0; index < STAGE2_DATA_DEPTH; index = index+1) begin
stage2_data[index] = 0;
stage2_dm[index] = 0;
end
for(index=0; index <(1<<BA_BITS); index=index+1) begin
@ -408,6 +431,11 @@ module ddr3_controller #(
delay_before_read_counter_q[index] = 0;
end
for(index = 0; index < READ_ACK_PIPE_WIDTH; index = index + 1) begin
shift_reg_read_pipe_q[index] = 0;
shift_reg_read_pipe_d[index] = 0;
end
//set all commands to all 1's makig CS_n high (thus commands are initially NOP)
for(index=0; index < 4; index=index+1) begin
cmd_q[index] = -1;
@ -601,8 +629,10 @@ module ddr3_controller #(
stage2_row <= 0;
cmd_odt_q <= 0;
stage2_data_unaligned <= 0;
stage2_dm_unaligned <= 0;
for(index=0; index<LANES; index=index+1) begin
unaligned_data[index] <= 0;
unaligned_dm[index] <= 0;
end
//set delay counters to 0
for(index=0; index<(1<<BA_BITS); index=index+1) begin
@ -619,6 +649,7 @@ module ddr3_controller #(
//reset data
for(index = 0; index < STAGE2_DATA_DEPTH; index = index+1) begin
stage2_data[index] <= 0;
stage2_dm[index] <= 0;
end
end
@ -666,9 +697,17 @@ module ddr3_controller #(
stage1_pending <= 0; //move pending request to stage 2 thus stage 1 will not be pending anymore UNLESS there is a wb request at this clk cycle
end
//abort any outgoing ack when cyc is low
if(!i_wb_cyc && state_calibrate == DONE_CALIBRATE) begin
stage2_pending <= 0;
stage1_pending <= 0;
end
//if pipeline is not stalled, move pipeline forward
if(!pipe_stall) begin
stage2_aux <= stage1_aux;
stage2_we <= stage1_we;
stage2_dm_unaligned <= stage1_dm;
stage2_col <= stage1_col;
stage2_bank <= stage1_bank;
stage2_row <= stage1_row;
@ -683,7 +722,9 @@ module ddr3_controller #(
//request is on the same bank as the current request. This
//will ensure stage1 bank will be different from stage2 bank
stage1_pending <= i_wb_stb;//actual request flag
stage1_aux = i_aux; //aux ID for AXI compatibility
stage1_we <= i_wb_we; //write-enable
stage1_dm <= i_wb_sel; //byte selection
stage1_col <= { i_wb_addr[(COL_BITS- $clog2(serdes_ratio*2)-1):0], {{$clog2(serdes_ratio*2)}{1'b0}} }; //column address (n-burst word-aligned)
stage1_bank <= i_wb_addr[(BA_BITS + COL_BITS- $clog2(serdes_ratio*2) - 1) : (COL_BITS- $clog2(serdes_ratio*2))]; //bank_address
stage1_row <= i_wb_addr[ (ROW_BITS + BA_BITS + COL_BITS- $clog2(serdes_ratio*2) - 1) : (BA_BITS + COL_BITS- $clog2(serdes_ratio*2)) ]; //row_address
@ -698,6 +739,8 @@ module ddr3_controller #(
else if(write_calib_stb) begin
stage1_pending <= write_calib_stb;//actual request flag
stage1_we <= write_calib_we; //write-enable
stage1_dm <= 0;
stage1_aux <= write_calib_aux; //aux ID for AXI compatibility
stage1_col <= write_calib_col; //column address (n-burst word-aligned)
stage1_bank <= 0; //bank_address
stage1_row <= 0; //row_address
@ -706,21 +749,36 @@ module ddr3_controller #(
end
for(index = 0; index < LANES; index = index + 1) begin
{unaligned_data[index], { stage2_data[0][((DQ_BITS*LANES)*7 + 8*index) +: 8], stage2_data[0][((DQ_BITS*LANES)*6 + 8*index) +: 8], stage2_data[0][((DQ_BITS*LANES)*5 + 8*index) +: 8],
stage2_data[0][((DQ_BITS*LANES)*4 + 8*index) +: 8], stage2_data[0][((DQ_BITS*LANES)*3 + 8*index) +: 8], stage2_data[0][((DQ_BITS*LANES)*2 + 8*index) +: 8], stage2_data[0][((DQ_BITS*LANES)*1 + 8*index) +: 8],
stage2_data[0][((DQ_BITS*LANES)*0 + 8*index) +: 8] }}
<= ( {stage2_data_unaligned[((DQ_BITS*LANES)*7 + 8*index) +: 8], stage2_data_unaligned[((DQ_BITS*LANES)*6 + 8*index) +: 8],
stage2_data_unaligned[((DQ_BITS*LANES)*5 + 8*index) +: 8], stage2_data_unaligned[((DQ_BITS*LANES)*4 + 8*index) +: 8], stage2_data_unaligned[((DQ_BITS*LANES)*3 + 8*index) +: 8],
stage2_data_unaligned[((DQ_BITS*LANES)*2 + 8*index) +: 8],stage2_data_unaligned[((DQ_BITS*LANES)*1 + 8*index) +: 8],stage2_data_unaligned[((DQ_BITS*LANES)*0 + 8*index) +: 8] }
{unaligned_data[index], {
stage2_data[0][((DQ_BITS*LANES)*7 + 8*index) +: 8], stage2_data[0][((DQ_BITS*LANES)*6 + 8*index) +: 8],
stage2_data[0][((DQ_BITS*LANES)*5 + 8*index) +: 8], stage2_data[0][((DQ_BITS*LANES)*4 + 8*index) +: 8],
stage2_data[0][((DQ_BITS*LANES)*3 + 8*index) +: 8], stage2_data[0][((DQ_BITS*LANES)*2 + 8*index) +: 8],
stage2_data[0][((DQ_BITS*LANES)*1 + 8*index) +: 8], stage2_data[0][((DQ_BITS*LANES)*0 + 8*index) +: 8] }}
<= ( { stage2_data_unaligned[((DQ_BITS*LANES)*7 + 8*index) +: 8], stage2_data_unaligned[((DQ_BITS*LANES)*6 + 8*index) +: 8],
stage2_data_unaligned[((DQ_BITS*LANES)*5 + 8*index) +: 8], stage2_data_unaligned[((DQ_BITS*LANES)*4 + 8*index) +: 8],
stage2_data_unaligned[((DQ_BITS*LANES)*3 + 8*index) +: 8], stage2_data_unaligned[((DQ_BITS*LANES)*2 + 8*index) +: 8],
stage2_data_unaligned[((DQ_BITS*LANES)*1 + 8*index) +: 8], stage2_data_unaligned[((DQ_BITS*LANES)*0 + 8*index) +: 8] }
<< data_start_index[index]) | unaligned_data[index];
{unaligned_dm[index], {
stage2_dm[0][LANES*7 + index], stage2_dm[0][LANES*6 + index],
stage2_dm[0][LANES*5 + index], stage2_dm[0][LANES*4 + index],
stage2_dm[0][LANES*3 + index], stage2_dm[0][LANES*2 + index],
stage2_dm[0][LANES*1 + index], stage2_dm[0][LANES*0 + index] }}
<= ( { stage2_dm_unaligned[LANES*7 + index], stage2_dm_unaligned[LANES*6 + index],
stage2_dm_unaligned[LANES*5 + index], stage2_dm_unaligned[LANES*4 + index],
stage2_dm_unaligned[LANES*3 + index], stage2_dm_unaligned[LANES*2 + index],
stage2_dm_unaligned[LANES*1 + index], stage2_dm_unaligned[LANES*0 + index] }
<< (data_start_index[index]>>3)) | unaligned_dm[index];
end
//{unaligned_data, stage2_data[0]} <= (stage2_data_unaligned << data_start_index) | unaligned_data;
for(index = 1; index < STAGE2_DATA_DEPTH; index = index+1) begin
stage2_data[index] <= stage2_data[index-1];
for(index = 0; index < STAGE2_DATA_DEPTH-1; index = index+1) begin
stage2_data[index+1] <= stage2_data[index];
stage2_dm[index+1] <= stage2_dm[index];
end
end
end
assign o_phy_data = stage2_data[STAGE2_DATA_DEPTH-1];
assign o_phy_dm = stage2_dm[STAGE2_DATA_DEPTH-1];
// DIAGRAM FOR ALL RELEVANT TIMING PARAMETERS:
//
// tRTP
@ -774,7 +832,10 @@ module ddr3_controller #(
assert(delay_before_read_counter_d[index] <= max(WRITE_TO_READ_DELAY,ACTIVATE_TO_READ_DELAY));
`endif
end
shift_reg_read_pipe_d = shift_reg_read_pipe_q>>1;
for(index = 1; index < READ_ACK_PIPE_WIDTH; index = index + 1) begin
shift_reg_read_pipe_d[index-1] = shift_reg_read_pipe_q[index];
end
shift_reg_read_pipe_d[READ_ACK_PIPE_WIDTH-1] = 0;
//if there is a pending request, issue the appropriate commands
if(stage2_pending) begin
o_wb_stall_d = o_wb_stall;
@ -786,8 +847,29 @@ module ddr3_controller #(
o_wb_stall_d = 0;
pipe_stall = 0; //move pipeline forward since write access is already done
cmd_odt = 1'b1;
shift_reg_read_pipe_d[READ_ACK_PIPE_WIDTH-1] = {stage2_aux, 1'b1};
//write acknowledge will use the same logic pipeline as the read acknowledge.
//This would mean write ack latency will be the same for
//read ack latency. If it takes 8 clocks for read ack, write
//ack latency will be the same. This simplifies the logic
//for write ack as there will be no need to analyze the
//contents of the shift_reg_read_pipe just to determine
//where best to place the write ack on the pipeline (since
//the order of ack must be maintaned). But this would mean
//the latency for write is fixed regardless if there is an
//outstanding read ack or none on the pipeline
//set-up delay before precharge, read, and write
delay_before_precharge_counter_d[stage2_bank] = WRITE_TO_PRECHARGE_DELAY;
if(delay_before_precharge_counter_q[stage2_bank] <= WRITE_TO_PRECHARGE_DELAY) begin
//it is possible that the delay_before_precharge is
//set to tRAS (activate to precharge delay). And if we
//overwrite delay_before_precharge, we might overwrite
//the delay to a lower value which will violate the
//tRAS requirement. Thus, we must first check if the
//delay_before_precharge is set to a value not more
//than the WRITE_TO_PRECHARGE_DELAY
delay_before_precharge_counter_d[stage2_bank] = WRITE_TO_PRECHARGE_DELAY;
end
for(index=0; index < (1<<BA_BITS); index=index+1) begin //the write to read delay applies to all banks (odt must be turned off properly before reading)
delay_before_read_counter_d[index] = WRITE_TO_READ_DELAY;
end
@ -816,11 +898,13 @@ module ddr3_controller #(
pipe_stall = 0; //move pipeline forward since read access is already done
cmd_odt = 1'b0;
//set-up delay before precharge, read, and write
delay_before_precharge_counter_d[stage2_bank] = READ_TO_PRECHARGE_DELAY;
if(delay_before_precharge_counter_q[stage2_bank] <= READ_TO_PRECHARGE_DELAY) begin
delay_before_precharge_counter_d[stage2_bank] = READ_TO_PRECHARGE_DELAY;
end
delay_before_read_counter_d[stage2_bank] = READ_TO_READ_DELAY;
delay_before_write_counter_d[stage2_bank] = READ_TO_WRITE_DELAY;
shift_reg_read_pipe_d[READ_DELAY + 1 + 2 + 1] = 1'b1;
shift_reg_read_pipe_d[READ_ACK_PIPE_WIDTH-1] = {stage2_aux, 1'b1};
//issue read command
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-4'd11}{1'b0}} , 1'b0 , stage2_col[9:0]};
@ -839,9 +923,10 @@ module ddr3_controller #(
//bank is idle so activate it
else if(!bank_status_q[stage2_bank] && delay_before_activate_counter_q[stage2_bank] == 0) begin
activate_slot_busy = 1'b1;
delay_before_precharge_counter_d[stage2_bank] = ACTIVATE_TO_PRECHARGE_DELAY;
//set-up delay before read and write
if(delay_before_read_counter_d[stage2_bank] < ACTIVATE_TO_READ_DELAY) begin
delay_before_read_counter_d[stage2_bank] <= ACTIVATE_TO_READ_DELAY;
if(delay_before_read_counter_q[stage2_bank] <= ACTIVATE_TO_READ_DELAY) begin
delay_before_read_counter_d[stage2_bank] = ACTIVATE_TO_READ_DELAY;
end
delay_before_write_counter_d[stage2_bank] = ACTIVATE_TO_WRITE_DELAY;
//issue activate command
@ -883,9 +968,10 @@ module ddr3_controller #(
//anticipated bank is idle so do activate
else if(!bank_status_q[stage1_next_bank] && delay_before_activate_counter_q[stage1_next_bank] == 0 && !activate_slot_busy) begin
delay_before_precharge_counter_d[stage1_next_bank] = ACTIVATE_TO_PRECHARGE_DELAY;
//set-up delay before read and write
if(delay_before_read_counter_d[stage1_next_bank] < ACTIVATE_TO_READ_DELAY) begin
delay_before_read_counter_d[stage1_next_bank] <= ACTIVATE_TO_READ_DELAY;
delay_before_read_counter_d[stage1_next_bank] = ACTIVATE_TO_READ_DELAY;
end
delay_before_write_counter_d[stage1_next_bank] = ACTIVATE_TO_WRITE_DELAY;
cmd_d[ACTIVATE_SLOT] = {1'b0, CMD_ACT[2:0] , cmd_odt, cmd_ck_en, cmd_reset_n, stage1_next_bank , stage1_next_row};
@ -917,7 +1003,6 @@ module ddr3_controller #(
/******************************************************* Align Read Data from ISERDES *******************************************************/
always @(posedge i_controller_clk, negedge i_rst_n) begin
if(!i_rst_n ) begin
shift_reg_read_pipe_q <= 0;
index_read_pipe <= 0;
index_wb_data <= 0;
write_dqs_val <= 0;
@ -925,13 +1010,18 @@ module ddr3_controller #(
write_dqs <= 0;
write_dq_q <= 0;
write_dq <= 0;
o_wb_ack_read_q <= 0;
for(index = 0; index < 2; index = index + 1) begin
delay_read_pipe[index] <= 0;
end
for(index = 0; index < 2; index = index + 1) begin
o_wb_data_q[index] <= 0;
end
for(index = 0; index < READ_ACK_PIPE_WIDTH; index = index + 1) begin
shift_reg_read_pipe_q[index] <= 0;
end
for(index = 0; index < MAX_ADDED_READ_ACK_DELAY ; index = index + 1) begin
o_wb_ack_read_q[index] <= 0;
end
end
else begin
write_dqs_val[0] <= write_dqs_d || write_dqs_q[0];
@ -941,19 +1031,55 @@ module ddr3_controller #(
write_dq_q <= write_dq_d;
write_dq[0] <= write_dq_d || write_dq_q; //high for 2 clk cycles
for(index = 1; index <= STAGE2_DATA_DEPTH; index = index+1) begin //increase by 1 to accomodate postamble
write_dqs[index] <= write_dqs[index-1];
write_dqs_val[index] <= write_dqs_val[index-1];
for(index = 0; index < STAGE2_DATA_DEPTH; index = index+1) begin //increase by 1 to accomodate postamble
write_dqs[index+1] <= write_dqs[index];
write_dqs_val[index+1] <= write_dqs_val[index];
end
for(index = 1; index <= STAGE2_DATA_DEPTH+1; index = index+1) begin //increase by 1 to accomodate postamble
write_dq[index] <= write_dq[index-1];
for(index = 0; index < STAGE2_DATA_DEPTH+1; index = index+1) begin //increase by 1 to accomodate postamble
write_dq[index+1] <= write_dq[index];
end
shift_reg_read_pipe_q <= shift_reg_read_pipe_d;
for(index = 0; index < READ_ACK_PIPE_WIDTH; index = index + 1) begin
shift_reg_read_pipe_q[index] <= shift_reg_read_pipe_d[index];
end
/*
f_sum_of_pending_ack = stage1_pending + stage2_pending +
if(f_outstanding == 1) begin
assert(stage1_pending ^ stage2_pending);
if(stage1_pending) begin
assert(!stage2_pending);
for(index = 0; index < READ_ACK_PIPE_WIDTH; index = index + 1) begin
assert(shift_reg_read_pipe_q[index] == 0);
end
for(index = 0; index < MAX_ADDED_READ_ACK_DELAY; index = index + 1) begin
assert(o_wb_ack_read_q[index] == 0);
end
end
else if(stage2_pending) begin
assert(!stage1_pending);
for(index = 0; index < READ_ACK_PIPE_WIDTH; index = index + 1) begin
assert(shift_reg_read_pipe_q[index] == 0);
end
for(index = 0; index < MAX_ADDED_READ_ACK_DELAY; index = index + 1) begin
assert(o_wb_ack_read_q[index] == 0);
end
end
else begin //neither stage1 nor stage2 is pending
for(index = 0; index < READ_ACK_PIPE_WIDTH; index = index + 1) begin
f_sum_of_pending_acks = shift_reg_read_pipe_q[index] == 0);
end
for(index = 0; index < MAX_ADDED_READ_ACK_DELAY; index = index + 1) begin
assert(o_wb_ack_read_q[index] == 0);
end
end
end
*/
for(index = 0; index < 2; index = index + 1) begin
delay_read_pipe[index] <= (delay_read_pipe[index] >> 1);
end
if(shift_reg_read_pipe_q[1]) begin //delay is over and data is now starting to release from iserdes BUT NOT YET ALIGNED
if(shift_reg_read_pipe_q[1][0]) begin //delay is over and data is now starting to release from iserdes BUT NOT YET ALIGNED
index_read_pipe <= !index_read_pipe; //control which delay_read_pipe would get updated (we have 3 pipe to store read data)ss
delay_read_pipe[index_read_pipe][added_read_pipe_max] <= 1'b1; //update delay_read_pipe
end
@ -978,25 +1104,39 @@ module ddr3_controller #(
o_wb_data_q[1][((DQ_BITS*LANES)*6 + 8*index) +: 8] <= i_phy_iserdes_data[((DQ_BITS*LANES)*6 + 8*index) +: 8]; //update each lane of the burst
o_wb_data_q[1][((DQ_BITS*LANES)*7 + 8*index) +: 8] <= i_phy_iserdes_data[((DQ_BITS*LANES)*7 + 8*index) +: 8]; //update each lane of the burst
end
end
if(o_wb_ack_read_q[0][0]) begin
index_wb_data <= !index_wb_data;
end
for(index = 1; index < MAX_ADDED_READ_ACK_DELAY; index = index + 1) begin
o_wb_ack_read_q[index-1] <= o_wb_ack_read_q[index];
end
o_wb_ack_read_q[MAX_ADDED_READ_ACK_DELAY-1] <= 0;
o_wb_ack_read_q[added_read_pipe_max] <= shift_reg_read_pipe_q[0];
if(o_wb_ack_read_q[0]) begin
index_wb_data <= !index_wb_data;
//abort any outgoing ack when cyc is low
if(!i_wb_cyc && state_calibrate == DONE_CALIBRATE) begin
for(index = 0; index < MAX_ADDED_READ_ACK_DELAY; index = index + 1) begin
o_wb_ack_read_q[index] <= 0;
end
/*
for(index = 0; index < 15; index = index + 1) begin
o_wb_ack_read_q[index] <= o_wb_ack_read_q[index+1];
for(index = 0; index < READ_ACK_PIPE_WIDTH; index = index + 1) begin
shift_reg_read_pipe_q[index] <= 0;
end
*/
o_wb_ack_read_q <= o_wb_ack_read_q >> 1;
o_wb_ack_read_q[added_read_pipe_max] <= shift_reg_read_pipe_q[0];
end
end
end
assign o_wb_ack = o_wb_ack_read_q[0];
assign o_wb_ack = o_wb_ack_read_q[0][0] && state_calibrate == DONE_CALIBRATE;
//o_wb_ack_read_q[0][0] is needed internally for write calibration but it must not go outside (since it is not an actual user wb request unless we are in DONE_CALIBRATE)
assign o_aux = o_wb_ack_read_q[0][AUX_WIDTH:1] && state_calibrate == DONE_CALIBRATE;
assign o_wb_data = o_wb_data_q[index_wb_data];
assign o_phy_dqs_tri_control = !write_dqs[STAGE2_DATA_DEPTH];
assign o_phy_dq_tri_control = !write_dq[STAGE2_DATA_DEPTH+1];
assign o_phy_toggle_dqs = write_dqs_val[STAGE2_DATA_DEPTH-2];
generate
if(STAGE2_DATA_DEPTH - 2 >= 0)
assign o_phy_toggle_dqs = write_dqs_val[STAGE2_DATA_DEPTH-2];
else
assign o_phy_toggle_dqs = write_dqs_d || write_dqs_q[0];
endgenerate
/*********************************************************************************************************************************************/
@ -1019,6 +1159,7 @@ module ddr3_controller #(
write_calib_odt <= 0;
prev_write_level_feedback <= 1;
write_calib_stb <= 0;//actual request flag
write_calib_aux <= 0; //AUX ID
write_calib_we <= 0; //write-enable
write_calib_col <= 0;
write_calib_data <= 0;
@ -1033,14 +1174,15 @@ module ddr3_controller #(
for(index = 0; index < LANES; index = index + 1) begin
added_read_pipe[index] <= 0;
data_start_index[index] <= 0;
odelay_data_cntvaluein[index] = DATA_INITIAL_ODELAY_TAP;
odelay_dqs_cntvaluein[index] = DQS_INITIAL_ODELAY_TAP;
idelay_data_cntvaluein[index] = DATA_INITIAL_IDELAY_TAP;
idelay_dqs_cntvaluein[index] = DQS_INITIAL_IDELAY_TAP;
odelay_data_cntvaluein[index] <= DATA_INITIAL_ODELAY_TAP;
odelay_dqs_cntvaluein[index] <= DQS_INITIAL_ODELAY_TAP;
idelay_data_cntvaluein[index] <= DATA_INITIAL_IDELAY_TAP;
idelay_dqs_cntvaluein[index] <= DQS_INITIAL_IDELAY_TAP;
end
end
else begin
write_calib_stb <= 0;//actual request flag
write_calib_aux <= 0; //AUX ID
write_calib_we <= 0; //write-enable
write_calib_col <= 0;
write_calib_data <= 0;
@ -1199,6 +1341,7 @@ module ddr3_controller #(
end
ISSUE_WRITE_1: if(instruction_address == 22) begin
write_calib_stb <= 1;//actual request flag
write_calib_aux <= 1; //AUX ID to determine later if ACK is for read or write
write_calib_we <= 1; //write-enable
write_calib_col <= 0;
write_calib_data <= { {LANES{8'h91}}, {LANES{8'h77}}, {LANES{8'h29}}, {LANES{8'h8c}}, {LANES{8'hd0}}, {LANES{8'had}}, {LANES{8'h51}}, {LANES{8'hc1}} };
@ -1206,6 +1349,7 @@ module ddr3_controller #(
end
ISSUE_WRITE_2: begin
write_calib_stb <= 1;//actual request flag
write_calib_aux <= 1; //AUX ID to determine later if ACK is for read or write
write_calib_we <= 1; //write-enable
write_calib_col <= 8;
write_calib_data <= { {LANES{8'h80}}, {LANES{8'hdb}}, {LANES{8'hcf}}, {LANES{8'hd2}}, {LANES{8'h75}}, {LANES{8'hf1}}, {LANES{8'h2c}}, {LANES{8'h3d}} };
@ -1214,11 +1358,12 @@ module ddr3_controller #(
ISSUE_READ: if(!o_wb_stall_d) begin
write_calib_stb <= 1;//actual request flag
write_calib_aux <= 0; //AUX ID to determine later if ACK is for read or write
write_calib_we <= 0; //write-enable
state_calibrate <= READ_DATA;
end
READ_DATA: if(o_wb_ack_read_q[0]) begin
READ_DATA: if(o_wb_ack_read_q[0] == {{(AUX_WIDTH){1'b0}}, 1'b1}) begin //wait for the read ack (which has UAX ID of 0}
read_data_store <= o_wb_data;
state_calibrate <= ANALYZE_DATA;
data_start_index[lane] <= 0;
@ -1447,11 +1592,41 @@ module ddr3_controller #(
$display("WRITE_TO_READ_DELAY = 4 = %0d", WRITE_TO_READ_DELAY);
$display("WRITE_TO_PRECHARGE_DELAY = 5 = %0d", WRITE_TO_PRECHARGE_DELAY);
$display("STAGE2_DATA_DEPTH = 2 = %0d", STAGE2_DATA_DEPTH);
$display("READ_ACK_PIPE_WIDTH = %0d", READ_ACK_PIPE_WIDTH);
end
`endif
`ifdef FORMAL
// wires and registers used in this formal section
localparam F_TEST_CMD_DATA_WIDTH = $bits(i_wb_data) + $bits(i_wb_sel) + $bits(i_aux) + $bits(i_wb_addr) + $bits(i_wb_we);
reg f_past_valid = 0;
reg[$bits(instruction_address) - 1: 0] f_addr = 0, f_read = 0 ;
reg[$bits(instruction) - 1:0] f_read_inst = INITIAL_RESET_INSTRUCTION;
reg[3:0] f_count_refreshes = 0; //count how many refresh cycles had already passed
reg[24:0] f_wb_inputs[31:0];
reg[4:0] f_index = 0;
reg[5:0] f_counter = 0;
reg[9:0] f_reset_counter = 0;
reg[4:0] f_index_1 = 0;
reg[F_TEST_CMD_DATA_WIDTH - 1:0] f_write_data;
reg f_write_fifo = 0, f_read_fifo = 0;
wire f_empty, f_full;
wire[F_TEST_CMD_DATA_WIDTH - 1:0] f_read_data;
reg[AUX_WIDTH - 1:0] f_write_data_2;
reg f_write_fifo_2 = 0, f_read_fifo_2 = 0;
wire f_empty_2, f_full_2;
wire[AUX_WIDTH - 1:0] f_read_data_2;
wire[$bits(instruction) - 1:0] a= read_rom_instruction(f_const_addr); //retrieve an instruction based on engine's choice
wire[1:0] f_write_slot;
wire[1:0] f_read_slot;
wire[1:0] f_precharge_slot;
wire[1:0] f_activate_slot;
(*anyconst*) reg[$bits(instruction_address) - 1: 0] f_const_addr;
initial assume(!i_rst_n);
always @* begin
@ -1463,19 +1638,17 @@ module ddr3_controller #(
assert(MR3_MPR_EN[18] != 1'b1);
assert(MR3_MPR_DIS[18] != 1'b1);
assert(DELAY_COUNTER_WIDTH <= $bits(MR0)); //bitwidth of mode register should be enough for the delay counter
assert(($bits(instruction) - $bits(CMD_MRS) - $bits(MR0)) == 5 ); //sanity checking to ensure 5 bits is allotted for extra instruction {reset_finished, use_timer , stay_command , cke , reset_n }
//sanity checking to ensure 5 bits is allotted for extra instruction {reset_finished, use_timer , stay_command , cke , reset_n }
assert(($bits(instruction) - $bits(CMD_MRS) - $bits(MR0)) == 5 );
assert(DELAY_SLOT_WIDTH >= DELAY_COUNTER_WIDTH); //width occupied by delay timer slot on the reset rom must be able to occupy the maximum possible delay value on the reset sequence
end
reg f_past_valid = 0;
always @(posedge i_controller_clk) f_past_valid <= 1;
//The idea below is sourced from https://zipcpu.com/formal/2019/11/18/genuctrlr.html
//We will form a packet of information describing each instruction as it goes through the pipeline and make assertions along the way.
//2-stage Pipeline: f_addr (update address) -> f_read (read instruction from rom)
reg[$bits(instruction_address) - 1: 0] f_addr = 0, f_read = 0 ;
reg[$bits(instruction) - 1:0] f_read_inst = INITIAL_RESET_INSTRUCTION;
//pipeline stage logic: f_addr (update address) -> f_read (read instruction from rom)
always @(posedge i_controller_clk, negedge i_rst_n) begin
@ -1483,7 +1656,8 @@ module ddr3_controller #(
f_addr <= 0;
f_read <= 0;
end
else if((delay_counter == 1 || !instruction[USE_TIMER] || skip_reset_seq_delay) /*&& !reset_done*/ )begin //move the pipeline forward when counter is about to go zero and we are not yet at end of reset sequence
//move the pipeline forward when counter is about to go zero and we are not yet at end of reset sequence
else if((delay_counter == 1 || !instruction[USE_TIMER] || skip_reset_seq_delay) /*&& !reset_done*/ )begin
f_addr <= (f_addr == 22)? 19:f_addr + 1;
f_read <= f_addr;
end
@ -1581,8 +1755,6 @@ module ddr3_controller #(
// assertions on the instructions stored on the rom
(*anyconst*) reg[$bits(instruction_address) - 1: 0] f_const_addr;
wire[$bits(instruction) - 1:0] a= read_rom_instruction(f_const_addr); //retrieve an instruction based on engine's choice
always @* begin
//there MUST BE no instruction which USE_TIMER is high but delay is zero since it can cause the logic to lock-up (delay must be at least 1)
if(a[USE_TIMER]) begin
@ -1624,13 +1796,13 @@ module ddr3_controller #(
end
//cover statements
`ifdef FORMAL_COVER
reg[3:0] f_count_refreshes = 0; //count how many refresh cycles had already passed
always @(posedge i_controller_clk) begin
if($past(f_read) == 15 && f_read == 12) f_count_refreshes = f_count_refreshes + 1; //every time address wrap around refresh is completed
end
always @(posedge i_controller_clk) begin
cover(f_count_refreshes == 5);
//cover($past(instruction[RST_DONE]) && !instruction[RST_DONE] && i_rst_n); //MUST FAIL: find an instance where RST_DONE will go low after it already goes high (except when i_rst_n is activated)
//MUST FAIL: find an instance where RST_DONE will go low after it already goes high (except when i_rst_n is activated)
//cover($past(instruction[RST_DONE]) && !instruction[RST_DONE] && i_rst_n);
end
`endif
@ -1647,10 +1819,6 @@ module ddr3_controller #(
//make an assertion that there will be no request pending before actual refresh starts at instruction 4'd12
reg[24:0] f_wb_inputs[31:0];
reg[4:0] f_index = 0;
reg[5:0] f_counter = 0;
reg[9:0] f_reset_counter = 0;
initial begin
/*
f_wb_inputs[0] = {1'b0, {14'd0,3'd1, 7'd0}}; //read
@ -1731,46 +1899,60 @@ module ddr3_controller #(
//cover(f_reset_counter == 10);
end
*/
//mini-FiFO
//error: AFTER PRECHARGE, cna already write since active row is lready
//eqaual
localparam f_fifo_width = 1;
(*keep*) reg[$bits(i_wb_addr) + $bits(i_wb_we) - 1:0] f_fifo_reg[2**f_fifo_width-1:0];
reg[f_fifo_width-1:0] f_write_pointer=0, f_read_pointer=0;
reg[4:0] f_index_1 = 0;
reg[$bits(i_wb_addr) + $bits(i_wb_we) - 1:0] f_write_data;
wire[24:0] f_read_data;
reg f_write_fifo = 0, f_read_fifo = 0;
reg f_empty = 1, f_full = 0;
always @(posedge i_controller_clk, negedge i_rst_n) begin
if(!i_rst_n) begin
f_empty <= 1;
f_full <=0;
f_read_pointer <= 0;
f_write_pointer <= 0;
end
mini_fifo #(
.FIFO_WIDTH(1), //the fifo will have 2**FIFO_WIDTH positions
.DATA_WIDTH(F_TEST_CMD_DATA_WIDTH) //each FIFO position can store DATA_WIDTH bits
) fifo_1 (
.i_clk(i_controller_clk),
.i_rst_n(i_rst_n && i_wb_cyc),
.read_fifo(f_read_fifo),
.write_fifo(f_write_fifo),
.empty(f_empty),
.full(f_full),
.write_data(f_write_data),
.read_data(f_read_data)
);
/*
mini_fifo #(
.FIFO_WIDTH($clog2(READ_ACK_PIPE_WIDTH+5)), //the fifo will have 2**FIFO_WIDTH positions
.DATA_WIDTH(AUX_WIDTH) //each FIFO position can store DATA_WIDTH bits
) fifo_2 (
.i_clk(i_controller_clk),
.i_rst_n(i_rst_n),
.read_fifo(f_read_fifo_2),
.write_fifo(f_write_fifo_2),
.empty(f_empty_2),
.full(f_full_2),
.write_data(f_write_data_2),
.read_data(f_read_data_2)
);
always @* begin
//write the wb request to fifo
if(i_wb_stb && i_wb_cyc && !o_wb_stall && state_calibrate == DONE_CALIBRATE) begin
f_write_fifo_2 = 1;
f_write_data_2 = i_aux;
end
else begin
if(f_read_fifo) begin
assert(!f_empty);
if(!f_write_fifo) f_full <= 0;
//advance read pointer
f_read_pointer <= f_read_pointer + 1;
if(f_read_pointer + 1'b1 == f_write_pointer && !f_write_fifo) f_empty <= 1;
end
if(f_write_fifo) begin
if(!f_read_fifo) assert(!f_full);
if(!f_read_fifo) f_empty <= 0;
//write to FiFo
f_fifo_reg[f_write_pointer] <= f_write_data;
//advance read pointer
f_write_pointer <= f_write_pointer + 1;
if(f_write_pointer + 1'b1 == f_read_pointer && !f_read_fifo) f_full <= 1'b1; //fifo should never be full
end
f_write_fifo_2 = 0;
end
f_read_fifo_2 = 0;
//check if an ack is received
if(o_wb_ack && i_wb_cyc) begin //
assert(f_read_data_2 == o_aux); //the AUX ID must match the corresponding request AUX ID
assert(!f_empty_2);
f_read_fifo_2 = 1;
assert(state_calibrate == DONE_CALIBRATE); //o_wb_ack must only go high after done calibration
end
if(state_calibrate != DONE_CALIBRATE) assert(f_empty_2); //if not yet finished calibrating, stall should never go low
if(!f_empty_2) assert(state_calibrate == DONE_CALIBRATE);
end
assign f_read_data = f_fifo_reg[f_read_pointer];
//mini-FiFo assertions
*/
always @* begin
if(state_calibrate == DONE_CALIBRATE) begin
if(f_full) assert(stage1_pending && stage2_pending);//there are 2 contents
@ -1781,11 +1963,8 @@ module ddr3_controller #(
if(f_empty) assert(stage1_pending == 0 && stage2_pending==0); //there is 0 content
if(stage1_pending == 0 && stage2_pending == 0) assert(f_empty);
end
if(f_empty || f_full) assert(f_write_pointer == f_read_pointer);
if(f_write_pointer == f_read_pointer) assert(f_empty || f_full);
assert(!(f_empty && f_full));
if(state_calibrate < ISSUE_WRITE_1) assert(!stage1_pending && !stage2_pending);
if(stage1_pending && state_calibrate == ISSUE_READ) assert(stage1_we);
@ -1825,25 +2004,39 @@ module ddr3_controller #(
//write the wb request to fifo
if(i_wb_stb && i_wb_cyc && !o_wb_stall && state_calibrate == DONE_CALIBRATE) begin
f_write_fifo = 1;
f_write_data = {i_wb_addr,i_wb_we};
f_write_data = {i_wb_data, i_wb_sel, i_aux, i_wb_addr,i_wb_we};
end
else f_write_fifo = 0;
f_read_fifo = 0;
//check if a DDR3 command is issued
for(f_index_1 = 0; f_index_1 < 4; f_index_1 = f_index_1 + 1) begin
if(!cmd_d[f_index_1][CMD_CS_N] && state_calibrate == DONE_CALIBRATE) begin //only if already done calibrate and controller can accept wb request
if(!cmd_d[f_index_1][CMD_CS_N]) begin //only if already done calibrate and controller can accept wb request
case(cmd_d[f_index_1][CMD_CS_N:CMD_WE_N])
4'b0100: begin //WRITE
assert(cmd_d[f_index_1][CMD_BANK_START:CMD_ADDRESS_START+1] == f_read_data[(COL_BITS - $clog2(serdes_ratio*2)) + 1 +: BA_BITS]); //bank and address must match
assert(cmd_d[f_index_1][CMD_ADDRESS_START:0] == {f_read_data[1 +: COL_BITS - $clog2(serdes_ratio*2)], 3'b000}); //bank and address must match
assert(f_read_data[0]); //i_wb_we must be high
f_read_fifo = 1; //advance read pointer to prepare for next read
if(state_calibrate == DONE_CALIBRATE) begin
assert(cmd_d[f_index_1][CMD_ADDRESS_START:0] == {f_read_data[1 +: COL_BITS - $clog2(serdes_ratio*2)], 3'b000}); //column address must match
assert(cmd_d[f_index_1][CMD_BANK_START:CMD_ADDRESS_START+1] == f_read_data[(COL_BITS - $clog2(serdes_ratio*2)) + 1 +: BA_BITS]); //bank must match
assert(stage2_aux == f_read_data[$bits(i_wb_addr) + 1 +: AUX_WIDTH]); //UAX ID must match
assert(stage2_dm_unaligned == f_read_data[$bits(i_wb_addr) + AUX_WIDTH + 1 +: $bits(i_wb_sel)]); //wb sel must match to data mask
//assert(stage2_data_unaligned == f_read_data[$bits(i_wb_sel) + $bits(i_wb_addr) + AUX_WIDTH + 1 +: $bits(i_wb_data)]); //actual data must match
assert(f_read_data[0]); //i_wb_we must be high
f_read_fifo = 1; //advance read pointer to prepare for next read
end
else if(state_calibrate > ISSUE_WRITE_1) begin
assert(stage2_aux == 1);
end
end
4'b0101: begin //READ
assert(cmd_d[f_index_1][CMD_BANK_START:CMD_ADDRESS_START+1] == f_read_data[(COL_BITS - $clog2(serdes_ratio*2)) + 1 +: BA_BITS]); //bank and address must match
assert(cmd_d[f_index_1][CMD_ADDRESS_START:0] == {f_read_data[1 +: COL_BITS - $clog2(serdes_ratio*2)], 3'b000}); //bank and address must match
assert(!f_read_data[0]); //i_wb_we must be low
f_read_fifo = 1; //advance read pointer to prepare for next read
if(state_calibrate == DONE_CALIBRATE) begin
assert(cmd_d[f_index_1][CMD_BANK_START:CMD_ADDRESS_START+1] == f_read_data[(COL_BITS - $clog2(serdes_ratio*2)) + 1 +: BA_BITS]); //bank and address must match
assert(cmd_d[f_index_1][CMD_ADDRESS_START:0] == {f_read_data[1 +: COL_BITS - $clog2(serdes_ratio*2)], 3'b000}); //bank and address must match
assert(stage2_aux == f_read_data[$bits(i_wb_addr) + 1 +: AUX_WIDTH]); //UAX ID must match
assert(!f_read_data[0]); //i_wb_we must be low
f_read_fifo = 1; //advance read pointer to prepare for next read
end
else if(state_calibrate > ISSUE_WRITE_1) begin
assert(stage2_aux == 0);
end
end
endcase
end
@ -1856,29 +2049,16 @@ module ddr3_controller #(
if(state_calibrate != DONE_CALIBRATE) assert(f_empty); //if not yet finished calibrating, stall should never go low
if(!f_empty) assert(state_calibrate == DONE_CALIBRATE);
end
wire[1:0] f_write_slot;
assign f_write_slot = WRITE_SLOT;
wire[1:0] f_read_slot;
assign f_read_slot = READ_SLOT;
wire[1:0] f_precharge_slot;
assign f_precharge_slot = PRECHARGE_SLOT;
wire[1:0] f_activate_slot;
assign f_activate_slot = ACTIVATE_SLOT;
reg[4:0] f_process_request_counter = 0;
always @(posedge i_controller_clk, negedge i_rst_n) begin
if(!i_rst_n) begin
f_process_request_counter <= 0;
end
else begin
if(!f_empty) begin//there is an ongoing wb request
f_process_request_counter <= f_read_fifo ? 0:f_process_request_counter + 1;//if a new command comes out (then read fifo) then counter will go back to sero
//assert(f_process_request_counter < 8); //a single wb request should not take more than 7 clock cycles
assert(stage1_pending || stage2_pending);
end
else f_process_request_counter <= 0;
if((stage1_pending || stage2_pending) && state_calibrate == DONE_CALIBRATE) assert(!f_empty || f_write_fifo);
always @(posedge i_controller_clk) begin
if(!f_empty) begin//there is an ongoing wb request
assert(stage1_pending || stage2_pending);
end
if((stage1_pending || stage2_pending) && state_calibrate == DONE_CALIBRATE) assert(!f_empty || f_write_fifo);
end
always @(posedge i_controller_clk) begin
if(f_past_valid) begin
@ -1913,12 +2093,177 @@ module ddr3_controller #(
end
if(instruction_address != 22 && instruction_address != 19) assert(!stage1_pending && !stage2_pending); //must be pending except in tREFI and in prestall delay
if(!reset_done) assert(stage1_pending == 0 && stage2_pending == 0);
if(state_calibrate <= ISSUE_READ) assert(o_wb_ack_read_q == 0);
if(state_calibrate <= ISSUE_READ) begin
for(index = 0; index < MAX_ADDED_READ_ACK_DELAY; index = index + 1) begin
assert(o_wb_ack_read_q[index] == 0);
end
for(index = 0; index < READ_ACK_PIPE_WIDTH; index = index + 1) begin
assert(shift_reg_read_pipe_q[index] == 0);
end
end
if(state_calibrate <= ISSUE_WRITE_1) begin
assert(bank_status_q == 0);
end
assert(state_calibrate <= DONE_CALIBRATE);
if(!DONE_CALIBRATE) assert(o_wb_ack == 0); //o_wb_ack must not go high before done calibration
end
wire[4:0] f_nreqs, f_nacks, f_outstanding;
integer f_sum_of_pending_acks = 0;
always @* begin
if(state_calibrate == DONE_CALIBRATE) begin
assume(added_read_pipe_max == 1);
end
f_sum_of_pending_acks = stage1_pending + stage2_pending;
for(index = 0; index < READ_ACK_PIPE_WIDTH; index = index + 1) begin
f_sum_of_pending_acks = f_sum_of_pending_acks + shift_reg_read_pipe_q[index][0] + 0;
end
for(index = 0; index < MAX_ADDED_READ_ACK_DELAY; index = index + 1) begin
f_sum_of_pending_acks = f_sum_of_pending_acks + o_wb_ack_read_q[index][0] + 0;
end
if(i_rst_n && state_calibrate == DONE_CALIBRATE) begin
assert(f_outstanding == f_sum_of_pending_acks);
end
else if(!i_rst_n) begin
assert(f_sum_of_pending_acks == 0);
end
if(state_calibrate != DONE_CALIBRATE && i_rst_n) begin
assert(f_outstanding == 0);
end
if(state_calibrate <= ISSUE_WRITE_1) begin
//not inside tREFI, prestall delay, nor precharge
assert(f_outstanding == 0);
assert(f_sum_of_pending_acks == 0);
end
end
fwb_slave #(
// {{{
.AW(wb_addr_bits),
.DW(wb_data_bits),
.F_MAX_STALL(15),
.F_MAX_ACK_DELAY(15),
.F_LGDEPTH(4),
.F_MAX_REQUESTS(10),
// OPT_BUS_ABORT: If true, the master can drop CYC at any time
// and must drop CYC following any bus error
.OPT_BUS_ABORT(0),
//
// If true, allow the bus to be kept open when there are no
// outstanding requests. This is useful for any master that
// might execute a read modify write cycle, such as an atomic
// add.
.F_OPT_RMW_BUS_OPTION(1),
//
//
// If true, allow the bus to issue multiple discontinuous
// requests.
// Unlike F_OPT_RMW_BUS_OPTION, these requests may be issued
// while other requests are outstanding
.F_OPT_DISCONTINUOUS(1),
//
//
// If true, insist that there be a minimum of a single clock
// delay between request and response. This defaults to off
// since the wishbone specification specifically doesn't
// require this. However, some interfaces do, so we allow it
// as an option here.
.F_OPT_MINCLOCK_DELAY(1),
//
//
//
.F_WB_ERR(0)
// }}}
) wb_properties (
// {{{
.i_clk(i_controller_clk),
.i_reset(!i_rst_n),
.i_check_assert(state_calibrate == DONE_CALIBRATE && instruction_address == 22),
// The Wishbone bus
.i_wb_cyc(i_wb_cyc),
.i_wb_stb(i_wb_stb),
.i_wb_we(i_wb_we),
.i_wb_addr(i_wb_addr),
.i_wb_data(i_wb_data),
.i_wb_sel(i_wb_sel),
//
.i_wb_ack(o_wb_ack),
.i_wb_stall(o_wb_stall),
.i_wb_idata(o_wb_data),
.i_wb_err(),
// Some convenience output parameters
.f_nreqs(f_nreqs),
.f_nacks(f_nacks),
.f_outstanding(f_outstanding)
// }}}
// }}}
);
`endif
endmodule
module mini_fifo #(
parameter FIFO_WIDTH = 1, //the fifo will have 2**FIFO_WIDTH positions
parameter DATA_WIDTH = 8 //each FIFO position can store DATA_WIDTH bits
)(
input wire i_clk, i_rst_n,
input wire read_fifo, write_fifo,
output reg empty, full,
input wire[DATA_WIDTH - 1:0] write_data,
output wire[DATA_WIDTH - 1:0] read_data
);
reg[FIFO_WIDTH-1:0] write_pointer=0, read_pointer=0;
reg[DATA_WIDTH - 1:0] fifo_reg[2**FIFO_WIDTH-1:0];
initial begin
empty = 1;
full = 0;
end
always @(posedge i_clk, negedge i_rst_n) begin
if(!i_rst_n) begin
empty <= 1;
full <=0;
read_pointer <= 0;
write_pointer <= 0;
end
else begin
if(read_fifo) begin
`ifdef FORMAL
assert(!empty);
`endif
if(!write_fifo) full <= 0;
//advance read pointer
read_pointer <= read_pointer + 1;
if(read_pointer + 1'b1 == write_pointer && !write_fifo) empty <= 1;
end
if(write_fifo) begin
`ifdef FORMAL
if(!read_fifo) assert(!full);
`endif
if(!read_fifo) empty <= 0;
//write to FiFo
fifo_reg[write_pointer] <= write_data;
//advance read pointer
write_pointer <= write_pointer + 1;
if(write_pointer + 1'b1 == read_pointer && !read_fifo) full <= 1'b1; //fifo should never be full
end
end
end
assign read_data = fifo_reg[read_pointer];
`ifdef FORMAL
//mini-FiFo assertions
always @* begin
if(empty || full) assert(write_pointer == read_pointer);
if(write_pointer == read_pointer) assert(empty || full);
assert(!(empty && full));
//TASK ADD MORE ASSERTIONS
end
`endif
endmodule