Commit 2a76216f authored by GuillemCabo's avatar GuillemCabo
Browse files

add 32b hamming and fix tb bugs

parent 36a2005d
pmu_ahb/
AXI_PMU_interface_v1_0_S00_AXI/
AXI_PMU/
dummy_ahb/
PMU_raw/
......@@ -3,4 +3,6 @@
!*.sh
!*.gtkw
!*.sby
seu_ip/hamming32t26d_dec/
seu_ip/hamming32t26d_enc/
seu_ip/way3_voter/
//-----------------------------------------------------
// 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.
// Description: This module takes 16 bit hamming encoded package and
// outputs the corrected data
//
// Coder : G.Cabo
// References : Ben Eater "What is error correction? Hamming codes in hardware" YT
......@@ -23,12 +23,6 @@ module hamming16t11d_dec #
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
......@@ -36,31 +30,7 @@ module hamming16t11d_dec #
// 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
//Locate 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]};
......
......@@ -23,12 +23,6 @@ module hamming16t11d_enc #
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
......
//-----------------------------------------------------
// ProjectName: De-RISC/SELENE
// Function : Single error corection, double error detection
// Description: This module takes 32 bit hamming encoded package and
// outputs the corrected data
//
// 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 hamming32t26d_dec #
(
// Width of sampled signal
localparam integer IN_WIDTH = 26,
// Number of hamming bits, overall parity bit not included
localparam integer N_CHECKB = $clog2(IN_WIDTH) //5
)
(
// 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
);
//Locate 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],
hv_i[17],hv_i[19],hv_i[21],hv_i[23],
hv_i[25],hv_i[27],hv_i[29],hv_i[31]};
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],
hv_i[18],hv_i[19], hv_i[22],hv_i[23],
hv_i[26],hv_i[27], hv_i[30],hv_i[31] };
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],
hv_i[20],hv_i[21],hv_i[22],hv_i[23],
hv_i[28],hv_i[29],hv_i[30],hv_i[31]};
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],
hv_i[24],hv_i[25],hv_i[26],hv_i[27],hv_i[28],hv_i[29],hv_i[30],hv_i[31]};
assign region_int[4] = ^{hv_i[16],hv_i[17],hv_i[18],hv_i[19],hv_i[20],hv_i[21],hv_i[22],hv_i[23],
hv_i[24],hv_i[25],hv_i[26],hv_i[27],hv_i[28],hv_i[29],hv_i[30],hv_i[31]};
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];
assign data_o[11]= (17==region_int)? ~hv_i[17] : hv_i[17];
assign data_o[12]= (18==region_int)? ~hv_i[18] : hv_i[18];
assign data_o[13]= (19==region_int)? ~hv_i[19] : hv_i[19];
assign data_o[14]= (20==region_int)? ~hv_i[20] : hv_i[20];
assign data_o[15]= (21==region_int)? ~hv_i[21] : hv_i[21];
assign data_o[16]= (22==region_int)? ~hv_i[22] : hv_i[22];
assign data_o[17]= (23==region_int)? ~hv_i[23] : hv_i[23];
assign data_o[18]= (24==region_int)? ~hv_i[24] : hv_i[24];
assign data_o[19]= (25==region_int)? ~hv_i[25] : hv_i[25];
assign data_o[20]= (26==region_int)? ~hv_i[26] : hv_i[26];
assign data_o[21]= (27==region_int)? ~hv_i[27] : hv_i[27];
assign data_o[22]= (28==region_int)? ~hv_i[28] : hv_i[28];
assign data_o[23]= (29==region_int)? ~hv_i[29] : hv_i[29];
assign data_o[24]= (30==region_int)? ~hv_i[30] : hv_i[30];
assign data_o[25]= (31==region_int)? ~hv_i[31] : hv_i[31];
////////////////////////////////////////////////////////////////////////////////
//
// Formal Verification section begins here.
//
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
assert (IN_WIDTH==26);
assert (N_CHECKB==5);
`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 26 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 hamming32t26d_enc #
(
// Width of sampled signal
localparam integer IN_WIDTH = 26,
// Number of hamming bits
localparam integer N_CHECKB = $clog2(IN_WIDTH) //4
)
(
// 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];
assign hv_o[17]=data_i[11];
assign hv_o[18]=data_i[12];
assign hv_o[19]=data_i[13];
assign hv_o[20]=data_i[14];
assign hv_o[21]=data_i[15];
assign hv_o[22]=data_i[16];
assign hv_o[23]=data_i[17];
assign hv_o[24]=data_i[18];
assign hv_o[25]=data_i[19];
assign hv_o[26]=data_i[20];
assign hv_o[27]=data_i[21];
assign hv_o[28]=data_i[22];
assign hv_o[29]=data_i[23];
assign hv_o[30]=data_i[24];
assign hv_o[31]=data_i[25];
//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];
assign hv_o[16]=hcheck_int[4];
//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],
hv_o[17],hv_o[19],hv_o[21],hv_o[23],
hv_o[25],hv_o[27],hv_o[29],hv_o[31]};
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],
hv_o[18],hv_o[19], hv_o[22],hv_o[23],
hv_o[26],hv_o[27], hv_o[30],hv_o[31] };
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],
hv_o[20],hv_o[21],hv_o[22],hv_o[23],
hv_o[28],hv_o[29],hv_o[30],hv_o[31]};
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],
hv_o[24],hv_o[25],hv_o[26],hv_o[27],hv_o[28],hv_o[29],hv_o[30],hv_o[31]};
assign hcheck_int[4] = ^{hv_o[17],hv_o[18],hv_o[19],hv_o[20],hv_o[21],hv_o[22],hv_o[23],
hv_o[24],hv_o[25],hv_o[26],hv_o[27],hv_o[28],hv_o[29],hv_o[30],hv_o[31]};
assign ocheck_int = ^hv_o[31:1];
////////////////////////////////////////////////////////////////////////////////
//
// Formal Verification section begins here.
//
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
assert (IN_WIDTH==26);
assert (N_CHECKB==5);
`endif
endmodule
`default_nettype wire //allow compatibility with legacy code and xilinx ip
hamming32t26d
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 hamming32t26d
vmap work $PWD/hamming32t26d
vlog +acc=rn +incdir+$TOP/hdl/ $TOP/submodules/seu_ip/hamming32t26d_dec.sv $TOP/submodules/seu_ip/hamming32t26d_enc.sv tb_hamming32t26d.sv ./colors.vh
vmake hamming32t26d/ > Makefile
if [ -z "$1" ]
then
vsim work.tb_hamming32t26d -do "do wave.do" -do "run -all"
else
vsim work.tb_hamming32t26d $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_hamming32t26d();
//***Parameters***
parameter CLK_PERIOD = 8;
parameter CLK_HALF_PERIOD = CLK_PERIOD / 2;
parameter CLK_QUARTER_PERIOD = CLK_HALF_PERIOD/ 2;
localparam TB_DATA_WIDTH = 26;
localparam TB_HAM_WIDTH = 32;//Width of 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
hamming32t26d_enc#(
)dut_hamming32t26d_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
hamming32t26d_dec#(
)dut_hamming32t26d_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_hamming32t26d_enc);
$dumpvars(0,dut_hamming32t26d_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(500,temp);
test_sbf(500,temp);
test_dbf(500,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 (32,26)
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[17] =tmp[11];
hv[18] =tmp[12];
hv[19] =tmp[13];
hv[20] =tmp[14];
hv[21] =tmp[15];
hv[22] =tmp[16];
hv[23] =tmp[17];
hv[24] =tmp[18];
hv[25] =tmp[19];
hv[26] =tmp[20];
hv[27] =tmp[21];
hv[28] =tmp[22];
hv[29] =tmp[23];
hv[30] =tmp[24];
hv[31] =tmp[25];
hv[1] = ^{hv[3],hv[5],hv[7],
hv[9],hv[11],hv[13],hv[15],
hv[17],hv[19],hv[21],hv[23],
hv[25],hv[27],hv[29],hv[31]};
hv[2] = ^{hv[3],hv[6],hv[7],
hv[10],hv[11],hv[14],hv[15],
hv[18],hv[19], hv[22],hv[23],
hv[26],hv[27], hv[30],hv[31] };
hv[4] = ^{hv[5],hv[6],hv[7],
hv[12],hv[13],hv[14],hv[15],
hv[20],hv[21],hv[22],hv[23],
hv[28],hv[29],hv[30],hv[31]};
hv[8] = ^{hv[9],hv[10],hv[11],hv[12],hv[13],hv[14],hv[15],
hv[24],hv[25],hv[26],hv[27],hv[28],hv[29],hv[30],hv[31]};
hv[16] = ^{hv[17],hv[18],hv[19],hv[20],hv[21],hv[22],hv[23],
hv[24],hv[25],hv[26],hv[27],hv[28],hv[29],hv[30],hv[31]};
hv[0] = ^hv[31: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[31:17],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;
//Release forced error after one cycle
release prot_reg;
trasient=0;
#CLK_PERIOD;
//check for errors