add initial ECC, ECC_ENABLE = 2 working
This commit is contained in:
parent
1f7d4d18a9
commit
7d93717b72
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue