CRCモジュール(Verilog-HDL)
作成者:mou-mou
弊社で作成したVerilog-HDLのCRCモジュールをご紹介いたします。
入力データビット幅、CRCデータ幅、多項式、シード値、CRC出力反転をパラメータ設定できます。
DATA_WIDTHは、入力データのビット幅を設定します。シリアル通信の場合などに、1ビット毎での入力を行うことも可能ですし、8ビットにして1バイト分の演算を1クロックサイクルで処理するなど自由に設定を行うことが出来ます。それによってデバイス、ロジック規模、クロックレートによって最適な使用方法を選択できます。
CRC_WIDTHは、CRCのビット幅を設定します。
POLYNOMIALは、多項式を設定します。例えばCRC-16-CCITT x16+x12+x5+1の場合、16’h1021となります。
SEED_VALは、初期値を設定します。通常は0を設定します。
OUTPUT_EXORは、出力の反転設定をします。通常は0を設定します。
【crc.v】
//% @file //% @brief crc //% CRC演算 module crc # ( parameter DATA_WIDTH = 8, //% データ幅 parameter CRC_WIDTH = 16, //% CRCデータ幅 parameter [CRC_WIDTH-1:0] POLYNOMIAL = 16'h1021, //% 生成多項式 parameter [CRC_WIDTH-1:0] SEED_VAL = 16'h0, //% シード値 parameter OUTPUT_EXOR = 16'h0 //% 出力反転 ) ( input CLK, //% クロック input RESET_N, //% リセット(負論理) input IN_CLR, //% 入力CRC初期化 input IN_ENA, //% 入力イネーブル input [DATA_WIDTH-1:0] IN_DATA, //% 入力データ output [CRC_WIDTH-1:0] OUT_CRC //% CRC演算結果出力 ); reg [CRC_WIDTH-1:0] crc_reg; /*! CRC演算関数 */ function [CRC_WIDTH-1:0] crc_calc; input [CRC_WIDTH-1:0] in_crc; input in_data; integer i; begin for (i = 0; i < CRC_WIDTH; i = i + 1) begin crc_calc[i] = 1'b0; if (i != 0) crc_calc[i] = in_crc[i-1]; if (POLYNOMIAL[i]) crc_calc[i] = crc_calc[i] ^ in_crc[CRC_WIDTH-1] ^ in_data; end end endfunction /*! CRC演算ループ関数 */ function [CRC_WIDTH-1:0] crc_calc_l; input [CRC_WIDTH-1:0] in_crc; input [DATA_WIDTH-1:0] in_data; integer i; begin crc_calc_l = in_crc; for (i = 0; i < DATA_WIDTH; i = i + 1) begin crc_calc_l = crc_calc(crc_calc_l, in_data[(DATA_WIDTH-1)-i]); end end endfunction /*! CRCレジスタ */ always @(posedge CLK) begin: crc_reg_l if (!RESET_N) crc_reg <= SEED_VAL; else begin if (IN_CLR) crc_reg <= SEED_VAL; else if (IN_ENA) crc_reg <= crc_calc_l(crc_reg, IN_DATA); end end assign OUT_CRC = crc_reg ^ OUTPUT_EXOR; endmodule
SDカードで使用しているCRC-7、CRC-16-CCITT、およびCRC-64-ECMA-182でシミュレーションしてみました。
[CRC-7 8ビット入力]
parameter DATA_WIDTH = 8;
parameter CRC_WIDTH = 7;
parameter [CRC_WIDTH-1:0] POLYNOMIAL = 7’h09;
parameter [CRC_WIDTH-1:0] SEED_VAL = 7’h0;
parameter [CRC_WIDTH-1:0] OUTPUT_EXOR = 7’h0;
SDのSPIコマンド セットCMD8 {48,00,00,01,AA}を入力しています。CRC-7の結果は7’h43となります。
7’h43を先頭詰めの8bitにすると8’h86になるので、8’h86を入力すると、CRC-7の結果は0となります。
[CRC-7 1ビット入力]
parameter DATA_WIDTH = 1;
parameter CRC_WIDTH = 7;
parameter [CRC_WIDTH-1:0] POLYNOMIAL = 7’h09;
parameter [CRC_WIDTH-1:0] SEED_VAL = 7’h0;
parameter [CRC_WIDTH-1:0] OUTPUT_EXOR = 7’h0;
同じくSPIコマンド セットCMD8 {48,00,00,01,AA}を入力しています。
結果は、当然ですが8ビット入力時と同じです。
[CRC-16 8ビット入力]
parameter DATA_WIDTH = 8;
parameter CRC_WIDTH = 16;
parameter [CRC_WIDTH-1:0] POLYNOMIAL = 16’h1021;
parameter [CRC_WIDTH-1:0] SEED_VAL = 16’h0;
parameter [CRC_WIDTH-1:0] OUTPUT_EXOR = 16’h0;
適当な値で{21,39,71,4B}を入力しています。CRC-16の結果は16’hD809となります。
{D8,09}を入力すると、CRC-16の結果は0となります。
[CRC-16 8ビット入力 シード値FFFF CRC出力反転]
parameter DATA_WIDTH = 8;
parameter CRC_WIDTH = 16;
parameter [CRC_WIDTH-1:0] POLYNOMIAL = 16’h1021;
parameter [CRC_WIDTH-1:0] SEED_VAL = 16’h0;
parameter [CRC_WIDTH-1:0] OUTPUT_EXOR = 16’h0;
適当な値で{21,39,71,4B}を入力しています。CRC-16の結果は16’hA336となります。
16’hA336をビット反転すると16’h5CC9となりますので5C,C9}を入力すると、CRC-16の結果は16’hFFFFとなります。
[CRC-64-ECMA-182 8ビット入力]
parameter DATA_WIDTH = 8;
parameter CRC_WIDTH = 64;
parameter [CRC_WIDTH-1:0] POLYNOMIAL = 64’h42F0E1EBA9EA3693;
parameter [CRC_WIDTH-1:0] SEED_VAL = 64’h0;
parameter [CRC_WIDTH-1:0] OUTPUT_EXOR = 64’h0;
適当な値で{DE,AD,BE,EF}を入力しています。CRC-64の結果は64’h3DF370C78407B980となります。
{3D,F3,70,C7,84,07,B9,80}を入力すると、CRC-64の結果は0となります。