// Copyright 2020 ETH Zurich and University of Bologna. // Copyright and related rights are licensed under the Solderpad Hardware // License, Version 0.51 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law // or agreed to in writing, software, hardware and materials distributed under // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. // // Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch> // /// # ECC Decoder /// /// Implements SECDED (Single Error Correction, Double Error Detection) Hamming Code /// with extended parity bit [1]. /// The module receives a data word including parity bit and decodes it according to the /// number of data and parity bit. /// /// 1. If no error has been detected, the syndrome will be zero and all flags will be zero. /// 2. If a single error has been detected, the syndrome is non-zero, and `single_error_o` will be /// asserted. The output word contains the corrected data. /// 3. If the parity bit contained an error, the module will assert `parity_error_o`. /// 4. In case of a double fault the syndrome is non-zero, `double_error_o` will be asserted. /// All other status flags will be de-asserted. /// /// [1] https://en.wikipedia.org/wiki/Hamming_code module ecc_decode import ecc_pkg::*; #( /// Data width of unencoded word. parameter int unsigned DataWidth = 64, // Do not change parameter type data_t = logic [DataWidth-1:0], parameter type parity_t = logic [get_parity_width(DataWidth)-1:0], parameter type code_word_t = logic [get_cw_width(DataWidth)-1:0], parameter type encoded_data_t = struct packed { logic parity; code_word_t code_word; } ) ( /// Encoded data in input encoded_data_t data_i, /// Corrected data out output data_t data_o, /// Error syndrome indicates the erroneous bit position output parity_t syndrome_o, /// A single error occurred output logic single_error_o, /// Error received in parity bit (MSB) output logic parity_error_o, /// A double error occurred output logic double_error_o ); logic parity; data_t data_wo_parity; parity_t syndrome; logic syndrome_not_zero; code_word_t correct_data; // Check parity bit. 0 = parity equal, 1 = different parity assign parity = data_i.parity ^ (^data_i.code_word); ///! | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ///! |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 ///! 1. Parity bit 1 covers all bit positions which have the least significant bit ///! set: bit 1 (the parity bit itself), 3, 5, 7, 9, etc. ///! 2. Parity bit 2 covers all bit positions which have the second least ///! significant bit set: bit 2 (the parity bit itself), 3, 6, 7, 10, 11, etc. ///! 3. Parity bit 4 covers all bit positions which have the third least ///! significant bit set: bits 4–7, 12–15, 20–23, etc. ///! 4. Parity bit 8 covers all bit positions which have the fourth least ///! significant bit set: bits 8–15, 24–31, 40–47, etc. ///! 5. In general each parity bit covers all bits where the bitwise AND of the ///! parity position and the bit position is non-zero. always_comb begin : calculate_syndrome syndrome = 0; for (int unsigned i = 0; i < unsigned'($bits(parity_t)); i++) begin for (int unsigned j = 0; j < unsigned'($bits(code_word_t)); j++) begin if (|(unsigned'(2**i) & (j + 1))) syndrome[i] = syndrome[i] ^ data_i.code_word[j]; end end end assign syndrome_not_zero = |syndrome; // correct the data word if the syndrome is non-zero always_comb begin correct_data = data_i.code_word; if (syndrome_not_zero) begin correct_data[syndrome - 1] = ~data_i.code_word[syndrome - 1]; end end ///! Syndrome | Overall Parity (MSB) | Error Type | Notes ///! -------------------------------------------------------- ///! 0 | 0 | No Error | ///! /=0 | 1 | Single Error | Correctable. Syndrome holds incorrect bit position. ///! 0 | 1 | Parity Error | Overall parity, MSB is in error and can be corrected. ///! /=0 | 0 | Double Error | Not correctable. assign single_error_o = parity & syndrome_not_zero; assign parity_error_o = parity & ~syndrome_not_zero; assign double_error_o = ~parity & syndrome_not_zero; // Extract data vector always_comb begin automatic int unsigned idx; // bit index data_wo_parity = '0; idx = 0; for (int unsigned i = 1; i < unsigned'($bits(code_word_t)) + 1; i++) begin // if i is a power of two we are indexing a parity bit if (unsigned'(2**$clog2(i)) != i) begin data_wo_parity[idx] = correct_data[i - 1]; idx++; end end end assign data_o = data_wo_parity; endmodule