ecc_encode.svの実装詳細
モジュール入出力
module ecc_encode import ecc_pkg::*; #( parameter int unsigned DataWidth = 64, 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; } ) ( input data_t data_i, output encoded_data_t data_o );
このモジュールは以下のパラメータを使用している:
DataWidth:エンコード対象のデータ幅 (デフォルト64ビット)data_t:入力データの型 (デフォルトではlogic [DataWidth-1: 0]parity_t:パリティビットの型 (デフォルトではlogic [get_parity_width(DataWidth)-1: 0])code_word_t:コードワード(データ+パリティ)の型 (logic [get_cw_width(DataWidth)-1: 0])encoded_data_t:最終的なエンコードデータの型(パリティビット+コードワード)
例えば、 DataWidth = 64 の場合、それぞれのパラメータは以下のように計算できる。
DataWidth = 64data_t = logic [63: 0]parity_t = logic[get_parity_width(64)-1: 0] = logic [7-1: 0] = logic [ 6: 0]code_word_t = logic [get_cw_width(DataWidth)-1: 0] = logic [64+7-1: 0] = logic [70: 0]encoded_data_t = struct packed {logic parity; logic [70: 0] code_word; }
ちなみに、 get_parity_width() は以下のように定義されている。コメントは自分の計算。
// Calculate required ECC parity width: function automatic int unsigned get_parity_width (input int unsigned data_width); // data_width + cw_width + 1 <= 2**cw_width int unsigned cw_width = 2; while (unsigned'(2**cw_width) < cw_width + data_width + 1) cw_width++; // data_width = 64 // cw_width = 2 -> 2**2 < 2 + 64 + 1 = 4 < 67 -> True // cw_width = 3 -> 2**3 < 3 + 64 + 1 = 8 < 68 -> True // cw_width = 4 -> 2**4 < 4 + 64 + 1 = 16 < 70 -> True // cw_width = 5 -> 2**5 < 5 + 64 + 1 = 32 < 71 -> True // cw_width = 6 -> 2**6 < 6 + 64 + 1 = 64 < 72 -> True // cw_width = 7 -> 2**7 < 7 + 64 + 1 = 128 < 73 -> False // cw_width = 7 return cw_width; endfunction // Calculate required ECC codeword width: function automatic int unsigned get_cw_width (input int unsigned data_width); // data width + parity width + one additional parity bit (for double error detection) return data_width + get_parity_width(data_width); // data_width = 64 // cw_width = 64 + 7 = 70 endfunction
実装の3つの主要ステップ
1. データの展開(expand_data)
// data_i は入力ビット列 // input data_t data_i, logic [63: 0] always_comb begin : expand_data automatic int unsigned idx; data = '0; idx = 0; for (int unsigned i = 1; i < unsigned'($bits(code_word_t)) + 1; i++) begin // if it is not a power of two word it is a normal data index if (unsigned'(2**$clog2(i)) != i) begin // iが2の累乗の時だけ非成立 data[i - 1] = data_i[idx]; idx++; end end end // 63| 62| 61|...| 8| 7| 6| 5| 4| 3| 2| 1| 0| // d63|d62|d61|...| d8| d7| d6| d5| d4| d3| d2| d1| d0| // ...| P | d4| d3| d2| P | d1| P | P | d0|
この処理では、入力データをコードワード幅に展開している。ハミング符号では、パリティビットは2のべき乗の位置(1, 2, 4, 8, ...)に配置されるため、データビットはそれ以外の位置に配置される。

2. シンドローム計算(calculate_syndrome)
always_comb begin : calculate_syndrome parity_code_word = 0; // もっとも外側のループは parity_t (Data=64-bit の場合は 6-bit) だけ回される for (int unsigned i = 0; i < unsigned'($bits(parity_t)); i++) begin // 次のループは、 code_word_t (Data=64-bit の場合は 70-bit) だけ回される for (int unsigned j = 1; j < unsigned'($bits(code_word_t)) + 1; j++) begin // たとえば、 // i = 0 -> j = 1 がXOR対象 // i = 1 -> j = 2, 3 が XOR対象 if (|(unsigned'(2**i) & j)) parity_code_word[i] = parity_code_word[i] ^ data[j - 1]; end end end
この処理では、各パリティビットを計算している。パリティビット i は、位置 j のビットが条件|(unsigned'(2**i) & j)を満たす場合にXOR演算に含まれる。これは、ハミング符号のパリティ計算規則に基づいている。

3. コードワード生成(generate_codeword)
always_comb begin : generate_codeword codeword = data; for (int unsigned i = 0; i < unsigned'($bits(parity_t)); i++) begin codeword[2**i-1] = parity_code_word[i]; end end
この処理では、計算されたパリティビットをコードワードの適切な位置に配置している。
最終出力
assign data_o.code_word = codeword; assign data_o.parity = ^codeword;
最終的に、コードワードと全体のパリティビット(全ビットのXOR)を出力している。この全体パリティビットにより、二重エラー検出が可能になる。