veryl-std 0.20.0

A modern hardware description language
Documentation
/// Decodes a Hamming encoded single-error-correcting bitvector into its closest word
module linear_sec_decoder #(
    /// Number of parity bits
    param P: u32 = 4,
    /// Length of codeword
    param K: u32 = (1 << P) - 1,
    /// Length of data
    param N: u32 = K - P,
) (
    i_codeword: input  logic<K>,
    o_word    : output logic<N>,
    /// Set iff the input codeword had a detected and corrected single-bit error in it
    o_corrected: output logic,

) {
    // 1-indexed codeword
    let codeword          : logic<K + 1> = {i_codeword, 1'b0};
    var codeword_corrected: logic<K + 1>;

    var errors: logic<P>;

    // Generate word from corrected codeword
    for idx in 1..(K + 2) :g_create_word {
        if !$onehot(idx) :g_data_bit {
            const CEIL            : u32 = $clog2(idx);
            const WORD_IDX        : u32 = idx - 1 - CEIL;
            assign o_word[WORD_IDX] = codeword_corrected[idx];
        }
    }

    // Check parities
    // for k in 1..K + 1 :g_check_parities {
    //     const ERROR_IDX: u32 = k - 1;
    //     if $onehot(k) :g_error_check_parities {
    //         var masked_bits    : logic<K + 1>;
    //         assign masked_bits[0]  = 1'b0;
    //         const ONE_IDX_SET_BIT: u32 = $clog2(k);
    //         for idx in 1..K + 1 :g_check_bits {
    //             if idx[ONE_IDX_SET_BIT] :g_take_parity {
    //                 assign masked_bits[idx] = codeword[idx];
    //             } else {
    //                 assign masked_bits[idx] = 1'b0;
    //             }
    //         }
    //         assign errors[ERROR_IDX] = ^masked_bits;
    //     } else {
    //         assign errors[ERROR_IDX] = 1'b0;
    //     }
    // }
    for pbit in 1..P + 1 :g_check_parities {
        const ONE_IDX_SET_BIT: u32          = pbit - 1;
        var   masked_bits    : logic<K + 1>;
        assign masked_bits[0]  = 1'b0;
        for idx in 1..K + 1 :g_check_bits {
            if idx[ONE_IDX_SET_BIT] :g_take_parity {
                assign masked_bits[idx] = codeword[idx];
            } else {
                assign masked_bits[idx] = 1'b0;
            }
        }
        assign errors[ONE_IDX_SET_BIT] = ^masked_bits;
    }
    // for idx in 1..(K + 1) :g_check_parities {
    //     if $onehot(idx) :g_is_onehot {
    //         const ONE_IDX_SET_BIT: u32      = $clog2(idx);
    //         var masked_bits    : logic<K>;
    //         for idx2 in 1..(P + 1) :gen_mask {
    //             if idx2[ONE_IDX_SET_BIT] :g_take_parity {
    //                 assign masked_bits[idx2 - 1] = codeword[idx2];
    //             } else {
    //                 assign masked_bits[idx2 - 1] = 1'b0;
    //             }
    //         }
    //         assign errors[ONE_IDX_SET_BIT] = ~^masked_bits;
    //     }
    // }

    // Correct as needed
    assign o_corrected = |errors;
    always_comb {
        codeword_corrected         =  codeword;
        codeword_corrected[errors] ^= 1;
    }
}

#[test(test_3_1_hamming_decode)]
embed (inline) sv{{{
module test_3_1_hamming_code;
  bit o_word;
  logic o_corrected;
  logic [2:0] i_codeword;

  std_linear_sec_decoder#(.P(2)) dut(.*);

  initial begin
    $monitor("word: %b\n", o_word, "cwrd: %3b\n", i_codeword,
        "corrected: %b\n", o_corrected,
        "errors: %b\n\n", dut.errors
    );
    i_codeword = 3'b111;
    #1 assert(o_word == 1'b1);
    i_codeword = 3'b000;
    #1 assert(o_word == 1'b0);
    i_codeword = 3'b010;
    #1 assert(o_word == 1'b0 && o_corrected);
    $finish;
  end

endmodule
}}}