head 1.1;
access;
symbols;
locks; strict;
comment @# @;
1.1
date 2001.09.03.13.18.30; author bbeaver; state Exp;
branches;
next ;
desc
@@
1.1
log
@no message
@
text
@//////////////////////////////////////////////////////////////////////
//// ////
//// hamming_ecc_64 ////
//// ////
//// hamming_ecc_generate_word_with_check_bits_64 ////
//// hamming_ecc_check_and_correct_64 ////
//// ////
//// This file is part of the general opencores effort. ////
//// ////
//// ////
//// Module Description: ////
//// Using Hamming style functions, calculate 72 bits from 64 to ////
//// make a value which can be corrected back to the original ////
//// 64 bits of valid data if a single bit error is applied to ////
//// the 72 bits. ////
//// ////
//// To Do: ////
//// nothing pending ////
//// ////
//// Author(s): ////
//// - Anonymous ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2001 Anonymous and OPENCORES.ORG ////
//// ////
//// 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 source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from ////
//// ////
//////////////////////////////////////////////////////////////////////
//
// $Id: hamming_ecc_64.v,v 1.1 2001/09/03 13:22:46 Blue Beaver Exp $
//
// CVS Revision History
//
// $Log: hamming_ecc_64.v,v $
// Revision 1.1 2001/09/03 13:22:46 Blue Beaver
// no message
//
//
//===========================================================================
//
// NOTE: The plan seems to be the following:
// Assign a binary Bit Address to each bit.
// Calculate ECC check bits by XOR'ing the bits together which
// correspond to 1's in each bit's Bit Address;
// (For instance, ECC Check Digit bit 0 XORs together Data_In[1],
// Data_In[3], and so on.)
// You need 7 bits to have enough addresses for all 64 single-bit
// errors, plus the value which covers the case of no errors.
//
// NOTE: But wait, there's more! What if a check bit fails?
// The trick is to have the failing check digit call ITSELF out.
// To achieve this, you have to distribute the check bits
// so that they have nice binary Bit Addresses.
//
// NOTE: There is even more. Every single bit error results in a word
// with wrong parity. But what if 2 bits flip? The parity goes
// back to the original. You can add a parity bit to everything,
// and if the check bits say there is an error but the parity is
// correct that means that 2 bits are wrong.
// The parity bit becomes the 8th bit of the ECC check bits.
//
// NOTE: The web pages discussing this seem to put the parity bit as bit 1
// in the check bit calculation, the LSB check bit as bit 2, the
// next check bit as bit 4, and so on.
//
// NOTE: Since the parity bit is used to calculate the LSB of the
// check bits, and since it is the XOR of all bits, you have
// to calculate the XOR of the bits you least expect to calculate
// the low-order check bit. The ones with "0" as the LSB of their
// bit address, not "1".
//
// This code was developed using VeriLogger Pro, by Synapticad.
// Their support is greatly appreciated.
//
//===========================================================================
`timescale 1ns/1ps
// Given 64 bits, calculate 7 bits of ECC check bits and 1 bit of parity.
// NOTE: Why a module and not a function? No idea.
module hamming_ecc_calculate_check_bits_private (
data_in,
check_bits_out,
par_if_inserting_check_bits_out
);
parameter NUM_DATA_BITS = 64; // do not override in the instantiation.
parameter NUM_CHECK_BITS = 8;
input [NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0] data_in;
output [NUM_CHECK_BITS - 1 : 0] check_bits_out;
output par_if_inserting_check_bits_out;
// LSB of Check Bits depends on every other input bit.
wire parity_1_3_5_7 = data_in[1] ^ data_in[3] ^ data_in[5] ^ data_in[7];
wire parity_9_11_13_15 = data_in[9] ^ data_in[11] ^ data_in[13] ^ data_in[15];
wire parity_17_19_21_23 = data_in[17] ^ data_in[19] ^ data_in[21] ^ data_in[23];
wire parity_25_27_29_31 = data_in[25] ^ data_in[27] ^ data_in[29] ^ data_in[31];
wire parity_33_35_37_39 = data_in[33] ^ data_in[35] ^ data_in[37] ^ data_in[39];
wire parity_41_43_45_47 = data_in[41] ^ data_in[43] ^ data_in[45] ^ data_in[47];
wire parity_49_51_53_55 = data_in[49] ^ data_in[51] ^ data_in[53] ^ data_in[55];
wire parity_57_59_61_63 = data_in[57] ^ data_in[59] ^ data_in[61] ^ data_in[63];
wire parity_65_67_69_71 = data_in[65] ^ data_in[67] ^ data_in[69] ^ data_in[71];
wire parity_1_3_5_7_9_11_13_15_17_19_21_23 =
parity_1_3_5_7 ^ parity_9_11_13_15 ^ parity_17_19_21_23;
wire parity_25_27_29_31_33_35_37_39_41_43_45_47 =
parity_25_27_29_31 ^ parity_33_35_37_39 ^ parity_41_43_45_47;
wire parity_49_51_53_55_57_59_61_63_65_67_69_71 =
parity_49_51_53_55 ^ parity_57_59_61_63 ^ parity_65_67_69_71;
assign check_bits_out[0] = parity_1_3_5_7_9_11_13_15_17_19_21_23
^ parity_25_27_29_31_33_35_37_39_41_43_45_47
^ parity_49_51_53_55_57_59_61_63_65_67_69_71;
// second bit depends 2 out of 4 bits
wire parity_2_3_6_7 = data_in[2] ^ data_in[3] ^ data_in[6] ^ data_in[7];
wire parity_10_11_14_15 = data_in[10] ^ data_in[11] ^ data_in[14] ^ data_in[15];
wire parity_18_19_22_23 = data_in[18] ^ data_in[19] ^ data_in[22] ^ data_in[23];
wire parity_26_27_30_31 = data_in[26] ^ data_in[27] ^ data_in[30] ^ data_in[31];
wire parity_34_35_38_39 = data_in[34] ^ data_in[35] ^ data_in[38] ^ data_in[39];
wire parity_42_43_46_47 = data_in[42] ^ data_in[43] ^ data_in[46] ^ data_in[47];
wire parity_50_51_54_55 = data_in[50] ^ data_in[51] ^ data_in[54] ^ data_in[55];
wire parity_58_59_62_63 = data_in[58] ^ data_in[59] ^ data_in[62] ^ data_in[63];
wire parity_66_67_70_71 = data_in[66] ^ data_in[67] ^ data_in[70] ^ data_in[71];
wire parity_2_3_6_7_10_11_14_15_18_19_22_23 =
parity_2_3_6_7 ^ parity_10_11_14_15 ^ parity_18_19_22_23;
wire parity_26_27_30_31_34_35_38_39_42_43_46_47 =
parity_26_27_30_31 ^ parity_34_35_38_39 ^ parity_42_43_46_47;
wire parity_50_51_54_55_58_59_62_63_66_67_70_71 =
parity_50_51_54_55 ^ parity_58_59_62_63 ^ parity_66_67_70_71;
assign check_bits_out[1] = parity_2_3_6_7_10_11_14_15_18_19_22_23
^ parity_26_27_30_31_34_35_38_39_42_43_46_47
^ parity_50_51_54_55_58_59_62_63_66_67_70_71;
// Higher-numbered bits depend on groups of 4 adjacent input bits.
wire parity_0_3 = ^data_in[3:0]; // XOR reduction
wire parity_4_7 = ^data_in[7:4]; // XOR reduction
wire parity_8_11 = ^data_in[11:8]; // XOR reduction
wire parity_12_15 = ^data_in[15:12]; // XOR reduction
wire parity_16_19 = ^data_in[19:16]; // XOR reduction
wire parity_20_23 = ^data_in[23:20]; // XOR reduction
wire parity_24_27 = ^data_in[27:24]; // XOR reduction
wire parity_28_31 = ^data_in[31:28]; // XOR reduction
wire parity_32_35 = ^data_in[35:32]; // XOR reduction
wire parity_36_39 = ^data_in[39:36]; // XOR reduction
wire parity_40_43 = ^data_in[43:40]; // XOR reduction
wire parity_44_47 = ^data_in[47:44]; // XOR reduction
wire parity_48_51 = ^data_in[51:48]; // XOR reduction
wire parity_52_55 = ^data_in[55:52]; // XOR reduction
wire parity_56_59 = ^data_in[59:56]; // XOR reduction
wire parity_60_63 = ^data_in[63:60]; // XOR reduction
wire parity_64_67 = ^data_in[67:64]; // XOR reduction
wire parity_68_71 = ^data_in[71:68]; // XOR reduction
wire parity_4_7_12_15_20_23 = parity_4_7 ^ parity_12_15 ^ parity_20_23;
wire parity_28_31_36_39_44_47 = parity_28_31 ^ parity_36_39 ^ parity_44_47;
wire parity_52_55_60_63_68_71 = parity_52_55 ^ parity_60_63 ^ parity_68_71;
assign check_bits_out[2] = parity_4_7_12_15_20_23
^ parity_28_31_36_39_44_47
^ parity_52_55_60_63_68_71;
wire parity_8_11_12_15_24_27 = parity_8_11 ^ parity_12_15 ^ parity_24_27;
wire parity_28_31_40_43_44_47 = parity_28_31 ^ parity_40_43 ^ parity_44_47;
wire parity_56_59_60_63 = parity_56_59 ^ parity_60_63;
assign check_bits_out[3] = parity_8_11_12_15_24_27
^ parity_28_31_40_43_44_47
^ parity_56_59_60_63;
wire parity_16_19_20_23_24_27 = parity_16_19 ^ parity_20_23 ^ parity_24_27;
wire parity_28_31_48_51_52_55 = parity_28_31 ^ parity_48_51 ^ parity_52_55;
assign check_bits_out[4] = parity_16_19_20_23_24_27
^ parity_28_31_48_51_52_55
^ parity_56_59_60_63;
wire parity_32_35_36_39_40_43 = parity_32_35 ^ parity_36_39 ^ parity_40_43;
wire parity_44_47_48_51_52_55 = parity_44_47 ^ parity_48_51 ^ parity_52_55;
wire parity_second_quarter = parity_32_35_36_39_40_43
^ parity_44_47_48_51_52_55
^ parity_56_59_60_63;
assign check_bits_out[5] = parity_second_quarter;
wire parity_third_quarter = parity_64_67 ^ parity_68_71;
assign check_bits_out[6] = parity_third_quarter;
// NOTE: In the generate case, the Check Bit inputs to this function come in
// as all 0's. The generator wants to calculate parity across all bits,
// including Check Bits!
// The slow, inexpensive way to do this is to calculate the odd parity of
// the data including 0's for Check Bits, then XOR that with all of
// the check bits to get the actual word checksum.
// A faster way to do this is to calculate the final checksum directly.
// This starts out by XOR'ing all the Data Bits together. BUT notice
// that the ECC bits contain XOR's of bits in the data. If you
// XOR the Check Bits with the XOR of the Data Bits, some of the
// dependencies on certain data bits go away!
// This function therefore only bothers to calculate the XOR of the bits
// which are not rendered don't cares by the XORing of the check bits.
wire parity_0_3_5_6 = data_in[0] ^ data_in[3] ^ data_in[5] ^ data_in[6];
wire parity_9_10_12_15 = data_in[9] ^ data_in[10] ^ data_in[12] ^ data_in[15];
wire parity_17_18_20_23 = data_in[17] ^ data_in[18] ^ data_in[20] ^ data_in[23];
wire parity_24_27_29_30 = data_in[24] ^ data_in[27] ^ data_in[29] ^ data_in[30];
wire parity_33_34_36_39 = data_in[33] ^ data_in[34] ^ data_in[36] ^ data_in[39];
wire parity_40_43_45_46 = data_in[40] ^ data_in[43] ^ data_in[45] ^ data_in[46];
wire parity_48_51_53_54 = data_in[48] ^ data_in[51] ^ data_in[53] ^ data_in[54];
wire parity_57_58_60_63 = data_in[57] ^ data_in[58] ^ data_in[60] ^ data_in[63];
wire parity_65_66_68_71 = data_in[65] ^ data_in[66] ^ data_in[68] ^ data_in[71];
wire parity_0_3_5_6_9_10_12_15_17_18_20_23 =
parity_0_3_5_6 ^ parity_9_10_12_15 ^ parity_17_18_20_23;
wire parity_24_27_29_30_33_34_36_39_40_43_45_46 =
parity_24_27_29_30 ^ parity_33_34_36_39 ^ parity_40_43_45_46;
wire parity_48_51_53_54_57_58_60_63 =
parity_48_51_53_54 ^ parity_57_58_60_63 ^ parity_65_66_68_71;
assign par_if_inserting_check_bits_out =
parity_0_3_5_6_9_10_12_15_17_18_20_23
^ parity_24_27_29_30_33_34_36_39_40_43_45_46
^ parity_48_51_53_54_57_58_60_63;
// The module which checks ECC values actually has to look at all the data.
// Reuse calculations which have already been done.
wire parity_0_3_8_11_16_19 = parity_0_3 ^ parity_8_11 ^ parity_16_19;
wire parity_24_27_28_31 = parity_24_27 ^ parity_28_31;
wire parity_first_quarter = parity_0_3_8_11_16_19
^ parity_4_7_12_15_20_23
^ parity_24_27_28_31;
assign check_bits_out[7] = parity_first_quarter
^ parity_second_quarter
^ parity_third_quarter;
endmodule
// Given a 64-bit word (with no errors), calculate the 72-bit word which
// will be stored to allow ECC to recover the original 64 bits in case of
// a single bit error.
module hamming_ecc_generate_word_with_check_bits_64 (
data_in,
data_plus_ecc_out,
clk
);
parameter NUM_DATA_BITS = 64; // do not override in the instantiation.
parameter NUM_CHECK_BITS = 8;
input [NUM_DATA_BITS - 1 : 0] data_in;
output [NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0] data_plus_ecc_out;
input clk;
wire [NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0] input_vector =
{data_in[63:57], 1'b0, // check digit 6, bit 64
data_in[56:26], 1'b0, // check digit 5, bit 32
data_in[25:11], 1'b0, // check digit 4, bit 16
data_in[10:4], 1'b0, // check digit 3, bit 8
data_in[3:1], 1'b0, // check digit 2, bit 4
data_in[0], 1'b0, // check digit 1, bit 2
1'b0, 1'b1}; // check digit 0, bit 0 == 1 says odd parity
wire [NUM_CHECK_BITS - 1 : 0] check_bits_out;
wire par_if_inserting_check_bits_out;
hamming_ecc_calculate_check_bits_private generate_ecc_bits (
.data_in (input_vector[NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0]),
.check_bits_out (check_bits_out[NUM_CHECK_BITS - 1 : 0]),
.par_if_inserting_check_bits_out (par_if_inserting_check_bits_out)
);
// Insert check bits into their nice power-of-2 locations, so they can call
// themselves out if they read in error.
wire [NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0] reordered_data_plus_ecc =
{data_in[63:57], check_bits_out[6], // check digit 6, bit 64
data_in[56:26], check_bits_out[5], // check digit 5, bit 32
data_in[25:11], check_bits_out[4], // check digit 4, bit 16
data_in[10:4], check_bits_out[3], // check digit 3, bit 8
data_in[3:1], check_bits_out[2], // check digit 2, bit 4
data_in[0], check_bits_out[1], // check digit 1, bit 2
check_bits_out[0], // check digit 0, bit 1
par_if_inserting_check_bits_out}; // odd parity, bit 0
reg [NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0] data_plus_ecc_out;
always @@(posedge clk)
begin
data_plus_ecc_out[NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0] <=
reordered_data_plus_ecc[NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0];
end
endmodule
// Given 64 bits, plus 7 bits of ECC check bits and 1 bit of parity,
// discover if the data is correct.
// If 1 bit is wrong, correct it and report the problem.
// If 2 bits are wrong, report the problem.
// If an unexpected bit error position comes out, report that as an error.
// If more than 2 bits are wrong, you are hosed. Most are not detected.
//
// The error_addressvalue is encoded. It means this:
// Error Value 0: no error
// Error Value 1: check bit 0 is wrong
// Error Value 2: check bit 1 is wrong
// Error Value 3: data bit 0 is wrong
// Error Value 4: check bit 2 is wrong
// Error Values 7:5: data bits 3:1 are wrong
// Error Value 8: check bit 3 is wrong
// Error Values 15:9: data bits 10:4 are wrong
// Error Value 16: check bit 4 is wrong
// Error Values 31:17: data bits 25:11 are wrong
// Error Value 32: check bit 5 is wrong
// Error Values 63:32: data bits 56:26 are wrong
// Error Value 64: check bit 6 is wrong
// Error Values 71:65: data bits 63:57 are wrong
// Error Value 72: check bit 7 is wrong
module hamming_ecc_check_and_correct_64 (
data_plus_ecc_in,
corrected_data_out,
corrected_check_bits_out,
single_bit_error_corrected,
double_bit_error_detected,
error_address,
clk
);
parameter NUM_DATA_BITS = 64; // do not override in the instantiation.
parameter NUM_CHECK_BITS = 8;
input [NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0] data_plus_ecc_in;
output [NUM_DATA_BITS - 1 : 0] corrected_data_out;
output [NUM_CHECK_BITS - 1 : 0] corrected_check_bits_out;
output single_bit_error_corrected;
output double_bit_error_detected;
output [6:0] error_address;
input clk;
// If there is an error, the XOR of the calculated and stored Check Bits
// gives the address of the failing bit.
// The calculate_check_bits module, when applied to a word containing check bits,
// will do the XOR automatically. The output is the address of the failing bit.
wire [NUM_CHECK_BITS - 1 : 0] check_bits;
wire par_if_inserting_check_bits_out; // ignore
hamming_ecc_calculate_check_bits_private check_ecc_bits (
.data_in (data_plus_ecc_in[NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0]),
.check_bits_out (check_bits[NUM_CHECK_BITS - 1 : 0]),
.par_if_inserting_check_bits_out (par_if_inserting_check_bits_out)
);
wire parity_error_detected = ~check_bits[7]; // If data was Odd Parity, return 1'b1;
wire parity_bit_wrong = (check_bits[6:0] == 7'h00) & parity_error_detected;
wire correction_needed = (check_bits[6:0] != 7'h00) // non-zero means correct!
| parity_bit_wrong;
wire unexpected_error_address = (check_bits[6:0] >= 8'h48); // >= 72
// If there is an error, need to make a mask to XOR with the data in order to
// get the corrected data back.
// Verilogger seems to be in a core-dumping mood with a straight-forward shift.
// Doing things manually will result in better logic, anyway.
wire [1:0] mask_0 = check_bits[0] ? 2'b10 : 2'b01;
wire [3:0] mask_1 = check_bits[1]
? {mask_0[1:0], 2'b00}
: {2'b00, mask_0[1:0]};
wire [7:0] mask_2 = check_bits[2]
? {mask_1[3:0], 4'h0}
: {4'h0, mask_1[3:0]};
wire [15:0] mask_3 = check_bits[3]
? {mask_2[7:0], 8'h00}
: {8'h00, mask_2[7:0]};
wire [31:0] mask_4 = check_bits[4]
? {mask_3[15:0], 16'h0000}
: {16'h0000, mask_3[15:0]};
wire [63:0] mask_5 = check_bits[5]
? {mask_4[31:0], 32'h00000000}
: {32'h00000000, mask_4[31:0]};
wire [71:0] mask_6 = check_bits[6]
? {mask_5[7:0], 64'h00000000_00000000}
: {8'h00, mask_5[63:0]};
wire [NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0] error_corrected_data =
data_plus_ecc_in[NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0]
^ {mask_6[71:1], parity_bit_wrong};
wire [NUM_DATA_BITS - 1 : 0] reordered_corrected_data =
{error_corrected_data[71:65],
error_corrected_data[63:33],
error_corrected_data[31:17],
error_corrected_data[15:9],
error_corrected_data[7:5],
error_corrected_data[3]};
wire [NUM_CHECK_BITS - 1 : 0] reordered_corrected_check_bits =
{error_corrected_data[0],
error_corrected_data[64],
error_corrected_data[32],
error_corrected_data[16],
error_corrected_data[8],
error_corrected_data[4],
error_corrected_data[2],
error_corrected_data[1]};
reg [NUM_DATA_BITS - 1 : 0] corrected_data_out;
reg [NUM_CHECK_BITS - 1 : 0] corrected_check_bits_out;
reg single_bit_error_corrected;
reg double_bit_error_detected;
reg [6:0] error_address;
always @@(posedge clk)
begin
corrected_data_out[NUM_DATA_BITS - 1 : 0] <=
reordered_corrected_data[NUM_DATA_BITS - 1 : 0];
corrected_check_bits_out[NUM_CHECK_BITS - 1 : 0] <=
reordered_corrected_check_bits[NUM_CHECK_BITS - 1 : 0];
single_bit_error_corrected <= correction_needed & parity_error_detected;
double_bit_error_detected <= (correction_needed & ~parity_error_detected)
| unexpected_error_address;
error_address[6:0] <= parity_bit_wrong
? 8'h48 // 72
: check_bits[6:0];
end
endmodule
// `define TEST_HAMMING_ECC_CODE
`ifdef TEST_HAMMING_ECC_CODE
module test_ecc ();
parameter NUM_DATA_BITS = 64; // do not override in the instantiation.
parameter NUM_CHECK_BITS = 8;
reg clk;
reg [NUM_DATA_BITS - 1 : 0] data_in;
wire [NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0] data_plus_ecc_out;
wire [NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0] data_plus_ecc_in;
reg [NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0] force_error;
wire [NUM_DATA_BITS - 1 : 0] corrected_data_out;
wire [NUM_CHECK_BITS - 1 : 0] corrected_check_bits_out;
wire single_bit_error_corrected;
wire double_bit_error_detected;
wire [6:0] error_address;
reg [NUM_DATA_BITS - 1 : 0] data_pattern;
reg [NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0] error_mask_1;
reg [NUM_DATA_BITS + NUM_CHECK_BITS - 1 : 0] error_mask_2;
integer cnt;
task make_clk;
begin
# 1;
clk = 1'b1;
# 2;
clk = 1'b0;
# 1;
end
endtask
wire [NUM_CHECK_BITS - 1 : 0] original_check_bits =
{data_plus_ecc_out[0],
data_plus_ecc_out[64],
data_plus_ecc_out[32],
data_plus_ecc_out[16],
data_plus_ecc_out[8],
data_plus_ecc_out[4],
data_plus_ecc_out[2],
data_plus_ecc_out[1]};
initial
begin
clk = 1'b0;
$display ("Walking a 1");
// need to check that walking 1 bit goes through correctly.
for (data_pattern = 64'h00000000_00000001;
data_pattern != 64'h0;
data_pattern = data_pattern << 1)
begin
data_in = data_pattern;
force_error = 72'h00_00000000_00000000;
make_clk;
make_clk;
if (data_in !== corrected_data_out)
$display ("*** Data In != Data Out %x %x", data_in, corrected_data_out);
if (original_check_bits !== corrected_check_bits_out)
$display ("*** Check Bits In != Check Bits Out %x %x", original_check_bits, corrected_check_bits_out);
if (single_bit_error_corrected !== 1'b0)
$display ("*** Unexpected Single Bit Error Detected %x %x %x",
single_bit_error_corrected, data_pattern, data_plus_ecc_in);
if (double_bit_error_detected !== 1'b0)
$display ("*** Unexpected Double Bit Error Detected %x %x %x",
double_bit_error_detected, data_pattern, data_plus_ecc_in);
end
$display ("Walking a 0");
// need to check that walking 0 bit goes through correctly.
for (data_pattern = 64'h00000000_00000001;
data_pattern != 64'h0;
data_pattern = data_pattern << 1)
begin
data_in = ~data_pattern;
force_error = 72'h00_00000000_00000000;
make_clk;
make_clk;
if (corrected_data_out !== data_in)
$display ("*** Data In != Data Out %x %x", data_in, corrected_data_out);
if (original_check_bits !== corrected_check_bits_out)
$display ("*** Check Bits In != Check Bits Out %x %x", original_check_bits, corrected_check_bits_out);
if (single_bit_error_corrected !== 1'b0)
$display ("*** Unexpected Single Bit Error Detected %x %x %x",
single_bit_error_corrected, data_pattern, data_plus_ecc_in);
if (double_bit_error_detected !== 1'b0)
$display ("*** Unexpected Double Bit Error Detected %x %x %x",
double_bit_error_detected, data_pattern, data_plus_ecc_in);
end
$display ("Sending Random Data");
// need to check that walking 0 bit goes through correctly.
for (cnt = 0; cnt < 1000; cnt = cnt + 1)
begin
data_in = {$random, $random};
force_error = 72'h00_00000000_00000000;
make_clk;
make_clk;
if (corrected_data_out !== data_in)
$display ("*** Data In != Data Out %x %x", data_in, corrected_data_out);
if (original_check_bits !== corrected_check_bits_out)
$display ("*** Check Bits In != Check Bits Out %x %x", original_check_bits, corrected_check_bits_out);
if (single_bit_error_corrected !== 1'b0)
$display ("*** Unexpected Single Bit Error Detected %x %x %x",
single_bit_error_corrected, data_pattern, data_plus_ecc_in);
if (double_bit_error_detected !== 1'b0)
$display ("*** Unexpected Double Bit Error Detected %x %x %x",
double_bit_error_detected, data_pattern, data_plus_ecc_in);
end
$display ("Making 0 go to 1, even parity, error check");
// need to check that 1 bit which should be 0 is detected correctly, even parity.
for (error_mask_1 = 72'h00_00000000_00000001;
error_mask_1 != 72'h0;
error_mask_1 = error_mask_1 << 1)
begin
data_in = 64'h00000000_00000000;
force_error = error_mask_1;
make_clk;
make_clk;
if (corrected_data_out !== data_in)
$display ("*** Data In != Data Out %x %x", data_in, corrected_data_out);
if (original_check_bits !== corrected_check_bits_out)
$display ("*** Check Bits In != Check Bits Out %x %x", original_check_bits, corrected_check_bits_out);
if (single_bit_error_corrected !== 1'b1)
$display ("*** Expected Single Bit Error Missed %x %x %x",
single_bit_error_corrected, error_mask_1, data_plus_ecc_in);
if (double_bit_error_detected !== 1'b0)
$display ("*** Unexpected Double Bit Error Detected %x %x %x",
double_bit_error_detected, error_mask_1, data_plus_ecc_in);
if ( (error_mask_1 == 72'h00_00000000_00000001)
& (error_address != 8'h48) )
$display ("*** Parity Error calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
if ( (error_mask_1 == 72'h00_00000000_00000001)
& (error_address != 8'h48) )
$display ("*** Bit 0 calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
if ( (error_mask_1 == 72'h80_00000000_00000000)
& (error_address != 8'h47) )
$display ("*** Bit 71 calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
end
$display ("Making 0 go to 1, odd parity, error check");
// need to check that 1 bit which should be 0 is detected correctly, odd parity.
for (error_mask_1 = 72'h00_00000000_00000001;
error_mask_1 != 72'h0;
error_mask_1 = error_mask_1 << 1)
begin
data_in = 64'h10000000_00000000;
force_error = error_mask_1;
make_clk;
make_clk;
if (corrected_data_out !== data_in)
$display ("*** Data In != Data Out %x %x", data_in, corrected_data_out);
if (original_check_bits !== corrected_check_bits_out)
$display ("*** Check Bits In != Check Bits Out %x %x", original_check_bits, corrected_check_bits_out);
if (single_bit_error_corrected !== 1'b1)
$display ("*** Expected Single Bit Error Missed %x %x %x",
single_bit_error_corrected, error_mask_1, data_plus_ecc_in);
if (double_bit_error_detected !== 1'b0)
$display ("*** Unexpected Double Bit Error Detected %x %x %x",
double_bit_error_detected, error_mask_1, data_plus_ecc_in);
if ( (error_mask_1 == 72'h00_00000000_00000001)
& (error_address != 8'h48) )
$display ("*** Parity Error calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
if ( (error_mask_1 == 72'h00_00000000_00000001)
& (error_address != 8'h48) )
$display ("*** Bit 0 calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
if ( (error_mask_1 == 72'h80_00000000_00000000)
& (error_address != 8'h47) )
$display ("*** Bit 71 calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
end
$display ("Making 1 go to 0, even parity, error check");
// need to check that 0 bit which should be 1 is detected correctly, even parity.
for (error_mask_1 = 72'h00_00000000_00000001;
error_mask_1 != 72'h0;
error_mask_1 = error_mask_1 << 1)
begin
data_in = 64'hFFFFFFFF_FFFFFFFF;
force_error = error_mask_1;
make_clk;
make_clk;
if (corrected_data_out !== data_in)
$display ("*** Data In != Data Out %x %x", data_in, corrected_data_out);
if (original_check_bits !== corrected_check_bits_out)
$display ("*** Check Bits In != Check Bits Out %x %x", original_check_bits, corrected_check_bits_out);
if (single_bit_error_corrected !== 1'b1)
$display ("*** Expected Single Bit Error Missed %x %x %x",
single_bit_error_corrected, error_mask_1, data_plus_ecc_in);
if (double_bit_error_detected !== 1'b0)
$display ("*** Unexpected Double Bit Error Detected %x %x %x",
double_bit_error_detected, error_mask_1, data_plus_ecc_in);
if ( (error_mask_1 == 72'h00_00000000_00000001)
& (error_address != 8'h48) )
$display ("*** Parity Error calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
if ( (error_mask_1 == 72'h00_00000000_00000001)
& (error_address != 8'h48) )
$display ("*** Bit 0 calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
if ( (error_mask_1 == 72'h80_00000000_00000000)
& (error_address != 8'h47) )
$display ("*** Bit 71 calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
end
$display ("Making 1 go to 0, odd parity, error check");
// need to check that 0 bit which should be 1 is detected correctly, odd parity.
for (error_mask_1 = 72'h00_00000000_00000001;
error_mask_1 != 72'h0;
error_mask_1 = error_mask_1 << 1)
begin
data_in = 64'hFFFFFFFF_FFFFFFFE;
force_error = error_mask_1;
make_clk;
make_clk;
if (corrected_data_out !== data_in)
$display ("*** Data In != Data Out %x %x", data_in, corrected_data_out);
if (original_check_bits !== corrected_check_bits_out)
$display ("*** Check Bits In != Check Bits Out %x %x", original_check_bits, corrected_check_bits_out);
if (single_bit_error_corrected !== 1'b1)
$display ("*** Expected Single Bit Error Missed %x %x %x",
single_bit_error_corrected, error_mask_1, data_plus_ecc_in);
if (double_bit_error_detected !== 1'b0)
$display ("*** Unexpected Double Bit Error Detected %x %x %x",
double_bit_error_detected, error_mask_1, data_plus_ecc_in);
if ( (error_mask_1 == 72'h00_00000000_00000001)
& (error_address != 8'h48) )
$display ("*** Parity Error calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
if ( (error_mask_1 == 72'h00_00000000_00000001)
& (error_address != 8'h48) )
$display ("*** Bit 0 calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
if ( (error_mask_1 == 72'h80_00000000_00000000)
& (error_address != 8'h47) )
$display ("*** Bit 71 calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
end
$display ("Walking error, random data, error check");
// need to check that 0 bit which should be 1 is detected correctly, odd parity.
for (error_mask_1 = 72'h00_00000000_00000001;
error_mask_1 != 72'h0;
error_mask_1 = error_mask_1 << 1)
begin
for (cnt = 0; cnt < 25; cnt = cnt + 1)
begin
data_in = {$random, $random};
force_error = error_mask_1;
make_clk;
make_clk;
if (corrected_data_out !== data_in)
$display ("*** Data In != Data Out %x %x", data_in, corrected_data_out);
if (original_check_bits !== corrected_check_bits_out)
$display ("*** Check Bits In != Check Bits Out %x %x", original_check_bits, corrected_check_bits_out);
if (single_bit_error_corrected !== 1'b1)
$display ("*** Expected Single Bit Error Missed %x %x %x",
single_bit_error_corrected, error_mask_1, data_plus_ecc_in);
if (double_bit_error_detected !== 1'b0)
$display ("*** Unexpected Double Bit Error Detected %x %x %x",
double_bit_error_detected, error_mask_1, data_plus_ecc_in);
if ( (error_mask_1 == 72'h00_00000000_00000001)
& (error_address != 8'h48) )
$display ("*** Parity Error calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
if ( (error_mask_1 == 72'h00_00000000_00000001)
& (error_address != 8'h48) )
$display ("*** Bit 0 calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
if ( (error_mask_1 == 72'h80_00000000_00000000)
& (error_address != 8'h47) )
$display ("*** Bit 71 calls out wrong bit offset %x %x",
error_address, data_plus_ecc_in);
end
end
$display ("testing 2-bit errors, random data, error check");
// need to check 2 bit errors detected.
for (error_mask_1 = 72'h00_00000000_00000001;
error_mask_1 != 72'h80_00000000_00000000;
error_mask_1 = error_mask_1 << 1)
begin
for (error_mask_2 = error_mask_1 << 1;
error_mask_2 != 72'h0;
error_mask_2 = error_mask_2 << 1)
begin
if (error_mask_1 != error_mask_2)
begin
data_in = {$random, $random};
force_error = error_mask_1 | error_mask_2;
make_clk;
make_clk;
if (single_bit_error_corrected !== 1'b0)
$display ("*** Unexpected Single Bit Error Detected %x %x %x",
single_bit_error_corrected, error_mask_1, data_plus_ecc_in);
if (double_bit_error_detected !== 1'b1)
$display ("*** Expected Double Bit Error Missed %x %x %x",
double_bit_error_detected, error_mask_1, data_plus_ecc_in);
end
end
end
end
hamming_ecc_generate_word_with_check_bits_64 generate (
.data_in (data_in),
.data_plus_ecc_out (data_plus_ecc_out),
.clk (clk)
);
assign data_plus_ecc_in[71:0] = data_plus_ecc_out ^ force_error;
hamming_ecc_check_and_correct_64 check_and_correct (
.data_plus_ecc_in (data_plus_ecc_in),
.corrected_data_out (corrected_data_out),
.corrected_check_bits_out (corrected_check_bits_out),
.single_bit_error_corrected (single_bit_error_corrected),
.double_bit_error_detected (double_bit_error_detected),
.error_address (error_address),
.clk (clk)
);
endmodule
`endif // TEST_HAMMING_ECC_CODE
@