Commit a1f28127 authored by GuillemCabo's avatar GuillemCabo Committed by Guillem
Browse files

add 16,11 hamming encoder and decoder

WIP hamming

decoder error correction and DED not working

Add extended hamming (SEC-DEC) 16t11d IP and TB

TB checks for run 500K cases of no upset, single bit upset and double bit upset
parent 872ea158
com_tr
ecc_reg_sbf
hamming16t11d_dec
hamming16t11d_gen
hamming16t5d_gen
hamming16t11d_gen
hamming16t5d_gen
//-----------------------------------------------------
// ProjectName: De-RISC/SELENE
// Function : Single error corection, double error detection
// Description: This module takes 11 bits of incomming data and computes the checkbits
// for Hamming codes.
//
// Coder : G.Cabo
// References : Ben Eater "What is error correction? Hamming codes in hardware" YT
`default_nettype none
`timescale 1 ns / 1 ps
`ifndef SYNT
`ifdef FORMAL
`define ASSERTIONS
`endif
`endif
module hamming16t11d_dec #
(
// Width of sampled signal
localparam integer IN_WIDTH = 11,
// Number of hamming bits
localparam integer N_CHECKB = $clog2(IN_WIDTH) //4
)
(
// Global Clock Signal
//input wire clk_i,
// Global Reset Signal. This Signal is Active LOW
//input wire rstn_i,
// Enable Signal.
//input wire en_i,
// Corrected data
output wire [IN_WIDTH-1:0] data_o,
// Hamming vector
input wire [IN_WIDTH+N_CHECKB:0] hv_i,
// Double error detection signal
output wire ded_error_o
);
//logic [N_CHECKB-1:0] hcheck_int; // hamming parity bits
//logic ocheck_int; // Overall parity bit
//logic [IN_WIDTH-1:0] data_int; // Encoded data
/*
//Rearrange ingputs
//Data
assign data_int[0]=hv_i[3];
assign data_int[1]=hv_i[5];
assign data_int[2]=hv_i[6];
assign data_int[3]=hv_i[7];
assign data_int[4]=hv_i[9];
assign data_int[5]=hv_i[10];
assign data_int[6]=hv_i[11];
assign data_int[7]=hv_i[12];
assign data_int[8]=hv_i[13];
assign data_int[9]=hv_i[14];
assign data_int[10]=hv_i[15];
//Checkbits
assign ocheck_int=hv_i[0];
assign hcheck_int[0]=hv_i[1];
assign hcheck_int[1]=hv_i[2];
assign hcheck_int[2]=hv_i[4];
assign hcheck_int[3]=hv_i[8];
*/
//Locate errors errors
logic [N_CHECKB-1:0] region_int;//Each parity "region" and overall.
assign region_int[0] = ^{hv_i[1],hv_i[3],hv_i[5],hv_i[7] ,hv_i[9],hv_i[11],hv_i[13],hv_i[15]};
assign region_int[1] = ^{hv_i[2],hv_i[3],hv_i[6],hv_i[7] ,hv_i[10],hv_i[11],hv_i[14],hv_i[15]};
assign region_int[2] = ^{hv_i[4],hv_i[5],hv_i[6],hv_i[7] ,hv_i[12],hv_i[13],hv_i[14],hv_i[15]};
assign region_int[3] = ^{hv_i[8],hv_i[9],hv_i[10],hv_i[11] ,hv_i[12],hv_i[13],hv_i[14],hv_i[15]};
assign ded_error_o = ~(^hv_i) & (region_int!=0);
//no errors -> data correct
//One or Two region parity bit -> recoverable
//Overall parity 1 -> two errors non-recoverable
//Flip data that needs correction
assign data_o[0]= (3==region_int)? ~hv_i[3] : hv_i[3];
assign data_o[1]= (5==region_int)? ~hv_i[5] : hv_i[5];
assign data_o[2]= (6==region_int)? ~hv_i[6] : hv_i[6];
assign data_o[3]= (7==region_int)? ~hv_i[7] : hv_i[7];
assign data_o[4]= (9==region_int)? ~hv_i[9] : hv_i[9];
assign data_o[5]= (10==region_int)? ~hv_i[10] : hv_i[10];
assign data_o[6]= (11==region_int)? ~hv_i[11] : hv_i[11];
assign data_o[7]= (12==region_int)? ~hv_i[12] : hv_i[12];
assign data_o[8]= (13==region_int)? ~hv_i[13] : hv_i[13];
assign data_o[9]= (14==region_int)? ~hv_i[14] : hv_i[14];
assign data_o[10]= (15==region_int)? ~hv_i[15] : hv_i[15];
/*
genvar i;
generate
for(i=0;i<IN_WIDTH-1;i++) begin
assign data_o[i]= (i==region_int)? ^hv_i[i] : hv_i[i];
end
endgenerate*/
/*
^data_i
^data_int[IN_WIDTH/2:0]
*/
////////////////////////////////////////////////////////////////////////////////
//
// Formal Verification section begins here.
//
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
assert (IN_WIDTH==11);
assert (N_CHECKB==4);
`endif
endmodule
`default_nettype wire //allow compatibility with legacy code and xilinx ip
//-----------------------------------------------------
// ProjectName: De-RISC/SELENE
// Function : Single error corection, double error detection
// Description: This module takes 11 bits of incomming data and computes the checkbits
// for Hamming codes.
//
// Coder : G.Cabo
// References : Ben Eater "What is error correction? Hamming codes in hardware" YT
`default_nettype none
`timescale 1 ns / 1 ps
`ifndef SYNT
`ifdef FORMAL
`define ASSERTIONS
`endif
`endif
module hamming16t11d_enc #
(
// Width of sampled signal
localparam integer IN_WIDTH = 11,
// Number of hamming bits
localparam integer N_CHECKB = $clog2(IN_WIDTH) //4
)
(
// Global Clock Signal
//input wire clk_i,
// Global Reset Signal. This Signal is Active LOW
//input wire rstn_i,
// Enable Signal.
//input wire en_i,
// Signal at register input
input wire [IN_WIDTH-1:0] data_i,
// Hamming vector
output wire [IN_WIDTH+N_CHECKB:0] hv_o
);
logic [N_CHECKB-1:0] hcheck_int; // hamming parity bits
logic ocheck_int; // Overall parity bit
//Rearrange ingputs
//Data
assign hv_o[3]=data_i[0];
assign hv_o[5]=data_i[1];
assign hv_o[6]=data_i[2];
assign hv_o[7]=data_i[3];
assign hv_o[9]=data_i[4];
assign hv_o[10]=data_i[5];
assign hv_o[11]=data_i[6];
assign hv_o[12]=data_i[7];
assign hv_o[13]=data_i[8];
assign hv_o[14]=data_i[9];
assign hv_o[15]=data_i[10];
//Checkbits
assign hv_o[0]=ocheck_int;
assign hv_o[1]=hcheck_int[0];
assign hv_o[2]=hcheck_int[1];
assign hv_o[4]=hcheck_int[2];
assign hv_o[8]=hcheck_int[3];
//compute checkbits
assign hcheck_int[0] = ^{hv_o[3],hv_o[5],hv_o[7] ,hv_o[9],hv_o[11],hv_o[13],hv_o[15]};
assign hcheck_int[1] = ^{hv_o[3],hv_o[6],hv_o[7] ,hv_o[10],hv_o[11],hv_o[14],hv_o[15]};
assign hcheck_int[2] = ^{hv_o[5],hv_o[6],hv_o[7] ,hv_o[12],hv_o[13],hv_o[14],hv_o[15]};
assign hcheck_int[3] = ^{hv_o[9],hv_o[10],hv_o[11] ,hv_o[12],hv_o[13],hv_o[14],hv_o[15]};
assign ocheck_int = ^hv_o[15:1];
/*
^data_i
^data_i[IN_WIDTH/2:0]
*/
////////////////////////////////////////////////////////////////////////////////
//
// Formal Verification section begins here.
//
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
assert (IN_WIDTH==11);
assert (N_CHECKB==4);
`endif
endmodule
`default_nettype wire //allow compatibility with legacy code and xilinx ip
...@@ -4,3 +4,7 @@ IPs for Transient and permanent error detection and correction mechanisms ...@@ -4,3 +4,7 @@ IPs for Transient and permanent error detection and correction mechanisms
combinational logic. Registered output error signal. Non-intrusive changes. combinational logic. Registered output error signal. Non-intrusive changes.
* reg\_sbf.sv: Single bitflip error detection for registers. Registered output * reg\_sbf.sv: Single bitflip error detection for registers. Registered output
signal. Non-intrusive changes. signal. Non-intrusive changes.
* ecc\_reg\_sbf.sv: Single bitflip error correction for registers.
* hamming16t11d\_enc: SEC-DEC Hamming encoder. 11 data bits, 5 check bits.
* hamming16t11d\_dec: SEC-DEC Hamming decoder. 11 data bits, 5 check bits.
hamming16t11d
Makefile
modelsim.ini
test.vcd
transcript
vsim.wlf
`define START_GREEN_PRINT $write("%c[1;32m",27);
`define START_RED_PRINT $write("%c[1;31m",27);
`define END_COLOR_PRINT $write("%c[0m",27);
# Use ./runtest.sh -batch to run the simulation in batch mode
TOP=../../..
vlib hamming16t11d
vmap work $PWD/hamming16t11d
vlog +acc=rn +incdir+$TOP/hdl/ $TOP/submodules/seu_ip/hamming16t11d_dec.sv $TOP/submodules/seu_ip/hamming16t11d_enc.sv tb_hamming16t11d.sv ./colors.vh
vmake hamming16t11d/ > Makefile
if [ -z "$1" ]
then
vsim work.tb_hamming16t11d -do "do wave.do" -do "run -all"
else
vsim work.tb_hamming16t11d $1 -do "do save_wave.do"
fi
set WildcardFilter ""
log -r /*
run -all
quit
//-----------------------------------------------------
// ProjectName: De-RISC/SELENE
// Function : TB for SEC-DEC Hamming encoder and decoder
// Description: This module takes a signals coming from the input of a register,
// encodes the data in Hamming (16,11) format, registers the coded data and retrieves
// the error corrected data at the output
//
// Double error detection signal is only active while the bit-flip is present
// in the circuit aka the error signal is NOT holded until it is handled.
//
// Coder : G.Cabo
// References : Ben Eater "What is error correction? Hamming codes in hardware" YT
`timescale 1 ns / 1 ns
`default_nettype none
`include "colors.vh"
//***Headers***
//***Test bench***
module tb_hamming16t11d();
//***Parameters***
parameter CLK_PERIOD = 8;
parameter CLK_HALF_PERIOD = CLK_PERIOD / 2;
parameter CLK_QUARTER_PERIOD = CLK_HALF_PERIOD/ 2;
localparam TB_DATA_WIDTH = 11;
localparam TB_HAM_WIDTH = 16;//Width od data with Hamming check bits
//***DUT parameters***
reg tb_clk_i;
reg tb_rstn_i;
reg tb_error_o;
reg tb_ded_error_o;
reg [TB_DATA_WIDTH-1:0] tb_din_i;
wire [TB_DATA_WIDTH-1:0] tb_dout_o;
reg [TB_HAM_WIDTH-1:0] prot_reg;
wire [TB_HAM_WIDTH-1:0] prot_reg_d;
wire [TB_HAM_WIDTH-1:0] prot_reg_q;
logic [TB_HAM_WIDTH-1:0] valid_value;
logic [TB_HAM_WIDTH-1:0] upset_value;
var trasient=0; // High while a signal has been forced
//store name of test for easier debug of waveform
reg[64*8:0] tb_test_name;
reg tb_fail = 0;
//***Modules***
//encoder
hamming16t11d_enc#(
)dut_hamming16t11d_enc (
.data_i(tb_din_i),
.hv_o(prot_reg_d)
);
// Instance of protected register and output wires
always_ff @(posedge tb_clk_i) begin
if(!tb_rstn_i) begin
prot_reg <= '{default:'0};
end else begin
prot_reg <= prot_reg_d ;
end
end
assign prot_reg_q = prot_reg;
//decoder
hamming16t11d_dec#(
)dut_hamming16t11d_dec (
.data_o(tb_dout_o),
.hv_i(prot_reg_q),
.ded_error_o(tb_ded_error_o)
);
// Degug only signals
wire [TB_DATA_WIDTH-1:0] dbg_andio;
assign dbg_andio = tb_din_i ^ tb_dout_o;
wire [TB_HAM_WIDTH-1:0] dbg_andhv;
assign dbg_andhv = valid_value ^ upset_value;
//***clk_gen***
initial tb_clk_i = 1;
always #CLK_HALF_PERIOD tb_clk_i = !tb_clk_i;
default clocking @(posedge tb_clk_i); endclocking
//***task automatic reset_dut***
task automatic reset_dut;
begin
$display("*** Toggle reset.");
tb_test_name = "reset_dut";
tb_rstn_i <= 1'b0;
#CLK_PERIOD;
tb_rstn_i <= 1'b1;
#CLK_PERIOD;
$display("Done");
tb_test_name = "";
end
endtask
//***task automatic init_sim***
//Initialize TB registers to a known state.
task automatic init_sim;
begin
$display("*** init sim.");
tb_test_name = "init_sim";
$display("Done");
tb_test_name = "";
tb_rstn_i=0;
tb_error_o=0;
tb_din_i<=0;
prot_reg=0;
valid_value=0;
upset_value=0;
end
endtask
//***task automatic init_dump***
task automatic init_dump;
begin
$dumpfile("test.vcd");
$dumpvars(0,dut_hamming16t11d_enc);
$dumpvars(0,dut_hamming16t11d_dec);
end
endtask
//***task automatic test_sim***
task automatic test_sim;
begin
int unsigned temp=1;
$display("*** test_sim.");
tb_test_name="test_sim";
//**test***
test_no_sbf(500000,temp);
test_sbf(500000,temp);
test_dbf(500000,temp);
//check results
if(temp!=1) begin
tb_fail = 1;
$error("FAIL test_sim.");
`START_RED_PRINT
$display("FAIL");
`END_COLOR_PRINT
end
$display("Done");
tb_test_name="";
end
endtask
//***task automatic test_no_sbf***
// Random input events are generated, but no
// errors are forced.
// Returns 0 if test fails and 1 if test passes
task automatic test_no_sbf(input int n_tries, output int rval);
begin
int tmp=0;
$display("*** test_no_sbf");
tb_test_name="test_no_sbf";
//**test***
for(int i=0;i<n_tries;i++) begin
tb_din_i <= $urandom();
#CLK_PERIOD;
#CLK_PERIOD;
//check for errors
if((tb_dout_o!=$past(tb_din_i)) || (tb_ded_error_o!=0)) begin
tmp=1;
end
end
//check results
if(tmp!=0) begin
$error("FAIL test_no_sbf. DED detected or data corrupted");
`START_RED_PRINT
$display("FAIL");
`END_COLOR_PRINT
rval=0;
end
$display("Done");
tb_test_name="";
rval=1;
end
endtask
//***task automatic ***
// Generates random valid hamming vectors (16,11)
task automatic rnd_hamming (output logic [TB_HAM_WIDTH-1:0] hv);
begin
logic [TB_HAM_WIDTH-1:0] tmp = $urandom();
hv[3] =tmp[0];
hv[5] =tmp[1];
hv[6] =tmp[2];
hv[7] =tmp[3];
hv[9] =tmp[4];
hv[10] =tmp[5];
hv[11] =tmp[6];
hv[12] =tmp[7];
hv[13] =tmp[8];
hv[14] =tmp[9];
hv[15] =tmp[10];
hv[1] = ^{hv[3],hv[5],hv[7] ,hv[9],hv[11],hv[13],hv[15]};
hv[2] = ^{hv[3],hv[6],hv[7] ,hv[10],hv[11],hv[14],hv[15]};
hv[4] = ^{hv[5],hv[6],hv[7] ,hv[12],hv[13],hv[14],hv[15]};
hv[8] = ^{hv[9],hv[10],hv[11] ,hv[12],hv[13],hv[14],hv[15]};
hv[0] = ^hv[15:1];
end
endtask
//***task automatic test_sbf***
// Random input events are generated, along
// single bit-flip faults.
// Returns 0 if test fails and 1 if test passes
task automatic test_sbf(input int n_tries, output int rval);
begin
int tmp=0;
$display("*** test_sbf");
tb_test_name="test_sbf";
//**test***
for(int i=0;i<n_tries;i++) begin
rnd_hamming(valid_value);
upset_value = valid_value ^ (1<< $urandom_range(0,TB_HAM_WIDTH-1));
//Ensure that the upset actually changes the value
while(upset_value == valid_value) begin
upset_value = valid_value ^ (1<< $urandom_range(0,TB_HAM_WIDTH-1));
end
//Assign input value
tb_din_i <= {valid_value[15:9],valid_value[7:5],valid_value[3]};
#CLK_PERIOD;
//Force error within register
trasient=1;
force prot_reg = upset_value;
#CLK_PERIOD;
//check for errors
if(($past(tb_dout_o)!=$past(tb_dout_o)) || (tb_ded_error_o!=0)) begin
tmp=1;
end
//Release forced error after one cycle
release prot_reg;
trasient=0;
#CLK_PERIOD;
end
//check results
if(tmp!=0) begin
$error("FAIL test_sbf.Some SBF have not been corrected or unexpected DED detected");
`START_RED_PRINT
$display("FAIL");
`END_COLOR_PRINT
rval=0;
end
$display("Done");
tb_test_name="";
rval=1;
end
endtask
//***task automatic test_dbf***
// Random input events are generated, along
// double bit-flip faults.
// Returns 0 if test fails and 1 if test passes
task automatic test_dbf(input int n_tries, output int rval);
begin
int tmp=0;
$display("*** test_dbf");
tb_test_name="test_dbf";
//**test***
for(int i=0;i<n_tries;i++) begin
rnd_hamming(valid_value);
upset_value = valid_value ^ (3<< $urandom_range(0,TB_HAM_WIDTH-2));
//Ensure that the upset actually changes the value
while(upset_value == valid_value) begin
upset_value = valid_value ^ (1<< $urandom_range(0,TB_HAM_WIDTH-1));
end
//Assign input value
tb_din_i <= {valid_value[15:9],valid_value[7:5],valid_value[3]};
#CLK_PERIOD;
//Force error within register
trasient=1;
force prot_reg = upset_value;
#CLK_PERIOD;
//check for errors
if((tb_ded_error_o!=1)) begin
tmp=1;
end
//Release forced error after one cycle
release prot_reg;
trasient=0;
#CLK_PERIOD;
end
//check results
if(tmp!=0) begin
$error("FAIL test_dbf.DED undetected");
`START_RED_PRINT
$display("FAIL");
`END_COLOR_PRINT
rval=0;
end
$display("Done");
tb_test_name="";
rval=1;
end
endtask
initial begin
integer retv;
tb_rstn_i<='{default:0};
valid_value <='{default:0};
upset_value <='{default:0};
if (TB_DATA_WIDTH >32) begin
$error("Width too big");
`START_RED_PRINT
$display("TB designed for TB_DATA_WIDTH up to 32 bit");
`END_COLOR_PRINT
end
init_sim();
init_dump();
reset_dut();
test_sim();
$finish;
end
endmodule
`default_nettype wire
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate -radix ascii /tb_hamming16t11d/tb_test_name
add wave -noupdate /tb_hamming16t11d/tb_clk_i
add wave -noupdate -color Orange -itemcolor Red /tb_hamming16t11d/upset_value
add wave -noupdate -color Orange -itemcolor Red /tb_hamming16t11d/valid_value
add wave -noupdate -color Coral -itemcolor Red /tb_hamming16t11d/dbg_andhv
add wave -noupdate -color Magenta /tb_hamming16t11d/trasient
add wave -noupdate -color {Medium Spring Green} /tb_hamming16t11d/dut_hamming16t11d_enc/data_i
add wave -noupdate -color {Cornflower Blue} -itemcolor Black /tb_hamming16t11d/dut_hamming16t11d_dec/data_o
add wave -noupdate -color {Medium Spring Green} /tb_hamming16t11d/dut_hamming16t11d_enc/hv_o
add wave -noupdate -color {Cornflower Blue} -itemcolor Black /tb_hamming16t11d/dut_hamming16t11d_dec/ded_error_o
add wave -noupdate -color {Cornflower Blue} -itemcolor Black /tb_hamming16t11d/dut_hamming16t11d_dec/hv_i
add wave -noupdate -color Coral /tb_hamming16t11d/prot_reg
add wave -noupdate /tb_hamming16t11d/tb_din_i
add wave -noupdate /tb_hamming16t11d/tb_dout_o
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {31886 ps} 0}
quietly wave cursor active 1
configure wave -namecolwidth 621
configure wave -valuecolwidth 157
configure wave -justifyvalue left
configure wave -signalnamewidth 0
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {0 ps} {33600 ps}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment