ecc_encode.sv
の実装調査を行ったので、今度は ecc_decode.sv
の実装調査をしてみる。
基本的には ecc_encode.sv
の逆を行っており、問題があればエラーを通知することになる。
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 );
data_i
:encoded_data_t
エンコード済みのデータが入っているdata_o
:data_t
デコード後の値を出力するsyndrome_o
:parity_t
エラーが発生した場合のビット位置の情報を出力する。single_error_o
: 単一ビットエラーが発生した場合にアサートされるparity_error_o
: 全体としてパリティエラーが発生した場合にアサートされるdouble_error_o
: 2ビット以上のエラーが発生した場合にアサートされる
実装の詳細についてだが、コード内にコメントがある:
///! | 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.
- パリティビット1は最下位ビット=1(つまり奇数インデックスのビット)のパリティを含んでいる
- パリティビット2は2番目に低いビット=1(つまり、2,3,6,7,10,11…) のパリティを含んでいる
- パリティビット4は3番目に低いビット=1(つまり、4-7, 12-15, 20-23, ….) のパリティを含んでいる
- パリティビット8は4番目に低いビット=!(つまり、8-15, 24-31, 40-47, … )のパリティを含んでいる
シンドロームの計算
それぞれのパリティを検算するために、各対象となるビットのXORを生成する。
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
すべてのシンドロームがゼロであれば問題ないが、1つでも問題があれば訂正または通知を試みる:
シンドロームが誤っているデータの位置を示しているので、そのビット位置を反転させるということになる。
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
- single bit errorの条件: 全体パリティビットエラー & シンドロームが検出された
- parity bit errorの条件: 全体パリティビットエラー & シンドロームが検出されない
- double bit error: 全体パリティビットエラーなし (2ビット反転しているので) & シンドロームが検出された
- シンドロームだけでは、single error と double error の違いが分からないので、double error では 2ビット反転によりparityビットエラーが発生しないことを理由に、切り分けを行っている。
///! 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;
データの抽出
2の累乗のビット位置にはパリティの情報が入っているので、それらを取り除いていく。
// 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;