add initial ECC, ECC_ENABLE = 2 working

This commit is contained in:
AngeloJacobo 2024-06-17 16:25:06 +08:00
parent 1f7d4d18a9
commit 7d93717b72
7 changed files with 835 additions and 44 deletions

123
formal/ecc_formal.v Normal file
View File

@ -0,0 +1,123 @@
module ecc_formal;
parameter K = 8,
P0_LSB = 0;
// function to find number of check bits
function integer calculate_m;
input integer k;
integer m;
begin
m=1;
while (2**m < m+k+1) m++;
calculate_m = m;
end
endfunction
// anyseq indicates nets that are controllable by engine
(*anyseq*)wire[K-1:0] d_i; // information input
(*anyseq*) wire[1:0] corrupted; // 0 or 3 = not corrupted bit, 1 = 1 corrupted bit, 2 = 2 corrupted bits
(*anyseq*) wire[$clog2(K+calculate_m(K))-1:0] corrupted_bit1, corrupted_bit2; // which bit will be corrupted
wire[K-1:0] q_o_dec;
wire[K+calculate_m(K):0] q_o_enc;
reg[K+calculate_m(K):0] q_o_enc_corrupted;
wire sb_err_o;
wire db_err_o;
ecc_enc #(
.K(K), //Information bit vector size
.P0_LSB(P0_LSB) //0: p0 is located at MSB
//1: p0 is located at LSB
) ecc_enc_inst (
.d_i(d_i), //information bit vector input
.q_o(q_o_enc), //encoded data word output
.p_o(), //parity vector output
.p0_o() //extended parity bit
);
ecc_dec #(
.K(K), //Information bit vector size
.LATENCY(0), //0: no latency (combinatorial design)
//1: registered outputs
//2: registered inputs+outputs
.P0_LSB(P0_LSB) //0: p0 is located at MSB
//1: p0 is located at LSB
) ecc_dec_inst (
//clock/reset ports (if LATENCY > 0)
.rst_ni(1'b1), //asynchronous reset
.clk_i(1'b0), //clock input
.clkena_i(1'b0), //clock enable input
//data ports
.d_i(q_o_enc_corrupted), //encoded code word input
.q_o(q_o_dec), //information bit vector output
.syndrome_o(), //syndrome vector output
//flags
.sb_err_o(sb_err_o), //single bit error detected
.db_err_o(db_err_o), //double bit error detected
.sb_fix_o() //repaired error in the information bits
);
`ifdef FORMAL
(*gclk*) reg f_clk = 0; // reference: https://symbiyosys.readthedocs.io/en/latest/verilog.html#global-clock
reg[9:0] f_counter = 0;
// corrupt the information based on the value of "corrupted" which is controllable by formal engine:
// 0 = no corrupted bits , 1 = 1 corrupted bit, 2 = 2 corrupted bits, 3 = no corrupted bits
always @* begin
q_o_enc_corrupted = q_o_enc;
if(corrupted == 1) begin
q_o_enc_corrupted[corrupted_bit1] = !q_o_enc_corrupted[corrupted_bit1]; //corrupt 1 random bit
end
else if (corrupted == 2) begin // flip 2 bits
q_o_enc_corrupted[corrupted_bit1] = !q_o_enc_corrupted[corrupted_bit1]; //corrupt 2 random bits
q_o_enc_corrupted[corrupted_bit2] = !q_o_enc_corrupted[corrupted_bit2];
end
assume(corrupted_bit1 != corrupted_bit2); // corrupted bit should be different (in case of 2 corrupted bits)
assume(corrupted_bit1 <= (K+calculate_m(K))); // corrupted bit should be within the index of q_o_enc_corrupted
assume(corrupted_bit2 <= (K+calculate_m(K))); // corrupted bit should be within the index of q_o_enc_corrupted
end
// main contract of this design
always @* begin
// if no corrupted bits, then decoded info must be equal to original info, and error flags should be low
if(corrupted == 0 || corrupted == 3) begin
assert(d_i == q_o_dec);
assert(!sb_err_o);
assert(!db_err_o);
end
// if 1 corrupted bit, then decoded info must still be equal to original info, single-bit error flag must be high, double-bit error flag must be low
else if(corrupted == 1) begin
assert(d_i == q_o_dec);
assert(sb_err_o);
assert(!db_err_o);
end
// if 2 corrupted bits, then single-bit error flag must be low, double-bit error flag must be high
else if(corrupted == 2) begin
assert(!sb_err_o);
assert(db_err_o);
end
end
// cover 10 cycles
always @(posedge f_clk) begin
f_counter <= f_counter + 1;
assume(corrupted == f_counter[1:0]); // number of corrupted bits change per clock cycle
cover((f_counter == 10));
end
// simulate random information
always @(posedge f_clk) begin
assume(d_i != $past(d_i,1));
assume(d_i != $past(d_i,2));
assume(d_i != $past(d_i,3));
assume(d_i != $past(d_i,4));
assume(d_i != $past(d_i,5));
assume(d_i != $past(d_i,6));
assume(d_i != $past(d_i,7));
assume(d_i != $past(d_i,8));
assume(d_i != $past(d_i,9));
assume(d_i != $past(d_i,10));
end
`endif
endmodule

View File

@ -66,6 +66,7 @@ module ddr3_controller #(
parameter[0:0] MICRON_SIM = 0, //enable faster simulation for micron ddr3 model (shorten POWER_ON_RESET_HIGH and INITIAL_CKE_LOW)
ODELAY_SUPPORTED = 1, //set to 1 when ODELAYE2 is supported
SECOND_WISHBONE = 0, //set to 1 if 2nd wishbone is needed
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 )
parameter[1:0] DIC = 2'b00, //Output Driver Impedance Control (2'b00 = RZQ/6, 2'b01 = RZQ/7, RZQ = 240ohms)
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
@ -299,8 +300,10 @@ module ddr3_controller #(
//and the IDELAY and ISERDES when receiving the data (NOTE TO SELF: ELABORATE ON WHY THOSE MAGIC NUMBERS)
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 + ps_to_cycles(tWLO+tWLOE) + 10; //plus 10 controller clocks for possible bus latency and
//the delay for receiving feedback DQ from IOBUF -> IDELAY -> ISERDES
localparam DELAY_BEFORE_WRITE_LEVEL_FEEDBACK = STAGE2_DATA_DEPTH + ps_to_cycles(tWLO+tWLOE) + 10;
//plus 10 controller clocks for possible bus latency and the delay for receiving feedback DQ from IOBUF -> IDELAY -> ISERDES
localparam ECC_INFORMATION_BITS = max_information_bits(wb_data_bits);
/*********************************************************************************************************************************************/
@ -402,6 +405,7 @@ module ddr3_controller #(
reg[AUX_WIDTH-1:0] stage1_aux = 0;
reg stage1_we = 0;
reg[wb_data_bits - 1:0] stage1_data = 0;
wire[wb_data_bits - 1:0] stage1_data_processed, stage1_data_encoded;
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;
@ -479,6 +483,11 @@ module ddr3_controller #(
reg 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 (since different lanes might not be aligned with each other and needs to be retrieved at a different time)
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[wb_data_bits - 1:0] o_wb_data_q_q;
reg o_wb_ack_q;
reg[AUX_WIDTH-1:0] o_aux_q;
reg o_wb_ack_q_uncalibrated;
wire[wb_data_bits - 1:0] o_wb_data_q_decoded;
reg[AUX_WIDTH:0] o_wb_ack_read_q[MAX_ADDED_READ_ACK_DELAY-1:0];
(* mark_debug = "true" *) reg calib_stb = 0;
reg[wb_sel_bits-1:0] calib_sel = 0;
@ -504,6 +513,7 @@ module ddr3_controller #(
(* mark_debug = "true" *) reg[63:0] read_lane_data = 0;
(* mark_debug = "true" *) reg odelay_cntvalue_halfway = 0;
reg already_finished_calibration = 0;
reg initial_calibration_done = 0;
// Wishbone 2
reg wb2_stb = 0;
reg wb2_update = 0;
@ -527,7 +537,8 @@ module ddr3_controller #(
reg[wb_addr_bits-1:0] read_test_address_counter = 0, check_test_address_counter = 0; ////////////////////////////////////////////////////////
reg[31:0] write_test_address_counter = 0;
reg[31:0] correct_read_data = 0, wrong_read_data = 0;
wire sb_err_o;
wire db_err_o;
// initial block for all regs
initial begin
@ -838,11 +849,11 @@ module ddr3_controller #(
stage2_bank <= stage1_bank;
stage2_row <= stage1_row;
if(ODELAY_SUPPORTED) begin
stage2_data_unaligned <= stage1_data;
stage2_data_unaligned <= stage1_data_processed;
stage2_dm_unaligned <= ~stage1_dm; //inverse each bit (1 must mean "masked" or not written)
end
else begin
stage2_data_unaligned_temp <= stage1_data;
stage2_data_unaligned_temp <= stage1_data_processed;
stage2_dm_unaligned_temp <= ~stage1_dm; //inverse each bit (1 must mean "masked" or not written)
end
//stage2_data -> shiftreg(CWL) -> OSERDES(DDR) -> ODELAY -> RAM
@ -962,6 +973,8 @@ module ddr3_controller #(
end
end
assign o_phy_data = stage2_data[STAGE2_DATA_DEPTH-1]; // the data sent to PHY is the last stage of of stage 2 (since stage 2 can have multiple pipelined stages inside it_
//assign o_phy_data = initial_calibration_done? {stage2_data[STAGE2_DATA_DEPTH-1][wb_data_bits - 1:1], 1'b0} : stage2_data[STAGE2_DATA_DEPTH-1]; // ECC test
assign o_phy_dm = stage2_dm[STAGE2_DATA_DEPTH-1];
/* verilator lint_off WIDTH */
assign wb_addr_plus_anticipate = i_wb_addr + MARGIN_BEFORE_ANTICIPATE; // wb_addr_plus_anticipate determines if it is near the end of column by checking if it jumps to next row
@ -1405,13 +1418,32 @@ module ddr3_controller #(
shift_reg_read_pipe_q[index] <= 0;
end
end
if(ECC_ENABLE == 1 || ECC_ENABLE == 2) begin // added latency of 1 clock cycle for decoding the ECC
o_wb_data_q_q <= o_wb_data_q_decoded;
o_wb_ack_q <= o_wb_ack_read_q[0][0] && state_calibrate == DONE_CALIBRATE;
o_wb_ack_q_uncalibrated <= o_wb_ack_read_q[0][0];
o_aux_q <= o_wb_ack_read_q[0][AUX_WIDTH:1];
end
end
end
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 to ack during 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];
assign o_wb_data = o_wb_data_q[index_wb_data];
generate
if(ECC_ENABLE == 0) begin: ecc_disabled_wishbone_out
assign o_wb_data_q_decoded = o_wb_data_q[index_wb_data];
always @* begin
o_wb_data_q_q = o_wb_data_q_decoded;
o_wb_ack_q = o_wb_ack_read_q[0][0] && state_calibrate == DONE_CALIBRATE;
o_wb_ack_q_uncalibrated = o_wb_ack_read_q[0][0];
o_aux_q = o_wb_ack_read_q[0][AUX_WIDTH:1];
end
end
endgenerate
// WIshbone Outputs
assign o_wb_data = o_wb_data_q_q;
assign o_wb_ack = o_wb_ack_q;
assign o_aux = o_aux_q;
// DQ/DQS IO tristate control logic
always @(posedge i_controller_clk) begin
o_phy_dqs_tri_control <= !write_dqs[STAGE2_DATA_DEPTH-1];
@ -1478,6 +1510,7 @@ module ddr3_controller #(
reset_from_calibrate <= 0;
write_by_byte_counter <= 0;
already_finished_calibration <= 0;
initial_calibration_done <= 1'b0;
for(index = 0; index < LANES; index = index + 1) begin
added_read_pipe[index] <= 0;
data_start_index[index] <= 0;
@ -1554,6 +1587,7 @@ module ddr3_controller #(
write_calib_dqs <= 0;
write_calib_odt <= 0;
o_phy_write_leveling_calib <= 0;
initial_calibration_done <= 1'b0;
end
else if(instruction_address == 13) begin
pause_counter <= 1; //pause instruction address @13 until read calibration finishes
@ -1801,7 +1835,7 @@ module ddr3_controller #(
// end
READ_DATA: if(o_wb_ack_read_q[0] == {{(AUX_WIDTH-2){1'b0}}, 2'd1, 1'b1}) begin //wait for the read ack (which has AUX ID of 1}
read_data_store <= o_wb_data; // read data on address 0
read_data_store <= o_wb_data_q[index_wb_data]; // read data on address 0
calib_stb <= 0;
state_calibrate <= ANALYZE_DATA;
data_start_index[lane] <= 0;
@ -1828,6 +1862,7 @@ module ddr3_controller #(
if(lane == LANES - 1) begin
/* verilator lint_on WIDTH */
state_calibrate <= BURST_WRITE;
initial_calibration_done <= 1'b1;
end
else begin
lane <= lane + 1;
@ -1905,11 +1940,11 @@ BITSLIP_DQS_TRAIN_3: if(train_delay == 0) begin //train again the ISERDES to cap
BURST_WRITE: if(!o_wb_stall_calib) begin // Test 1: Burst write (per byte write to test datamask feature), then burst read
calib_stb <= 1;
calib_aux <= 2;
if(TDQS == 0) begin //Test datamask by writing 1 byte at a time
if(TDQS == 0 && ECC_ENABLE == 0) begin //Test datamask by writing 1 byte at a time
calib_sel <= 1 << write_by_byte_counter;
calib_we <= 1;
calib_addr <= write_test_address_counter[wb_addr_bits-1:0];
calib_data<= {wb_sel_bits{8'haa}};
calib_data <= {wb_sel_bits{8'haa}};
calib_data[8*write_by_byte_counter +: 8] <= write_test_address_counter[7:0];
if(MICRON_SIM) begin
@ -1941,7 +1976,7 @@ BITSLIP_DQS_TRAIN_3: if(train_delay == 0) begin //train again the ISERDES to cap
calib_sel <= {wb_sel_bits{1'b1}};
calib_we <= 1;
calib_addr <= write_test_address_counter[wb_addr_bits-1:0];
calib_data<= {wb_sel_bits{write_test_address_counter[7:0]}};
calib_data <= {wb_sel_bits{write_test_address_counter[7:0]}};
if(MICRON_SIM) begin
//if(write_test_address_counter[wb_addr_bits-1:0] == 500) begin //inject error at middle
@ -2101,14 +2136,25 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
assign o_phy_idelay_dqs_cntvaluein = idelay_dqs_cntvaluein[lane];
assign dqs_target_index_value = dqs_start_index_stored[0]? dqs_start_index_stored + 2: dqs_start_index_stored + 1; // move to next odd (if 3 then 5, if 4 then 5)
// To show why next odd number is needed: https://github.com/AngeloJacobo/UberDDR3/tree/b762c464f6526159c1d8c2e4ee039b4ae4e78dbd#per-lane-read-calibration
reg[31:0] wb_data_to_wb2 = 0;
always @(posedge i_controller_clk) begin
if(o_wb_ack_read_q[0][0]) wb_data_to_wb2 <= o_wb_data[31:0]; //save data read
end
/*********************************************************************************************************************************************/
/******************************************************* Calibration Test Receiver *******************************************************/
reg[wb_data_bits-1:0] wrong_data = 0;
wire[wb_data_bits-1:0] correct_data;
generate
if(ECC_ENABLE == 0) begin : ecc_enable_0_correct_data
assign correct_data = {wb_sel_bits{check_test_address_counter[7:0]}};
end
if(ECC_ENABLE == 1 || ECC_ENABLE == 2) begin : ecc_enable_1_2_correct_data
wire[wb_data_bits-1:0] correct_data_orig;
assign correct_data_orig = {wb_sel_bits{check_test_address_counter[7:0]}};
assign correct_data = {{(wb_data_bits-ECC_INFORMATION_BITS){1'b0}} , correct_data_orig[ECC_INFORMATION_BITS - 1 : 0]}; //only ECC_INFORMATION_BITS are valid in o_wb_data
end
endgenerate
always @(posedge i_controller_clk) begin
if(sync_rst_controller) begin
check_test_address_counter <= 0;
@ -2118,9 +2164,9 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
end
else begin
reset_from_test <= 0;
if(state_calibrate != DONE_CALIBRATE) begin
if(o_wb_ack_read_q[0] == {{(AUX_WIDTH-3){1'b0}}, 3'd3, 1'b1}) begin //read ack received
if(o_wb_data == {wb_sel_bits{check_test_address_counter[7:0]}}) begin
if(state_calibrate != DONE_CALIBRATE) begin
if ( (o_aux == {{(AUX_WIDTH-3){1'b0}}, 3'd3} || o_aux == {{(AUX_WIDTH-3){1'b0}}, 3'd5}) && o_wb_ack_q_uncalibrated ) begin
if(o_wb_data == correct_data) begin
correct_read_data <= correct_read_data + 1;
end
else begin
@ -2128,18 +2174,9 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
wrong_data <= o_wb_data;
reset_from_test <= !already_finished_calibration; //reset controller when a wrong data is received (only when calibration is not yet done)
end
check_test_address_counter <= check_test_address_counter + 1;
end
else if(o_wb_ack_read_q[0] == {{(AUX_WIDTH-3){1'b0}}, 3'd5, 1'b1}) begin //read ack received (alternate write read)
if(o_wb_data == {wb_sel_bits{check_test_address_counter[7:0]}}) begin
correct_read_data <= correct_read_data + 1;
end
else begin
wrong_read_data <= wrong_read_data + 1;
wrong_data <= o_wb_data;
reset_from_test <= !already_finished_calibration; //reset controller when a wrong data is received (only when calibration is not yet done)
end
check_test_address_counter <= check_test_address_counter + 2;
/* verilator lint_off WIDTHEXPAND */
check_test_address_counter <= check_test_address_counter + 1 + (o_aux == {{(AUX_WIDTH-3){1'b0}}, 3'd5}); // alternate write read when aux == 5
/* verilator lint_on WIDTHEXPAND */
end
end
if(repeat_test) begin
@ -2510,6 +2547,70 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
find_delay = k[3:0];
end
endfunction
// find maximum information bit the data width can accomadate
// Reference: https://docs.amd.com/v/u/en-US/xapp383
// Relevant equations: N <= 2^(K-1) - K , total_bits = N + K ---> total_bits <= 2^(total_bits - N - 1)
// N = information bits , K = parity bits , total_bits = total data width (information bit plus parity bits)
function integer max_information_bits;
input integer total_bits;
integer N;
begin
N = total_bits;
while (total_bits > 2**(total_bits-N-1)) N = N - 1;
max_information_bits = N;
end
endfunction
/*********************************************************************************************************************************************/
/******************************************************* Module Instantiations *******************************************************/
generate
if(ECC_ENABLE == 0) begin : no_ecc
assign stage1_data_encoded = stage1_data;
assign stage1_data_processed = stage1_data_encoded;
end
else if (ECC_ENABLE == 2) begin : sideband_ECC_per_8_bursts
/* verilator lint_off PINCONNECTEMPTY */
ecc_enc #(
.K(ECC_INFORMATION_BITS), //Information bit vector size
.P0_LSB(0) //0: p0 is located at MSB
//1: p0 is located at LSB
) ecc_enc_inst (
.d_i(stage1_data[ECC_INFORMATION_BITS-1:0]), //information bit vector input
.q_o(stage1_data_encoded), //encoded data word output
.p_o(), //parity vector output
.p0_o() //extended parity bit
);
// if initial calibration is not yet done, then data will not be encoded with ECC
assign stage1_data_processed = initial_calibration_done? stage1_data_encoded : stage1_data;
ecc_dec #(
.K(ECC_INFORMATION_BITS), //Information bit vector size
.LATENCY(0), //0: no latency (combinatorial design)
//1: registered outputs
//2: registered inputs+outputs
.P0_LSB(0) //0: p0 is located at MSB
//1: p0 is located at LSB
) ecc_dec_inst (
//clock/reset ports (if LATENCY > 0)
.rst_ni(1'b1), //asynchronous reset
.clk_i(1'b0), //clock input
.clkena_i(1'b0), //clock enable input
//data ports
.d_i(o_wb_data_q[index_wb_data]), //encoded code word input
.q_o(o_wb_data_q_decoded[ECC_INFORMATION_BITS-1:0]), //information bit vector output
.syndrome_o(), //syndrome vector output
//flags
.sb_err_o(sb_err_o), //single bit error detected
.db_err_o(db_err_o), //double bit error detected
.sb_fix_o() //repaired error in the information bits
);
/* verilator lint_on PINCONNECTEMPTY */
assign o_wb_data_q_decoded[wb_data_bits - 1 : ECC_INFORMATION_BITS] = 0;
end
endgenerate
/*********************************************************************************************************************************************/
@ -2530,6 +2631,8 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
$display("SECOND_WISHBONE = %0d", SECOND_WISHBONE);
$display("WB2_ADDR_BITS = %0d", WB2_ADDR_BITS);
$display("WB2_DATA_BITS = %0d", WB2_DATA_BITS);
$display("ECC_ENABLE = %0d", ECC_ENABLE);
$display("ECC_INFORMATION_BITS = %0d", ECC_INFORMATION_BITS);
$display("\nCONTROLLER LOCALPARAMS:\n-----------------------------");
$display("wb_addr_bits = %0d", wb_addr_bits);
@ -2560,6 +2663,7 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
$display("WRITE_TO_PRECHARGE_DELAY = %0d", WRITE_TO_PRECHARGE_DELAY);
$display("STAGE2_DATA_DEPTH = %0d", STAGE2_DATA_DEPTH);
$display("READ_ACK_PIPE_WIDTH = %0d\n", READ_ACK_PIPE_WIDTH);
end
`endif

View File

@ -43,6 +43,7 @@ module ddr3_top #(
parameter[0:0] MICRON_SIM = 0, //enable faster simulation for micron ddr3 model (shorten POWER_ON_RESET_HIGH and INITIAL_CKE_LOW)
ODELAY_SUPPORTED = 0, //set to 1 when ODELAYE2 is supported
SECOND_WISHBONE = 0, //set to 1 if 2nd wishbone for debugging is needed
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 )
parameter[1:0] DIC = 2'b00, //Output Driver Impedance Control (2'b00 = RZQ/6, 2'b01 = RZQ/7, RZQ = 240ohms)
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
@ -219,6 +220,7 @@ ddr3_top #(
.MICRON_SIM(MICRON_SIM), //simulation for micron ddr3 model (shorten POWER_ON_RESET_HIGH and INITIAL_CKE_LOW)
.ODELAY_SUPPORTED(ODELAY_SUPPORTED), //set to 1 when ODELAYE2 is supported
.SECOND_WISHBONE(SECOND_WISHBONE), //set to 1 if 2nd wishbone is needed
.ECC_ENABLE(ECC_ENABLE), // set to 1 or 2 to add ECC (1 = Side-band ECC per burst, 2 = Side-band ECC per 8 bursts , 3 = Inline ECC )
.DIC(DIC), //Output Driver Impedance Control (2'b00 = RZQ/6, 2'b01 = RZQ/7, RZQ = 240ohms)
.RTT_NOM(RTT_NOM) //RTT Nominal (3'b000 = disabled, 3'b001 = RZQ/4, 3'b010 = RZQ/2 , 3'b011 = RZQ/6, RZQ = 240ohms)
) ddr3_controller_inst (

312
rtl/ecc/ecc_dec.sv Normal file
View File

@ -0,0 +1,312 @@
/////////////////////////////////////////////////////////////////////
// ,------. ,--. ,--. //
// | .--. ' ,---. ,--,--. | | ,---. ,---. `--' ,---. //
// | '--'.'| .-. |' ,-. | | | | .-. | .-. |,--.| .--' //
// | |\ \ ' '-' '\ '-' | | '--.' '-' ' '-' || |\ `--. //
// `--' '--' `---' `--`--' `-----' `---' `- /`--' `---' //
// `---' //
// Error Correction and Detection Decoder //
// Parameterized Extended Hamming Code Decoder //
// //
/////////////////////////////////////////////////////////////////////
// //
// Copyright (C) 2017 ROA Logic BV //
// www.roalogic.com //
// //
// This source file may be used and distributed without //
// restriction provided that this copyright statement is not //
// removed from the file and that any derivative work contains //
// the original copyright notice and the associated disclaimer. //
// //
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //
// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR OR //
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, //
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT //
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; //
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) //
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN //
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR //
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS //
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //
// //
/////////////////////////////////////////////////////////////////////
// +FHDR - Semiconductor Reuse Standard File Header Section -------
// FILE NAME : ecc_dec.sv
// DEPARTMENT :
// AUTHOR : rherveille
// AUTHOR'S EMAIL :
// ------------------------------------------------------------------
// RELEASE HISTORY
// VERSION DATE AUTHOR DESCRIPTION
// 1.0 2017-04-07 rherveille initial release
// ------------------------------------------------------------------
// KEYWORDS : HAMMING ERROR CORRECTION DECODER
// ------------------------------------------------------------------
// PURPOSE : Decodes Data and ECC bits from incoming data
// Detects and corrects bit errors
// ------------------------------------------------------------------
// PARAMETERS
// PARAM NAME RANGE DESCRIPTION DEFAULT UNITS
// K 1+ Information vector size 8
// LATENCY 0,1,2 0: No latency 0
// 1: Registered outputs
// 2: Registered inputs/outputs
// P0_LSB 0,1 0: p0 located at MSB 1
// 1: p0 located at LSB
// ------------------------------------------------------------------
// REUSE ISSUES
// Reset Strategy : external asynchronous active low; rst_ni
// Clock Domains : 1, clk_i, rising edge
// Critical Timing :
// Test Features : na
// Asynchronous I/F : no
// Scan Methodology : na
// Instantiations : none
// Synthesizable (y/n) : Yes
// Other :
// -FHDR-------------------------------------------------------------
//-----------------------------------------------------------------------------
// Hamming codes can detect and correct a single bit error.
// An extended Hamming code allows detection of double bit errors and
// correction of single bit errors.
// This is called SECDED; Single Error Correction, Double Error Detection
//
// Number of bits required by a Hamming code: n = m + k
// n = code length
// m = number of check bits
// k = number of information bits
//
// Information, parity, and syndrome expressed as vectors:
// u = Information bit vector
// p = Parity check bit vector
// s = Syndrome vector
//
// The parity vector is encoded in 'n'.
// The information bit vector is part of 'p'
// The syndrome vector needs to be calculated.
//
// Bits required:
// p ranges from 0 to m+k; or p_range=m+k+1
// As a result 2^m >= m+k+1
//-----------------------------------------------------------------------------
module ecc_dec #(
parameter K = 8, //Information bit vector size
parameter LATENCY = 0, //0: no latency (combinatorial design)
//1: registered outputs
//2: registered inputs+outputs
parameter P0_LSB = 1, //0: p0 is located at MSB
//1: p0 is located at LSB
//These should be localparams
parameter m = calculate_m(K),
parameter n = m + K
)
(
//clock/reset ports (if LATENCY > 0)
input rst_ni, //asynchronous reset
input clk_i, //clock input
input clkena_i, //clock enable input
//data ports
input [n :0] d_i, //encoded code word input
output reg [K-1:0] q_o, //information bit vector output
output reg [m :0] syndrome_o, //syndrome vector output
//flags
output reg sb_err_o, //single bit error detected
output reg db_err_o, //double bit error detected
output reg sb_fix_o //repaired error in the information bits
);
//---------------------------------------------------------
// Functions
//---------------------------------------------------------
function integer calculate_m(input integer k);
integer m;
begin
m=1;
while (2**m < m+k+1) m++;
calculate_m = m;
end
endfunction //calculate_m
function [m:1] calculate_syndrome(input [n:0] cw);
integer p_idx, cw_idx;
begin
//clear syndrome
calculate_syndrome = 0;
for (p_idx =1; p_idx <=m; p_idx++) //parity vector index
for (cw_idx=1; cw_idx<=n; cw_idx++) //code-word index
if (|(2**(p_idx-1) & cw_idx)) calculate_syndrome[p_idx] = calculate_syndrome[p_idx] ^ cw[cw_idx];
end
endfunction //calculate_syndrome
function [n:0] correct_codeword(input [n:0] cw, input [m:1] syndrome);
/*
Correct all bits, including parity bits and extended parity bit.
This simplifies this section and keeps the logic simple.
The parity-bits are not used when extracting the information bits vector.
Dead-logic-removal gets rid of the generated logic for the parity bits.
*/
//assign code word
correct_codeword = cw;
//then invert bit indicated by syndrome
correct_codeword[syndrome] = ~correct_codeword[syndrome];
endfunction //correct_codeword
function [K-1:0] extract_q(input [n:0] cw);
integer bit_idx, cw_idx;
begin
//This function extracts the information bits vector from the codeword
//information bits are stored in non-power-of-2 locations
bit_idx=0; //information bit vector index
for (cw_idx=1; cw_idx<=n; cw_idx++) //codeword index
if (2**$clog2(cw_idx) != cw_idx)
extract_q[bit_idx++] = cw[cw_idx];
end
endfunction //extract_q
function is_power_of_2(input int n);
is_power_of_2 = (n & (n-1)) == 0;
endfunction
function information_error(input [m:1] syndrome);
begin
//This function checks if an error was detected/corrected in the information bits
information_error = |syndrome & !is_power_of_2(syndrome);
end
endfunction //information_error
//---------------------------------------------------------
// Variables
//---------------------------------------------------------
wire parity; //full codeword parity check
logic parity_reg;
wire [m :1] syndrome; //bit error indication/location
logic [m :1] syndrome_reg;
wire [n :0] cw_fixed; //corrected code word
wire [n :0] d;
logic [n :0] d_reg;
wire [K-1:0] q;
wire sb_err;
wire db_err;
wire sb_fix;
//---------------------------------------------------------
// Module Body
//---------------------------------------------------------
/*
Below diagram indicates the locations of the parity and data bits
in the final 'p' vector.
It also shows what databits each parity bit operates on
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
p1 p2 d1 p4 d2 d3 d4 p8 d5 d6 d7 d8 d9 d10 d11
p1 x x x x x x x x
p2 x x x x x x x x
p4 x x x x x x x x
p8 x x x x x x x x
*/
//Step 1: Locate Parity bit
assign d = P0_LSB ? d_i : {d_i[n-1:0],d_i[n]};
//Step 2: Calculate code word parity
assign parity = ^d;
//Step 3: Calculate syndrome
assign syndrome = calculate_syndrome(d);
//Step 4: Generate intermediate registers (if any)
generate
if (LATENCY > 1)
begin
always @(posedge clk_i or negedge rst_ni)
if (!rst_ni)
begin
d_reg <= {n+1{1'b0}};
parity_reg <= 1'b0;
syndrome_reg <= {m{1'b0}};
end
else if (clkena_i)
begin
d_reg <= d;
parity_reg <= parity;
syndrome_reg <= syndrome;
end
end
else
begin
assign d_reg = d;
assign parity_reg = parity;
assign syndrome_reg = syndrome;
end
endgenerate
//Step 5: Correct erroneous bit (if any)
assign cw_fixed = correct_codeword(d_reg, syndrome_reg);
//Step 6: Extract information bits vector
assign q = extract_q(cw_fixed);
//Step 7: Generate status flags
assign sb_err = (parity_reg & |syndrome_reg);
assign db_err = ~parity_reg & |syndrome_reg;
assign sb_fix = parity_reg & |information_error(syndrome_reg);
//Step 8: Generate output registers (if required)
generate
if (LATENCY > 0) //
begin //Generate output registers
always @(posedge clk_i or negedge rst_ni)
if (!rst_ni)
begin
q_o <= {K{1'b0}};
syndrome_o <= {m+1{1'b0}};
sb_err_o <= 1'b0;
db_err_o <= 1'b0;
sb_fix_o <= 1'b0;
end
else if (clkena_i)
begin
q_o <= q;
syndrome_o <= P0_LSB ? {syndrome_reg, parity_reg} : {parity_reg, syndrome_reg};
sb_err_o <= sb_err;
db_err_o <= db_err;
sb_fix_o <= sb_fix;
end
end
else
begin //No output registers
always_comb
begin
q_o = q;
syndrome_o = P0_LSB ? {syndrome_reg, parity_reg} : {parity_reg, syndrome_reg};
sb_err_o = sb_err;
db_err_o = db_err;
sb_fix_o = sb_fix;
end
end
endgenerate
endmodule

217
rtl/ecc/ecc_enc.sv Normal file
View File

@ -0,0 +1,217 @@
/////////////////////////////////////////////////////////////////////
// ,------. ,--. ,--. //
// | .--. ' ,---. ,--,--. | | ,---. ,---. `--' ,---. //
// | '--'.'| .-. |' ,-. | | | | .-. | .-. |,--.| .--' //
// | |\ \ ' '-' '\ '-' | | '--.' '-' ' '-' || |\ `--. //
// `--' '--' `---' `--`--' `-----' `---' `- /`--' `---' //
// `---' //
// Error Correction and Detection Encoder //
// Parameterized Extended Hamming Code Encoder //
// //
/////////////////////////////////////////////////////////////////////
// //
// Copyright (C) 2017 ROA Logic BV //
// www.roalogic.com //
// //
// This source file may be used and distributed without //
// restriction provided that this copyright statement is not //
// removed from the file and that any derivative work contains //
// the original copyright notice and the associated disclaimer. //
// //
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //
// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR OR //
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, //
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT //
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; //
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) //
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN //
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR //
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS //
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //
// //
/////////////////////////////////////////////////////////////////////
// +FHDR - Semiconductor Reuse Standard File Header Section -------
// FILE NAME : ecc_enc.sv
// DEPARTMENT :
// AUTHOR : rherveille
// AUTHOR'S EMAIL :
// ------------------------------------------------------------------
// RELEASE HISTORY
// VERSION DATE AUTHOR DESCRIPTION
// 1.0 2017-04-07 rherveille initial release
// ------------------------------------------------------------------
// KEYWORDS : HAMMING ERROR CORRECTION ENCODER
// ------------------------------------------------------------------
// PURPOSE : Adds ECC bits to incoming data
// ------------------------------------------------------------------
// PARAMETERS
// PARAM NAME RANGE DESCRIPTION DEFAULT UNITS
// K 1+ Information vector size 8
// P0_LSB 0,1 0: p0 located at MSB 1
// 1: p0 located at LSB
// ------------------------------------------------------------------
// REUSE ISSUES
// Reset Strategy : none
// Clock Domains : none
// Critical Timing :
// Test Features : na
// Asynchronous I/F : yes
// Scan Methodology : na
// Instantiations : none
// Synthesizable (y/n) : Yes
// Other :
// -FHDR-------------------------------------------------------------
//-----------------------------------------------------------------------------
// Hamming codes can detect and correct a single bit error.
// An extended Hamming code allows detection of double bit errors and
// correction of single bit errors.
// This is called SECDED; Single Error Correction, Double Error Detection
//
// Number of bits required by a Hamming code: n = m + k
// n = code length
// m = number of check bits
// k = number of information bits
//
// Information, parity, and syndrome expressed as vectors:
// u = Information bit vector
// p = Parity check bit vector
// s = Syndrome vector
//
// The parity vector is encoded in 'n'.
// The information bit vector is part of 'p'
// The syndrome vector needs to be calculated.
//
// Bits required:
// p ranges from 0 to m+k; or p_range=m+k+1
// As a result 2^m >= m+k+1
//-----------------------------------------------------------------------------
module ecc_enc #(
parameter K = 8, //Information bit vector size
parameter P0_LSB = 1, //0: p0 is located at MSB
//1: p0 is located at LSB
//these should be localparams
parameter m = calculate_m(K),
parameter n = m + K
)
(
input [K-1:0] d_i, //information bit vector input
output [n :0] q_o, //encoded data word output
output [m :1] p_o, //parity vector output
output p0_o //extended parity bit
);
//---------------------------------------------------------
// Functions
//---------------------------------------------------------
function integer calculate_m;
input integer k;
integer m;
begin
m=1;
while (2**m < m+k+1) m++;
calculate_m = m;
end
endfunction //calculate_m
function [n:1] store_dbits_in_codeword;
input [K-1:0] d;
integer bit_idx, cw_idx;
begin
//This function puts the information bits vector in the correct location
//Information bits are stored in non-power-of-2 locations
//clear all bits
store_dbits_in_codeword = 0;
bit_idx=0; //information vector bit index
for (cw_idx=1; cw_idx<=n; cw_idx++)
if (2**$clog2(cw_idx) != cw_idx)
store_dbits_in_codeword[cw_idx] = d[bit_idx++];
end
endfunction //store_dbits_in_codeword
function [m:1] calculate_p;
input [n:1] cw;
integer p_idx, cw_idx;
begin
//clear p
calculate_p = 0;
for (p_idx =1; p_idx <=m; p_idx++) //parity-index
for (cw_idx=1; cw_idx<=n; cw_idx++) //codeword-index
if (|(2**(p_idx-1) & cw_idx)) calculate_p[p_idx] = calculate_p[p_idx] ^ cw[cw_idx];
end
endfunction //calculate_p
function [n:1] store_p_in_codeword;
input [n:1] cw;
input [m:1] p;
integer i;
begin
//databits don't change ... copy into codeword
store_p_in_codeword = cw;
//put parity vector at power-of-2 locations
for (i=1; i<=m; i=i+1)
store_p_in_codeword[2**(i-1)] = p[i];
end
endfunction //store_p_in_codeword
//---------------------------------------------------------
// Variables
//---------------------------------------------------------
logic [n:1] cw_w_dbits; //codeword with loaded data bits
logic [n:1] cw; //codeword with information + parity bits
//---------------------------------------------------------
// Module Body
//---------------------------------------------------------
/*
Below diagram indicates the locations of the parity and data bits
in the final 'p' vector.
It also shows what databits each parity bit operates on
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
p1 p2 d1 p4 d2 d3 d4 p8 d5 d6 d7 d8 d9 d10 d11
p1 x x x x x x x x
p2 x x x x x x x x
p4 x x x x x x x x
p8 x x x x x x x x
*/
//Step 1: Load all databits in codeword
assign cw_w_dbits = store_dbits_in_codeword(d_i);
//Step 2: Calculate p-vector
assign p_o = calculate_p(cw_w_dbits);
//Step 3: Store p-vector in codeword
assign cw = store_p_in_codeword(cw_w_dbits, p_o);
//Step 4: Calculate p0 (extended parity bit)
// and store it in the codeword
assign p0_o = ^cw;
assign q_o = P0_LSB ? {cw,p0_o} : {p0_o,cw};
endmodule

View File

@ -63,7 +63,8 @@ module ddr3_dimm_micron_sim;
localparam CONTROLLER_CLK_PERIOD = 10_000, //ps, period of clock input to this DDR3 controller module
DDR3_CLK_PERIOD = 2500, //ps, period of clock input to DDR3 RAM device
AUX_WIDTH = 16; // AUX lines
AUX_WIDTH = 16, // AUX lines
ECC_ENABLE = 2; // ECC enable
reg i_controller_clk, i_ddr3_clk, i_ref_clk, i_ddr3_clk_90;
reg i_rst_n;
@ -160,7 +161,8 @@ ddr3_top #(
.AUX_WIDTH(AUX_WIDTH), //width of aux line (must be >= 4)
.MICRON_SIM(1), //enable faster simulation for micron ddr3 model (shorten POWER_ON_RESET_HIGH and INITIAL_CKE_LOW)
.ODELAY_SUPPORTED(ODELAY_SUPPORTED), //set to 1 if ODELAYE2 is supported
.SECOND_WISHBONE(0) //set to 1 if 2nd wishbone for debugging is needed
.SECOND_WISHBONE(0), //set to 1 if 2nd wishbone for debugging is needed
.ECC_ENABLE(ECC_ENABLE)
) ddr3_top
(
//clock and reset
@ -258,7 +260,16 @@ ddr3_top #(
.dq(dq)
);
`endif
// Force change for ECC tests
always @(ddr3_top.ddr3_controller_inst.stage2_data[ddr3_top.ddr3_controller_inst.STAGE2_DATA_DEPTH-1]) begin
if(ddr3_top.ddr3_controller_inst.initial_calibration_done) begin
force ddr3_top.ddr3_controller_inst.o_phy_data = {ddr3_top.ddr3_controller_inst.stage2_data[ddr3_top.ddr3_controller_inst.STAGE2_DATA_DEPTH-1][ddr3_top.ddr3_controller_inst.wb_data_bits - 1:1], 1'b0};
end
else begin
release ddr3_top.ddr3_controller_inst.o_phy_data;
end
end
reg[511:0] write_data = 0, expected_read_data = 0;
integer address = 0, read_address = 0, address_inner = 0;
integer start_address = 0, start_read_address;
@ -619,6 +630,9 @@ ddr3_top #(
for (index = 0; index < $bits(ddr3_top.i_wb_data)/32; index = index + 1) begin
expected_read_data[index*32 +: 32] = $random(read_address + index); //each $random only has 32 bits
end
if (ECC_ENABLE == 1 || ECC_ENABLE == 2) begin
expected_read_data[511 : ddr3_top.ddr3_controller_inst.ECC_INFORMATION_BITS] = 0;
end
if(expected_read_data == o_wb_data) begin
//$display("SUCCESSFUL: Address = %0d, expected data = %h, read data = %h", (read_address/($bits(ddr3_top.i_wb_data)/32)), expected_read_data, o_wb_data);
number_of_successful = number_of_successful + 1;
@ -639,6 +653,9 @@ ddr3_top #(
for (index = 0; index < $bits(ddr3_top.i_wb_data)/32; index = index + 1) begin
expected_read_data[index*32 +: 32] = $random(read_address + index); //each $random only has 32 bits
end
if (ECC_ENABLE == 1 || ECC_ENABLE == 2) begin
expected_read_data[511 : ddr3_top.ddr3_controller_inst.ECC_INFORMATION_BITS] = 0;
end
if(expected_read_data == o_wb_data) begin
//$display("SUCCESSFUL: Address = %0d, expected data = %h, read data = %h", (read_address/($bits(ddr3_top.i_wb_data)/32)), expected_read_data, o_wb_data);
number_of_successful = number_of_successful + 1;
@ -659,6 +676,9 @@ ddr3_top #(
for (index = 0; index < $bits(ddr3_top.i_wb_data)/32; index = index + 1) begin
expected_read_data[index*32 +: 32] = $random(read_address + index); //each $random only has 32 bits
end
if (ECC_ENABLE == 1 || ECC_ENABLE == 2) begin
expected_read_data[511 : ddr3_top.ddr3_controller_inst.ECC_INFORMATION_BITS] = 0;
end
if(expected_read_data == o_wb_data) begin
//$display("SUCCESSFUL: Address = %0d, expected data = %h, read data = %h", (read_address/($bits(ddr3_top.i_wb_data)/32)), expected_read_data, o_wb_data);
number_of_successful = number_of_successful + 1;
@ -679,6 +699,9 @@ ddr3_top #(
for (index = 0; index < $bits(ddr3_top.i_wb_data)/32; index = index + 1) begin
expected_read_data[index*32 +: 32] = $random(read_address + index); //each $random only has 32 bits
end
if (ECC_ENABLE == 1 || ECC_ENABLE == 2) begin
expected_read_data[511 : ddr3_top.ddr3_controller_inst.ECC_INFORMATION_BITS] = 0;
end
if(expected_read_data == o_wb_data) begin
//$display("SUCCESSFUL: Address = %0d, expected data = %h, read data = %h", (read_address/($bits(ddr3_top.i_wb_data)/32)), expected_read_data, o_wb_data);
number_of_successful = number_of_successful + 1;

View File

@ -11,15 +11,15 @@
</db_ref>
</db_ref_list>
<zoom_setting>
<ZoomStartTime time="64,090.179 ns"></ZoomStartTime>
<ZoomEndTime time="64,220.813 ns"></ZoomEndTime>
<Cursor1Time time="64,130.000 ns"></Cursor1Time>
<ZoomStartTime time="749.583 ns"></ZoomStartTime>
<ZoomEndTime time="6,229.584 ns"></ZoomEndTime>
<Cursor1Time time="1,130.000 ns"></Cursor1Time>
</zoom_setting>
<column_width_setting>
<NameColumnWidth column_width="268"></NameColumnWidth>
<ValueColumnWidth column_width="66"></ValueColumnWidth>
<NameColumnWidth column_width="272"></NameColumnWidth>
<ValueColumnWidth column_width="129"></ValueColumnWidth>
</column_width_setting>
<WVObjectSize size="44" />
<WVObjectSize size="47" />
<wvobject fp_name="divider869" type="divider">
<obj_property name="label">Clocks and Reset</obj_property>
<obj_property name="DisplayName">label</obj_property>
@ -48,6 +48,18 @@
<obj_property name="label">Calibration</obj_property>
<obj_property name="DisplayName">label</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_dimm_micron_sim/ddr3_top/ddr3_controller_inst/\sideband_ECC_per_8_bursts.ecc_dec_inst /sb_err">
<obj_property name="ElementShortName">sb_err</obj_property>
<obj_property name="ObjectShortName">sb_err</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_dimm_micron_sim/ddr3_top/ddr3_controller_inst/\sideband_ECC_per_8_bursts.ecc_dec_inst /db_err">
<obj_property name="ElementShortName">db_err</obj_property>
<obj_property name="ObjectShortName">db_err</obj_property>
</wvobject>
<wvobject type="logic" fp_name="/ddr3_dimm_micron_sim/ddr3_top/ddr3_controller_inst/initial_calibration_done">
<obj_property name="ElementShortName">initial_calibration_done</obj_property>
<obj_property name="ObjectShortName">initial_calibration_done</obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_dimm_micron_sim/calibration_state">
<obj_property name="ElementShortName">calibration_state[319:0]</obj_property>
<obj_property name="ObjectShortName">calibration_state[319:0]</obj_property>
@ -71,12 +83,10 @@
<wvobject type="array" fp_name="/ddr3_dimm_micron_sim/ddr3_top/io_ddr3_dqs">
<obj_property name="ElementShortName">io_ddr3_dqs[1:0]</obj_property>
<obj_property name="ObjectShortName">io_ddr3_dqs[1:0]</obj_property>
<obj_property name="isExpanded"></obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_dimm_micron_sim/ddr3_top/ddr3_phy_inst/idelay_dqs">
<obj_property name="ElementShortName">idelay_dqs[1:0]</obj_property>
<obj_property name="ObjectShortName">idelay_dqs[1:0]</obj_property>
<obj_property name="isExpanded"></obj_property>
</wvobject>
<wvobject type="array" fp_name="/ddr3_dimm_micron_sim/ddr3_top/ddr3_controller_inst/lane">
<obj_property name="ElementShortName">lane[0:0]</obj_property>