CRC処理をロジック化
CRCをVerilogでLogic化しました。
通信系や制御系でCRCを設計していましたが、特定用途だったため、生成多項式も固定、bit幅も固定、右/左送りも固定だったため、汎用性の高いCRCを作成してみました。
1クロックで処理するため、半導体の設計では定番に近い構成になると思います。
汎用性が高いと言っても、検証は入力データ8bit、CRCは8,16,32で行い、合成/マッピングは、入力データ8bit、CRC16bitで行いました。
機能仕様
- 入力データは最大32bit*1の入力が可能。
- CRC結果は最大32bit*2の出力が可能。
- 生成多項式はレジスタで設定可能。
- CRCの初期値はレジスタで設定可能。
- CRC結果の反転が可能。
- 入力データのMSB/LSBのbit反転が設定可能。
- CRC結果のMSB/LSBのbit反転が可能。
- 各レジスタ(上記3~7のレジスタ)のリセット時の初期値は、parameterで設定可能。
- parameter PRM_FIXが"0"の場合、レジスタが有効となり、"1"の場合はレジスタ(上記3~7のレジスタ)はAvalon-MMからの設定は不可となり、パラメータ設定のみ有効となります。(ただし、リードは可能)
操作仕様
【parameter PRM_FIX=0】
1、レジスタに初期設定を行います。(アドレス=0x10以降)
設定するレジスタは以下の通りです。
0x10:CRC初期値
0x14:生成多項式
0x18:CRC値反転
0x1C:bit反転([0]=入力データ、[1]=CRC結果)
※CRC初期値、生成多項式、CRC値反転のレジスタbit幅は、
parameter CRC_WIDTHの設定値に依存します。
2、アドレス0x00にライトを行います。
これにより、CRC結果がアドレス0x10で設定した値(CRC初期値)に
初期化します。
尚、アドレス0x00にライトするデータは任意の値で構いません。
3、アドレス0x04に入力データをライトします。
ライトする度にライトデータをCRC処理します。
尚、有効bit幅は、parameter DAT_WIDTHの設定値に依存します。
4、アドレス0x08をリードします。
上記3でライトした分のデータのCRC結果がリードできます。
尚、有効bit幅は、parameter CRC_WIDTHの設定値に依存します。
【parameter PRM_FIX=1】
CRC処理で必要な設定値はparameterで設定した値に固定されるため、
上記「【parameter PRM_FIX=0】」の場合の2~4の手順でCRC結果が得られます。
IOタイミング
Avalon-MM I/F信号
処理内容
入力データ(複数ビット)からCRC結果を1クロックで求めるため、一般的なCRC回路を並列化します。
以下に一般的なCRC回路例を示します。(1bit毎に処理を行う回路)
尚、例として使用する「一般的なCRC回路」の生成多項式は、以下の通りです。
上記一般的なCRC回路を入力ビット毎に展開し、使用します。
以下が、上記回路を並列で処理した場合の回路構成となります。
尚、図中では、入力データ(in_dat[7:0])=0x82を入力することにより、CRC結果(res_crc[7:0])=0x87が得られます。
CRC結果=0x87が得られる計算式は以下の通りです。
※上記回路の演算方法と下記計算方法は少し違います。
上記回路では生成多項式の"1"の時だけXORを行い、
下記計算式は入力データ又はXOR結果の上位ビットが"1"の時だけXORを行います。
補足)
回路構成の場合、8bit分のパディングは不要となります。
(演算回数を増やす必要はありません。)
ソースコード
verilog-HDLのソースコードは以下の通りです。
モジュールトップ名は、「NML_CRC」となります。
module NML_CRC #( parameter P_IND_BIT_WIDTH = 8 , // 入力データのbit幅 parameter P_CRC_BIT_WIDTH = 16 , // CRCのbit幅 (32まで) parameter P_INI_CRCV = 16'h0000 , // レジスタ初期値 CRC初期値 parameter P_INI_POLY = 16'h1021 , // レジスタ初期値 生成多項式 parameter P_INI_XOROUT = 16'h0000 , // レジスタ初期値 CRC値反転 parameter P_INI_REFI = 1'b0 , // レジスタ初期値 入力bit反転(0:正転 1:反転) parameter P_INI_REFO = 1'b0 , // レジスタ初期値 CRC bit反転(0:正転 1:反転) parameter P_PRM_FIX = 1'b0 // モード レジスタ固定(1:上記P_INI_*のみ有効[書き込みできない]) ) ( input wire CLK , // システムクロック input wire RESET_N , // システムリセット input wire AVA_WEN , // Avalon-MM(Slave側) ライトイネーブル input wire AVA_REN , // Avalon-MM(Slave側) リードイネーブル input wire [ 5:0] AVA_ADD , // Avalon-MM(Slave側) リード/ライトアドレス input wire [31:0] AVA_WDT , // Avalon-MM(Slave側) ライトデータ output wire AVA_WIT , // Avalon-MM(Slave側) ウェイトリクエスト output reg AVA_RVL , // Avalon-MM(Slave側) リードデータイネーブル output reg [31:0] AVA_RDT , // Avalon-MM(Slave側) リードデータ output reg [31:0] MON_CRC // CRC結果 ); // @@ // @@ Avalon-MM I/F // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reg in_ava_wen; reg in_ava_ren; reg [ 5:0] in_ava_add; reg [31:0] in_ava_wdt; wire ot_ava_wit; wire ot_ava_rvl; wire [31:0] ot_ava_rdt; always @( posedge CLK or negedge RESET_N ) begin if( ~RESET_N ) begin in_ava_wen <= 1'b0; in_ava_ren <= 1'b0; in_ava_add <= 6'h00; in_ava_wdt <= 32'd0; end else begin in_ava_wen <= AVA_WEN; in_ava_ren <= AVA_REN; in_ava_add <= AVA_ADD; in_ava_wdt <= AVA_WDT; end end always @( posedge CLK or negedge RESET_N ) begin if( ~RESET_N ) begin AVA_RVL <= 1'b0; AVA_RDT <= 32'd0; end else begin AVA_RVL <= ot_ava_rvl; AVA_RDT <= ot_ava_rdt; end end assign AVA_WIT = ( AVA_REN & ot_ava_wit ); // ++ アクセス制御 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ wire acc_wen = in_ava_wen; reg acc_ren; wire [ 3:0] acc_add = in_ava_add[5:2]; wire [31:0] acc_wdt = in_ava_wdt; always @( posedge CLK or negedge RESET_N ) begin if( ~RESET_N ) acc_ren <= 1'b0; else acc_ren <= ( AVA_REN & (~in_ava_ren) ) ? 1'b1 : 1'b0; end // ++ リード/ライト制御 (デコード) // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ wire ade_ini = ( acc_add==4'h0 ); // [R/W] 初期化 wire ade_dat = ( acc_add==4'h1 ); // [R/W] 入力データ wire ade_crc = ( acc_add==4'h2 ); // [ R ] CRCデータ wire ade_prm_info = ( acc_add==4'h3 ); // [ R ] パラメータ情報 wire ade_crc_init = ( acc_add==4'h4 ); // [R/W] CRC初期値 wire ade_crc_poly = ( acc_add==4'h5 ); // [R/W] 生成多項式 wire ade_crc_xoro = ( acc_add==4'h6 ); // [R/W] CRC値反転 wire ade_crc_refl = ( acc_add==4'h7 ); // [R/W] bit反転 wire set_ini = ( acc_wen & ade_ini ); wire set_dat = ( acc_wen & ade_dat ); wire set_crc = 1'b0; wire set_prm_info = 1'b0; wire set_crc_init = ( acc_wen & ade_crc_init & (P_PRM_FIX[0]==1'b0) ); wire set_crc_poly = ( acc_wen & ade_crc_poly & (P_PRM_FIX[0]==1'b0) ); wire set_crc_xoro = ( acc_wen & ade_crc_xoro & (P_PRM_FIX[0]==1'b0) ); wire set_crc_refl = ( acc_wen & ade_crc_refl & (P_PRM_FIX[0]==1'b0) ); wire get_ini = ( acc_ren & ade_ini ); wire get_dat = ( acc_ren & ade_dat ); wire get_crc = ( acc_ren & ade_crc ); wire get_prm_info = ( acc_ren & ade_prm_info ); wire get_crc_init = ( acc_ren & ade_crc_init ); wire get_crc_poly = ( acc_ren & ade_crc_poly ); wire get_crc_xoro = ( acc_ren & ade_crc_xoro ); wire get_crc_refl = ( acc_ren & ade_crc_refl ); // ++ レジスタ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ----- [制御系レジスタ] ----- reg reg_ini_enb; // CRC結果初期化用イネーブル reg reg_dat_enb; // 入力データ用イネーブル reg [31:0] reg_dat; // 入力データ用レジスタ wire [31:0] bit_dat = { {32-P_IND_BIT_WIDTH{1'b0}} , {P_IND_BIT_WIDTH{1'b1}} }; always @( posedge CLK or negedge RESET_N ) begin if( ~RESET_N ) reg_ini_enb <= 1'b0; else reg_ini_enb <= set_ini; end always @( posedge CLK or negedge RESET_N ) begin if( ~RESET_N ) reg_dat_enb <= 1'b0; else reg_dat_enb <= set_dat; end always @( posedge CLK or negedge RESET_N ) begin if( ~RESET_N ) reg_dat <= 32'd0; else if( set_dat ) reg_dat <= acc_wdt & bit_dat; else reg_dat <= reg_dat; end // ----- [パラメータ系レジスタ] ----- reg [31:0] reg_prm_crcv ; reg [31:0] reg_prm_poly ; reg [31:0] reg_prm_xorout; reg [ 1:0] reg_prm_refl; wire [31:0] bit_crc = { {32-P_CRC_BIT_WIDTH{1'b0}} , {P_CRC_BIT_WIDTH{1'b1}} }; always @( posedge CLK or negedge RESET_N ) begin if( ~RESET_N ) begin reg_prm_crcv <= { {32-P_CRC_BIT_WIDTH{1'b0}} , P_INI_CRCV[P_CRC_BIT_WIDTH-1:0] }; reg_prm_poly <= { {32-P_CRC_BIT_WIDTH{1'b0}} , P_INI_POLY[P_CRC_BIT_WIDTH-1:0] }; reg_prm_xorout <= { {32-P_CRC_BIT_WIDTH{1'b0}} , P_INI_XOROUT[P_CRC_BIT_WIDTH-1:0] }; reg_prm_refl[0] <= P_INI_REFI[0]; reg_prm_refl[1] <= P_INI_REFO[0]; end else begin reg_prm_crcv <= (set_crc_init) ? acc_wdt & bit_crc : reg_prm_crcv ; reg_prm_poly <= (set_crc_poly) ? acc_wdt & bit_crc : reg_prm_poly ; reg_prm_xorout <= (set_crc_xoro) ? acc_wdt & bit_crc : reg_prm_xorout; reg_prm_refl <= (set_crc_refl) ? acc_wdt[1:0] : reg_prm_refl ; end end // ----- [リードオンリー系レジスタ] ----- wire [31:0] res_crc; reg [31:0] reg_crc; wire [31:0] reg_prm_info = { 15'd0 , P_PRM_FIX[0] // モード , P_CRC_BIT_WIDTH[7:0] // CRCのbit幅 , P_IND_BIT_WIDTH[7:0]}; // 入力データのbit幅 always @( posedge CLK or negedge RESET_N ) begin if( ~RESET_N ) reg_crc <= { {32-P_CRC_BIT_WIDTH{1'b0}} , P_INI_CRCV[P_CRC_BIT_WIDTH-1:0] }; else reg_crc <= { {32-P_CRC_BIT_WIDTH{1'b0}} , res_crc[ P_CRC_BIT_WIDTH-1:0] }; end always @( posedge CLK or negedge RESET_N ) begin if( ~RESET_N ) MON_CRC <= { {32-P_CRC_BIT_WIDTH{1'b0}} , P_INI_CRCV[P_CRC_BIT_WIDTH-1:0] }; else MON_CRC <= reg_crc; end // ++ レジスタリード制御 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ assign ot_ava_rvl = ( acc_ren ); assign ot_ava_rdt = ( ( get_ini ) ? { {31{1'b0}}, reg_ini_enb } : 32'd0 ) | ( ( get_dat ) ? reg_dat : 32'd0 ) | ( ( get_crc ) ? reg_crc : 32'd0 ) | ( ( get_prm_info ) ? reg_prm_info : 32'd0 ) | ( ( get_crc_init ) ? reg_prm_crcv : 32'd0 ) | ( ( get_crc_poly ) ? reg_prm_poly : 32'd0 ) | ( ( get_crc_xoro ) ? reg_prm_xorout: 32'd0 ) | ( ( get_crc_refl ) ? { {30{1'b0}}, reg_prm_refl} : 32'd0 ) ; assign ot_ava_wit = ~ot_ava_rvl; // @@ // @@ CRC calculation core // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ NML_CRC_CORE #( .P_IND_BIT_WIDTH(P_IND_BIT_WIDTH ), // parameter P_IND_BIT_WIDTH = 8 , // 入力データのbit幅 .P_CRC_BIT_WIDTH(P_CRC_BIT_WIDTH ), // parameter P_CRC_BIT_WIDTH = 16 , // CRCのbit幅 .P_INI_CRCV (P_INI_CRCV ) // parameter P_INI_CRCV = 16'h0000 // レジスタ初期値 CRC初期値 ) UnCORE( .CLK (CLK ), // input wire CLK .RESET_N (RESET_N ), // input wire RESET_N .INIT (reg_ini_enb ), // input wire INIT .ENABLE (reg_dat_enb ), // input wire ENABLE .DAT_REFL (reg_prm_refl[ 0]), // input wire DAT_REFL .CRC_INIT (reg_prm_crcv[ P_CRC_BIT_WIDTH-1:0]), // input wire [P_CRC_BIT_WIDTH-1:0] CRC_INIT .CRC_POLY (reg_prm_poly[ P_CRC_BIT_WIDTH-1:0]), // input wire [P_CRC_BIT_WIDTH-1:0] CRC_POLY .CRC_XORO (reg_prm_xorout[P_CRC_BIT_WIDTH-1:0]), // input wire [P_CRC_BIT_WIDTH-1:0] CRC_XORO .CRC_REFL (reg_prm_refl[ 1]), // input wire CRC_REFL .DAT (reg_dat[ P_IND_BIT_WIDTH-1:0]), // input wire [P_IND_BIT_WIDTH-1:0] DAT .CRC (res_crc[ P_CRC_BIT_WIDTH-1:0]) // output wire [P_CRC_BIT_WIDTH-1:0] CRC ); endmodule // ** // ** CRC Core // ** // ***************************************************************************** module NML_CRC_CORE #( parameter P_IND_BIT_WIDTH = 8 , // 入力データのbit幅 parameter P_CRC_BIT_WIDTH = 16 , // CRCのbit幅(32まで) parameter P_INI_CRCV = 16'h0000 // レジスタ初期値 CRC初期値 ) ( input wire CLK , // システムクロック input wire RESET_N , // システムリセット input wire INIT , // CRC結果初期化イネーブル input wire ENABLE , // 入力データイネーブル input wire DAT_REFL , // 入力データbit反転 input wire [P_CRC_BIT_WIDTH-1:0] CRC_INIT , // CRC結果初期値 input wire [P_CRC_BIT_WIDTH-1:0] CRC_POLY , // 生成多項式 input wire [P_CRC_BIT_WIDTH-1:0] CRC_XORO , // CRC値反転 input wire CRC_REFL , // CRC結果bit反転 input wire [P_IND_BIT_WIDTH-1:0] DAT , // 入力データ output wire [P_CRC_BIT_WIDTH-1:0] CRC // CRC結果 ); // ++ // ++ Input FF // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ reg in_enb; reg [P_IND_BIT_WIDTH-1:0] in_dat; always @( posedge CLK or negedge RESET_N ) begin if( ~RESET_N ) in_enb <= 1'b0; else in_enb <= ENABLE; end wire [P_IND_BIT_WIDTH-1:0] dat_inv; NML_CRC_INVERT #(.WIDTH(P_IND_BIT_WIDTH)) UnDAT_INVERT(.DI(DAT),.DO(dat_inv)); always @( posedge CLK or negedge RESET_N ) begin if( ~RESET_N ) in_dat <= {P_IND_BIT_WIDTH{1'b0}}; else if( ENABLE ) in_dat <= ( DAT_REFL ) ? dat_inv : DAT; else in_dat <= in_dat; end // ++ // ++ CRC calculation // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ logic [P_CRC_BIT_WIDTH-1:0] pre_crc; logic [P_CRC_BIT_WIDTH-1:0] out_crc; logic [P_CRC_BIT_WIDTH-1:0] res_crc[0:P_IND_BIT_WIDTH]; generate genvar p; assign res_crc[(P_IND_BIT_WIDTH-1)-0+1] = pre_crc; for(p=0;p<P_IND_BIT_WIDTH;p=p+1) begin : GenDatBit NML_CRC_CALC #( .P_CRC_BIT_WIDTH(P_CRC_BIT_WIDTH) // parameter P_CRC_BIT_WIDTH = 16 // CRCビット幅 ) UnCRC_CALC( .POL_CRC (CRC_POLY ), // input logic [P_CRC_BIT_WIDTH-1:0] POL_CRC , // 生成多項式 .PRE_CRC (res_crc[(P_IND_BIT_WIDTH-1)-p+1] ), // input logic [P_CRC_BIT_WIDTH-1:0] PRE_CRC , // 前回のCRC結果 .BIT_DAT ( in_dat[(P_IND_BIT_WIDTH-1)-p] ), // input logic BIT_DAT , // 入力値 .RES_CRC (res_crc[(P_IND_BIT_WIDTH-1)-p] ) // output logc [P_CRC_BIT_WIDTH-1:0] RES_CRC // CRC結果 ); end endgenerate always @( posedge CLK or negedge RESET_N ) begin if( ~RESET_N ) pre_crc <= P_INI_CRCV; else if( INIT ) pre_crc <= CRC_INIT; else if( in_enb ) pre_crc <= res_crc[0]; else pre_crc <= pre_crc; end wire [P_CRC_BIT_WIDTH-1:0] crc_inv; NML_CRC_INVERT #(.WIDTH(P_CRC_BIT_WIDTH)) UnCRC_INVERT(.DI(pre_crc),.DO(crc_inv)); always @( posedge CLK or negedge RESET_N ) begin if( ~RESET_N ) out_crc <= P_INI_CRCV; else if( CRC_REFL ) out_crc <= crc_inv ^ CRC_XORO; else out_crc <= pre_crc ^ CRC_XORO; end assign CRC = out_crc; endmodule // ** // ** CRC generation // ** CRC bit毎に計算 // ***************************************************************************** module NML_CRC_CALC #( parameter P_CRC_BIT_WIDTH = 16 // CRCビット幅 ) ( input logic [P_CRC_BIT_WIDTH-1:0] POL_CRC , // 生成多項式 input logic [P_CRC_BIT_WIDTH-1:0] PRE_CRC , // 前回のCRC結果 input logic BIT_DAT , // 入力値 output logic [P_CRC_BIT_WIDTH-1:0] RES_CRC // CRC結果 ); logic [P_CRC_BIT_WIDTH :0] cyc_crc; logic [P_CRC_BIT_WIDTH-1:0] pre_xor; assign cyc_crc = {PRE_CRC[P_CRC_BIT_WIDTH-1:0],1'b0}; generate genvar p; for(p=0;p<P_CRC_BIT_WIDTH;p=p+1) begin : GenCrcCalc assign pre_xor[p] = BIT_DAT ^ cyc_crc[P_CRC_BIT_WIDTH] ^ cyc_crc[p]; assign RES_CRC[p] = ( POL_CRC[p] ) ? pre_xor[p] : cyc_crc[p] ; end endgenerate endmodule // ** // ** Bit反転 // ** // ***************************************************************************** module NML_CRC_INVERT #( parameter WIDTH = 16 // Bit Width ) ( input logic [WIDTH-1:0] DI , output logic [WIDTH-1:0] DO ); generate genvar p; for(p=0;p<WIDTH;p=p+1) begin : GenInvert assign DO[p] = DI[(WIDTH-1)-p]; end endgenerate endmodule
上記ソースは、Avalon-MMでI/Fを行っていますが、CRCの演算のコアな部分は、モジュール「NML_CRC_CORE」となります。
従って、別Logicに実装したい場合は、モジュール「NML_CRC_CORE」を使用するだけで良いようになっています。
単体検証
モジュールNML_CRCをトップとしたシミュレーション環境を作成し、検証を行いました。
検証方法
入力データは8bitデータとし、0x31~0x39の9Byte入力します。
CRC結果は、8bit、16bit、32bitの3ケースで検証を行います。
得られたCRC結果は、期待値と比較します。
期待値は、ネット上にあったサイト(CRCプログラム)から得た値と比較します。
検証パターン
検証パターン(CRC処理の設定値と期待値)は以下の通りとなります。
8bitCRC:13パターン
16bitCRC:24パターン
32bitCRC:9パターン
検証結果
期待値と一致しました。
ModelSimでシミュレーションを行い、得られたCRC結果と期待値とを比較し、Log表示させたものを以下に示します。(抜粋したもの)
※Log中の「Error」が期待値との不一致数を示します。
Log中では"0"なので、不一致数は0です。
CRC32の時のシミュレーション波形は以下の通りです。
尚、入力データは連続で入力しています。
テストベンチソース
単体検証でのテストベンチソースは以下の通りです。
`timescale 1ns/1ps module TB_TOP; parameter P_IND_BIT_WIDTH = 8 ; // 入力データのbit幅 parameter P_CRC_BIT_WIDTH = 16 ; // CRCのbit幅 (32まで) parameter P_INI_CRCV = 16'h0000 ; // レジスタ初期値 CRC初期値 parameter P_INI_POLY = 16'h1021 ; // レジスタ初期値 生成多項式 parameter P_INI_XOROUT = 16'h0000 ; // レジスタ初期値 CRC値反転 parameter P_INI_REFI = 1'b0 ; // レジスタ初期値 入力bit反転(0:正転 1:反転) parameter P_INI_REFO = 1'b0 ; // レジスタ初期値 CRC bit反転(0:正転 1:反転) parameter P_PRM_FIX = 1'b0 ; // モード レジスタ固定(1:上記P_INI_*のみ有効[書き込みできない]) integer PERIOD = 0; reg CLK = 0; // システムクロック reg RESET_N = 0; // システムリセット reg AVA_WEN = 0; // Avalon-MM ライトイネーブル reg AVA_REN = 0; // Avalon-MM リードイネーブル reg [ 5:0] AVA_ADD = 0; // Avalon-MM リード/ライトアドレス reg [31:0] AVA_WDT = 0; // Avalon-MM ライトデータ wire AVA_WIT ; // Avalon-MM ウェイトリクエスト wire AVA_RVL ; // Avalon-MM リードデータイネーブル wire [31:0] AVA_RDT ; // Avalon-MM リードデータ wire [31:0] MON_CRC ; // CRC結果 // ++ タイミング設定 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Clock波形 real tcCLK = 20.000; real tpCLK = 5.000; real tnCLK = 15.000; // -- // -- テストシナリオ // ------------------------------------------------------------------- //`define CRC_8BIT `define CRC_32BIT //`define CRC_16BIT `include "TB_EXP.sv" integer TypeNum = 0; T_EXP CRC_TYPE; integer error = 0; `ifdef CRC_8BIT defparam TARGET.P_CRC_BIT_WIDTH = 8; `elsif CRC_32BIT defparam TARGET.P_CRC_BIT_WIDTH = 32; `else defparam TARGET.P_CRC_BIT_WIDTH = 16; `endif integer BurstAdd; reg [31:0] BurstMem[0:256]; reg [31:0] RdData; initial begin #0; repeat(10) @(PERIOD); @(posedge CLK); #1 RESET_N = 1; repeat(10) @(PERIOD); // ** 初期値リード // ***************************************************** RdCPU('h00,RdData); // [R/W] 初期化 RdCPU('h04,RdData); // [R/W] 入力データ RdCPU('h08,RdData); // [ R ] CRCデータ RdCPU('h0C,RdData); // [ R ] パラメータ固定モード RdCPU('h10,RdData); // [R/W] CRC初期値 RdCPU('h14,RdData); // [R/W] 生成多項式 RdCPU('h18,RdData); // [R/W] CRC値反転 RdCPU('h1C,RdData); // [R/W] bit反転 // ** CRC処理 // ***************************************************** for(BurstAdd=0;BurstAdd<9;BurstAdd=BurstAdd+1) BurstMem[BurstAdd] = 'h31+BurstAdd; `ifdef CRC_8BIT $display(" <<<<< CRC 8bit >>>>> "); for(TypeNum=0;TypeNum<CRC08_NUM;TypeNum=TypeNum+1) begin CRC_TYPE = CRC08_TYP[TypeNum]; `elsif CRC_32BIT $display(" <<<<< CRC 32bit >>>>> "); for(TypeNum=0;TypeNum<CRC32_NUM;TypeNum=TypeNum+1) begin CRC_TYPE = CRC32_TYP[TypeNum]; `else $display(" <<<<< CRC 16bit >>>>> "); for(TypeNum=0;TypeNum<CRC16_NUM;TypeNum=TypeNum+1) begin CRC_TYPE = CRC16_TYP[TypeNum]; `endif WrCPU('h10,CRC_TYPE.INIT); // [R/W] CRC初期値 WrCPU('h14,CRC_TYPE.POLY); // [R/W] 生成多項式 WrCPU('h18,CRC_TYPE.XORO); // [R/W] CRC値反転 WrCPU('h1C,CRC_TYPE.REFL); // [R/W] bit反転 WrCPU('h00,'h0000_0000); // [R/W] 初期化 WrCPU_BURST('h04, 9); // [R/W] 入力データ repeat(20) @(PERIOD); RdCPU('h08,RdData); // [ R ] CRCデータ if( CRC_TYPE.RSLT !== RdData ) error = error + 1; $display(" >>> Type[%d](Error=%d) : %h(Exp) %h(Rd) [Parameter %p]",TypeNum[7:0],error[7:0],CRC_TYPE.RSLT,RdData,CRC_TYPE); repeat(20) @(PERIOD); end if( error != 0 ) $display(" ##### Error : %d",error); else $display(" >>>>> Error : %d",error); // ** 終了 // ***************************************************** repeat(20) @(PERIOD); $finish(); end // -- // -- Clock生成 // ------------------------------------------------------------------- initial begin forever begin fork #(tpCLK) CLK = 1; #(tnCLK) CLK = 0; #(tcCLK) PERIOD = PERIOD+1; join end end // -- // -- ターゲットのインスタンス // ------------------------------------------------------------------- NML_CRC #( .P_IND_BIT_WIDTH(P_IND_BIT_WIDTH), // parameter P_IND_BIT_WIDTH = 8 , // 入力データのbit幅 .P_CRC_BIT_WIDTH(P_CRC_BIT_WIDTH), // parameter P_CRC_BIT_WIDTH = 16 , // CRCのbit幅 (32まで) .P_INI_CRCV (P_INI_CRCV ), // parameter P_INI_CRCV = 16'h0000 , // レジスタ初期値 CRC初期値 .P_INI_POLY (P_INI_POLY ), // parameter P_INI_POLY = 16'h1021 , // レジスタ初期値 生成多項式 .P_INI_XOROUT (P_INI_XOROUT ), // parameter P_INI_XOROUT = 16'h0000 , // レジスタ初期値 CRC値反転 .P_INI_REFI (P_INI_REFI ), // parameter P_INI_REFI = 1'b0 , // レジスタ初期値 入力bit反転(0:正転 1:反転) .P_INI_REFO (P_INI_REFO ), // parameter P_INI_REFO = 1'b0 , // レジスタ初期値 CRC bit反転(0:正転 1:反転) .P_PRM_FIX (P_PRM_FIX ) // parameter P_PRM_FIX = 1'b0 // モード レジスタ固定(1:上記P_INI_*のみ有効[書き込みできない]) ) TARGET ( .CLK (CLK ), // input wire CLK , // システムクロック .RESET_N (RESET_N ), // input wire RESET_N , // システムリセット .AVA_WEN (AVA_WEN ), // input wire AVA_WEN , // Avalon-MM(Slave側) ライトイネーブル .AVA_REN (AVA_REN ), // input wire AVA_REN , // Avalon-MM(Slave側) リードイネーブル .AVA_ADD (AVA_ADD ), // input wire [ 5:0] AVA_ADD , // Avalon-MM(Slave側) リード/ライトアドレス .AVA_WDT (AVA_WDT ), // input wire [31:0] AVA_WDT , // Avalon-MM(Slave側) ライトデータ .AVA_WIT (AVA_WIT ), // output wire AVA_WIT , // Avalon-MM(Slave側) ウェイトリクエスト .AVA_RVL (AVA_RVL ), // output reg AVA_RVL , // Avalon-MM(Slave側) リードデータイネーブル .AVA_RDT (AVA_RDT ), // output reg [31:0] AVA_RDT , // Avalon-MM(Slave側) リードデータ .MON_CRC (MON_CRC ) // output reg [31:0] MON_CRC // CRC結果 ); // -- // -- Task // ------------------------------------------------------------------- task WrCPU( input [31:0] Addr, input [31:0] Data ); reg Comp; begin @(posedge CLK) begin AVA_WEN<=1; AVA_ADD<=Addr; AVA_WDT<=Data; end @(posedge CLK) begin AVA_WEN<=0; AVA_ADD<=0; AVA_WDT<=0; end end endtask task WrCPU_BURST( input [31:0] Addr, input integer Size ); integer addr; begin addr = 0; #1; repeat(Size) begin @(posedge CLK) begin AVA_WEN<=1; AVA_ADD<=Addr; AVA_WDT<=BurstMem[addr]; addr<=addr+1; end end @(posedge CLK) begin AVA_WEN<=0; AVA_ADD<=0; AVA_WDT<=0; end end endtask task RdCPU( input [31:0] Addr, output [31:0] Data ); reg Comp; begin Comp = 0; @(posedge CLK) begin AVA_REN<=1; AVA_ADD<=Addr; end while( Comp == 0 ) begin @(posedge CLK) begin if( AVA_WIT===1'b0 ) begin AVA_REN<=0; AVA_ADD<=0; end if( AVA_RVL===1'b1 ) begin Data <= AVA_RDT; Comp <= 1; end end #1; end end endtask endmodule
インクルードファイル"TB_EXP.sv"の内容は以下の通りです。
設定値と期待値を構造体に設定しています。
typedef struct packed { reg [31:0] INIT; reg [31:0] POLY; reg [31:0] XORO; reg [31:0] REFL; reg [31:0] RSLT; } T_EXP; integer CRC08_NUM = 13; integer CRC16_NUM = 24; integer CRC32_NUM = 9; T_EXP CRC08_TYP[0:12]; T_EXP CRC16_TYP[0:23]; T_EXP CRC32_TYP[0: 8]; initial begin CRC08_TYP[ 0] = {32'h00000000,32'h00000007,32'h00000000,32'h00000000,32'h000000F4}; CRC08_TYP[ 1] = {32'h000000FF,32'h0000001D,32'h000000FF,32'h00000000,32'h0000004B}; CRC08_TYP[ 2] = {32'h00000000,32'h0000001D,32'h00000000,32'h00000000,32'h00000037}; CRC08_TYP[ 3] = {32'h000000FF,32'h0000002F,32'h000000FF,32'h00000000,32'h000000DF}; CRC08_TYP[ 4] = {32'h000000FF,32'h0000009B,32'h00000000,32'h00000000,32'h000000DA}; CRC08_TYP[ 5] = {32'h00000000,32'h00000039,32'h00000000,32'h00000003,32'h00000015}; CRC08_TYP[ 6] = {32'h00000000,32'h000000D5,32'h00000000,32'h00000000,32'h000000BC}; CRC08_TYP[ 7] = {32'h000000FF,32'h0000001D,32'h00000000,32'h00000003,32'h00000097}; CRC08_TYP[ 8] = {32'h000000FD,32'h0000001D,32'h00000000,32'h00000000,32'h0000007E}; CRC08_TYP[ 9] = {32'h00000000,32'h00000007,32'h00000055,32'h00000000,32'h000000A1}; CRC08_TYP[10] = {32'h00000000,32'h00000031,32'h00000000,32'h00000003,32'h000000A1}; CRC08_TYP[11] = {32'h000000FF,32'h00000007,32'h00000000,32'h00000003,32'h000000D0}; CRC08_TYP[12] = {32'h00000000,32'h0000009B,32'h00000000,32'h00000003,32'h00000025}; CRC16_TYP[ 0] = {32'h00000000,32'h00001021,32'h00000000,32'h00000000,32'h000031C3}; CRC16_TYP[ 1] = {32'h00000000,32'h00008005,32'h00000000,32'h00000003,32'h0000BB3D}; CRC16_TYP[ 2] = {32'h00001D0F,32'h00001021,32'h00000000,32'h00000000,32'h0000E5CC}; CRC16_TYP[ 3] = {32'h00000000,32'h00008005,32'h00000000,32'h00000000,32'h0000FEE8}; CRC16_TYP[ 4] = {32'h0000FFFF,32'h00001021,32'h00000000,32'h00000000,32'h000029B1}; CRC16_TYP[ 5] = {32'h0000FFFF,32'h0000C867,32'h00000000,32'h00000000,32'h00004C06}; CRC16_TYP[ 6] = {32'h0000800D,32'h00008005,32'h00000000,32'h00000000,32'h00009ECF}; CRC16_TYP[ 7] = {32'h00000000,32'h00000589,32'h00000001,32'h00000000,32'h0000007E}; CRC16_TYP[ 8] = {32'h00000000,32'h00000589,32'h00000000,32'h00000000,32'h0000007F}; CRC16_TYP[ 9] = {32'h00000000,32'h00003D65,32'h0000FFFF,32'h00000003,32'h0000EA82}; CRC16_TYP[10] = {32'h00000000,32'h00003D65,32'h0000FFFF,32'h00000000,32'h0000C2B7}; CRC16_TYP[11] = {32'h0000FFFF,32'h00001021,32'h0000FFFF,32'h00000000,32'h0000D64E}; CRC16_TYP[12] = {32'h00000000,32'h00008005,32'h0000FFFF,32'h00000003,32'h000044C2}; CRC16_TYP[13] = {32'h0000FFFF,32'h00001021,32'h00000000,32'h00000003,32'h00006F91}; CRC16_TYP[14] = {32'h0000B2AA,32'h00001021,32'h00000000,32'h00000003,32'h000063D0}; CRC16_TYP[15] = {32'h00000000,32'h00008BB7,32'h00000000,32'h00000000,32'h0000D0DB}; CRC16_TYP[16] = {32'h00000000,32'h0000A097,32'h00000000,32'h00000000,32'h00000FB3}; CRC16_TYP[17] = {32'h000089EC,32'h00001021,32'h00000000,32'h00000003,32'h000026B1}; CRC16_TYP[18] = {32'h0000FFFF,32'h00008005,32'h0000FFFF,32'h00000003,32'h0000B4C8}; CRC16_TYP[19] = {32'h0000C6C6,32'h00001021,32'h00000000,32'h00000003,32'h0000BF05}; CRC16_TYP[20] = {32'h00000000,32'h00001021,32'h00000000,32'h00000003,32'h00002189}; CRC16_TYP[21] = {32'h0000FFFF,32'h00008005,32'h00000000,32'h00000003,32'h00004B37}; CRC16_TYP[22] = {32'h0000FFFF,32'h00001021,32'h0000FFFF,32'h00000003,32'h0000906E}; CRC16_TYP[23] = {32'h00000000,32'h00001021,32'h00000000,32'h00000000,32'h000031C3}; CRC32_TYP[ 0] = {32'hFFFFFFFF,32'h04C11DB7,32'hFFFFFFFF,32'h00000003,32'hCBF43926}; CRC32_TYP[ 1] = {32'hFFFFFFFF,32'h04C11DB7,32'hFFFFFFFF,32'h00000000,32'hFC891918}; CRC32_TYP[ 2] = {32'hFFFFFFFF,32'h1EDC6F41,32'hFFFFFFFF,32'h00000003,32'hE3069283}; CRC32_TYP[ 3] = {32'hFFFFFFFF,32'hA833982B,32'hFFFFFFFF,32'h00000003,32'h87315576}; CRC32_TYP[ 4] = {32'hFFFFFFFF,32'h04C11DB7,32'h00000000,32'h00000000,32'h0376E6E7}; CRC32_TYP[ 5] = {32'h00000000,32'h04C11DB7,32'hFFFFFFFF,32'h00000000,32'h765E7680}; CRC32_TYP[ 6] = {32'h00000000,32'h814141AB,32'h00000000,32'h00000000,32'h3010BF7F}; CRC32_TYP[ 7] = {32'hFFFFFFFF,32'h04C11DB7,32'h00000000,32'h00000003,32'h340BC6D9}; CRC32_TYP[ 8] = {32'h00000000,32'h000000AF,32'h00000000,32'h00000000,32'hBD0BE338}; end
Excel VBAでCRC期待値作成
今後の用途で利用できるよう、Excel VBAでも期待値となるプログラムを作成しましたので、記載します。
記載は2通りです。
1つはLogicの処理をVBAで表したものとなり、もう一つは一般的なプログラムになります。
Logicの処理をVBAで表したもの
'// '// Verilog記述をプログラム化した場合のCRCトップ関数 '// '// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Function NML_CRC( _ ByVal LngCRC_Bits As LongLong, _ ByVal LngCRC_Init As LongLong, _ ByVal LngCRC_Poly As LongLong, _ ByVal LngCRC_Xoro As LongLong, _ ByVal LngCRC_Refi As LongLong, _ ByVal LngCRC_Refo As LongLong, _ ByVal LngDAT_Bits As LongLong, _ ByVal LngDAT_Size As LongLong, _ ByVal DatArea As Range _ ) As LongLong Dim ad As LongLong '// 入力データ数 Dim DAT As LongLong '// 入力データ Dim in_dat As LongLong '// 入力データ(bit正転/反転後) Dim pre_crc As LongLong '// 1つ前のCRC結果 Dim res_crc As LongLong '// CRC結果 Dim out_crc As LongLong '// CRC結果(bit正転/反転後) pre_crc = LngCRC_Init '// CRCの初期化 ad = 0 '// データ取得用変数 While (ad < LngDAT_Size) '// DAT = NML_GET_ARRAY(DatArea, ad) '// データを取得 If (LngCRC_Refi = 1) Then '// 入力データbit反転 in_dat = NML_CRC_INVERT(LngDAT_Bits, DAT) '// 反転 Else '// in_dat = DAT '// 正転 End If '// '// ===== CRC計算コア ===== res_crc = NML_CRC_CORE(LngDAT_Bits, LngCRC_Bits, LngCRC_Poly, pre_crc, in_dat) pre_crc = res_crc ad = ad + 1 Wend If (LngCRC_Refo = 1) Then '// CRC結果bit反転 out_crc = NML_CRC_INVERT(LngCRC_Bits, pre_crc) '// 反転 Else '// out_crc = pre_crc '// 正転 End If '// '// CRC結果値の反転 NML_CRC = WorksheetFunction.Bitxor(out_crc, LngCRC_Xoro) End Function '// 入力データをbit毎 CRC計算 '// ================================================================= Function NML_CRC_CORE( _ ByVal DAT_BITS As LongLong, _ ByVal CRC_BITS As LongLong, _ ByVal CRC_POLY As LongLong, _ ByVal CRC_PRE As LongLong, _ ByVal DAT As LongLong _ ) As LongLong Dim p As LongLong '// bit位置 Dim bit_dat As LongLong '// bit値 Dim pre_crc As LongLong '// 1bit前のCRC結果 Dim res_crc As LongLong '// 1bitのCRC結果 pre_crc = CRC_PRE p = 0 While (p < DAT_BITS) bit_dat = NML_BIT(DAT, (DAT_BITS - 1) - p) res_crc = NML_CRC_CALC(CRC_BITS, CRC_POLY, pre_crc, bit_dat) pre_crc = res_crc p = p + 1 Wend NML_CRC_CORE = res_crc End Function '// CRC bit毎に計算 '// ================================================================= Function NML_CRC_CALC( _ ByVal CRC_BITS As LongLong, _ ByVal POL_CRC As LongLong, _ ByVal pre_crc As LongLong, _ ByVal bit_dat As LongLong _ ) As LongLong Dim p As LongLong Dim cyc_crc As LongLong Dim cyc_crc_p As LongLong Dim cyc_crc_m As LongLong Dim pre_xor_p As LongLong Dim POL_CRC_p As LongLong Dim RES_CRC_p As LongLong Dim res_crc As LongLong cyc_crc = pre_crc * 2 '// {PRE_CRC[CRC_BITS-1:0],1'b0} '// ----- GenCrcCalc ----- res_crc = 0 p = 0 While (p < CRC_BITS) cyc_crc_p = NML_BIT(cyc_crc, p) '// cyc_crc[p] cyc_crc_m = NML_BIT(cyc_crc, CRC_BITS) '// cyc_crc[CRC_BITS] pre_xor_p = cyc_crc_p Xor cyc_crc_m Xor bit_dat '// cyc_crc[p] ^ cyc_crc[CRC_BITS] ^ BIT_DAT POL_CRC_p = NML_BIT(POL_CRC, p) '// POL_CRC[p] If (POL_CRC_p = 1) Then '// ( POL_CRC[p] ) ? pre_xor[p] : RES_CRC_p = pre_xor_p '// Else '// RES_CRC_p = cyc_crc_p '// cyc_crc[p] ; End If '// res_crc = res_crc + NML_VAL(RES_CRC_p, p) '// RES_CRC[p] p = p + 1 Wend NML_CRC_CALC = res_crc End Function '// Bit反転 '// ================================================================= Function NML_CRC_INVERT( _ ByVal WIDTH As LongLong, _ ByVal DI As LongLong _ ) As LongLong Dim p As LongLong Dim Value As LongLong Value = 0 p = 0 While (p < WIDTH) Value = Value + NML_VAL(NML_BIT(DI, (WIDTH - 1) - p), p) p = p + 1 Wend NML_CRC_INVERT = Value End Function '// 部品 '// ================================================================= Function NML_GET_ARRAY( _ ByVal Area As Range, _ ByRef Addr As LongLong _ ) As LongLong NML_GET_ARRAY = WorksheetFunction.Index(Area, Addr + 1) End Function Function NML_BIT( _ ByVal Data As LongLong, _ ByVal Bits As LongLong _ ) As LongLong Dim aaa As LongLong aaa = WorksheetFunction.RoundDown(Data / (2 ^ Bits), 0) NML_BIT = aaa Mod 2 End Function Function NML_VAL( _ ByVal Data As LongLong, _ ByVal Bits As LongLong _ ) As LongLong NML_VAL = Data * (2 ^ Bits) End Function
一般的なプログラム
Function CRC( _ ByVal LngCRC_Bits As LongLong, _ ByVal LngCRC_Init As LongLong, _ ByVal LngCRC_Poly As LongLong, _ ByVal LngCRC_Xoro As LongLong, _ ByVal LngCRC_Refi As LongLong, _ ByVal LngCRC_Refo As LongLong, _ ByVal LngDAT_Bits As LongLong, _ ByVal LngDAT_Size As LongLong, _ ByVal DatArea As Range _ ) As LongLong Dim Base As LongLong Dim Poly As LongLong Dim Mask As LongLong Dim Jdge As LongLong Dim Refi As LongLong Dim Refo As LongLong Dim Data As LongLong Dim CRCx As LongLong Dim ad As LongLong Dim j As LongLong Base = LngCRC_Bits - LngDAT_Bits Poly = LngCRC_Poly Mask = (2 ^ LngCRC_Bits) - 1 Jdge = (2 ^ (LngCRC_Bits - 1)) Refi = LngCRC_Refi Refo = LngCRC_Refo CRCx = LngCRC_Init '// CRC初期値 ad = 0 While (ad < LngDAT_Size) Data = GetArray(DatArea, ad) '// データ取得 If (Refi = 1) Then Data = Invert(LngDAT_Bits, Data) '// 反転 End If Data = WorksheetFunction.Bitlshift(Data, Base) '// Shift CRCx = WorksheetFunction.Bitxor(CRCx, Data) j = 0 While (j < LngDAT_Bits) If (WorksheetFunction.Bitand(CRCx, Jdge) = Jdge) Then CRCx = WorksheetFunction.Bitlshift(CRCx, 1) CRCx = WorksheetFunction.Bitxor(CRCx, Poly) Else CRCx = WorksheetFunction.Bitlshift(CRCx, 1) End If CRCx = WorksheetFunction.Bitand(CRCx, Mask) j = j + 1 Wend ad = ad + 1 Wend If (Refo = 1) Then CRCx = Invert(LngCRC_Bits, CRCx) End If CRC = WorksheetFunction.Bitxor(CRCx, LngCRC_Xoro) End Function Function Invert( _ ByVal WIDTH As LongLong, _ ByVal DI As LongLong _ ) As LongLong Dim p As LongLong Dim Value As LongLong Value = 0 p = 0 While (p < WIDTH) Value = Value + NML_VAL(NML_BIT(DI, (WIDTH - 1) - p), p) p = p + 1 Wend Invert = Value End Function Function GetArray( _ ByVal Area As Range, _ ByRef Addr As LongLong _ ) As LongLong GetArray = WorksheetFunction.Index(Area, Addr + 1) End Function
実装
Veilogで作成したCRCブロックを前回のFRAM I/Fが実装されているFPGAに実装しました。
前回の構成は以下を参照ください。
nao-milk.hatenablog.com
トップソースは、以下の通りです。
module TOP( input wire RESET_N , // @@ リセット input wire CLOCK , // @@ クロック output wire FRAM_WP_N , // @@ FRAM ライトプロテクト[0:プロテクト] output wire FRAM_CS_N , // @@ FRAM SPI チップセレクト output wire FRAM_SCLK , // @@ FRAM SPI シリアルクロック output wire FRAM_MOSI , // @@ FRAM SPI シリアル出力 input wire FRAM_MISO , // @@ FRAM SPI シリアル入力 input wire SW_SLAVE , // @@ Master/Slave切替 [0:Master] input wire SW_GO , // @@ 処理イネーブル output wire LED_LOCK // @@ LED Lock ); // @@ // @@ クロック/リセット生成 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ wire cpu_rst_n; wire cpu_clk ; wire sys_rst_n; wire sys_clk ; NML_CLKRST UnCLKRST( .PAD_RST_N (RESET_N ), // input wire PAD_RST_N , // @@ 入力リセット .PAD_CLK (CLOCK ), // input wire PAD_CLK , // @@ 入力クロック .CPU_RST_N (cpu_rst_n ), // output reg CPU_RST_N , // @@ CPU用 リセット .CPU_CLK (cpu_clk ), // output wire CPU_CLK , // @@ CPU用 クロック[50MHz] .SYS_RST_N (sys_rst_n ), // output reg SYS_RST_N , // @@ System用 リセット .SYS_CLK (sys_clk ), // output wire SYS_CLK , // @@ System用 クロック[200MHz] .PLL_LOCK (LED_LOCK ) // output wire PLL_LOCK // @@ PLL LOCK ); // @@ // @@ CPU // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ wire fram_ami_wen; wire [31:0] fram_ami_add; wire [ 3:0] fram_ami_ben; wire [ 7:0] fram_ami_wdt; wire fram_asi_wen; wire fram_asi_ren; wire [ 5:0] fram_asi_add; wire [31:0] fram_asi_wdt; wire fram_asi_wit; wire fram_asi_rvl; wire [31:0] fram_asi_rdt; wire fram_cpu_irq; wire crc_asi_wen; wire crc_asi_ren; wire [ 5:0] crc_asi_add; wire [31:0] crc_asi_wdt; wire crc_asi_wit; wire crc_asi_rvl; wire [31:0] crc_asi_rdt; NML_CPU UnCPU( .clk_clk (cpu_clk ), // input wire clk_clk, // clk.clk .irq_irq (fram_cpu_irq ), // input wire [0:0] irq_irq, // irq.irq .fram_write (fram_asi_wen ), // output wire fram_write, // .write .fram_read (fram_asi_ren ), // output wire fram_read, // .read .fram_address (fram_asi_add ), // output wire [5:0] fram_address, // .address .fram_writedata (fram_asi_wdt ), // output wire [31:0] fram_writedata, // .writedata .fram_waitrequest (fram_asi_wit ), // input wire fram_waitrequest, // fram.waitrequest .fram_readdatavalid (fram_asi_rvl ), // input wire fram_readdatavalid, // .readdatavalid .fram_readdata (fram_asi_rdt ), // input wire [31:0] fram_readdata, // .readdata .fram_burstcount (/** OPEN **/ ), // output wire [0:0] fram_burstcount, // .burstcount .fram_byteenable (/** OPEN **/ ), // output wire [3:0] fram_byteenable, // .byteenable .fram_debugaccess (/** OPEN **/ ), // output wire fram_debugaccess, // .debugaccess .fram_wp_export (FRAM_WP_N ), // output wire fram_wp_export, // fram_wp.export .param_clken (1'b1 ), // input wire param_clken, // .clken .param_chipselect (1'b1 ), // input wire param_chipselect, // .chipselect .param_write ( fram_ami_wen ), // input wire param_write, // .write .param_address ( fram_ami_add[11: 2] ), // input wire [9:0] param_address, // param.address .param_byteenable ( fram_ami_ben ), // input wire [3:0] param_byteenable, // .byteenable .param_writedata ({4{fram_ami_wdt}} ), // input wire [31:0] param_writedata, // .writedata .param_readdata (/** OPEN **/ ), // output wire [31:0] param_readdata, // .readdata .port_a_export ( ), // output wire [7:0] port_a_export, // port_a.export .port_b_export ( ), // output wire [7:0] port_b_export, // port_b.export .crc_write (crc_asi_wen ), // output wire fram_write, // .write .crc_read (crc_asi_ren ), // output wire fram_read, // .read .crc_address (crc_asi_add ), // output wire [5:0] fram_address, // .address .crc_writedata (crc_asi_wdt ), // output wire [31:0] fram_writedata, // .writedata .crc_waitrequest (crc_asi_wit ), // input wire fram_waitrequest, // fram.waitrequest .crc_readdatavalid (crc_asi_rvl ), // input wire fram_readdatavalid, // .readdatavalid .crc_readdata (crc_asi_rdt ), // input wire [31:0] fram_readdata, // .readdata .crc_burstcount (/** OPEN **/ ), // output wire [0:0] fram_burstcount, // .burstcount .crc_byteenable (/** OPEN **/ ), // output wire [3:0] fram_byteenable, // .byteenable .crc_debugaccess (/** OPEN **/ ), // output wire fram_debugaccess, // .debugaccess .reset_reset_n (cpu_rst_n ) // input wire reset_reset_n // reset.reset_n ); // @@ // @@ FRAM I/F // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ NML_FRAMIF UnFRAMIF( .CPU_RST_N (cpu_rst_n ), // input wire CPU_RST_N , // @@ CPU I/F用 リセット .CPU_CLK (cpu_clk ), // input wire CPU_CLK , // @@ CPU I/F用 クロック .SYS_RST_N (sys_rst_n ), // input wire SYS_RST_N , // @@ システム動作用 リセット .SYS_CLK (sys_clk ), // input wire SYS_CLK , // @@ システム動作用 クロック .MST_SLV (SW_SLAVE ), // input wire MST_SLV , // @@ Avalon-MM Master/Slave切替 [0:Master] .PRM_ENB (SW_GO ), // input wire PRM_ENB , // @@ 処理イネーブル [1→0:OFF 0→1:ON] .PRM_DIV (4'd0 ), // input wire [ 3:0] PRM_DIV , // @@ シリアルクロック周波数設定 .PRM_POL (1'b0 ), // input wire PRM_POL , // @@ シリアルクロック極性設定 .PRM_TAK (2'd0 ), // input wire [ 1:0] PRM_TAK , // @@ シリアルデータ取り込みタイミング設定 .PRM_ACS (21'd8192 ), // input wire [20:0] PRM_ACS , // @@ アクセスバイト数 (最大値:1,048,579) .PRM_OTC (2'd3 ), // input wire [ 1:0] PRM_OTC , // @@ 出力バイト数 (最大値:3) .PRM_MSK (1'b0 ), // input wire PRM_MSK , // @@ 割り込みマスク .PRM_CLR (1'b0 ), // input wire PRM_CLR , // @@ 割り込みクリア .PRM_STA (32'h0000_0000 ), // input wire [31:0] PRM_STA , // @@ Avalon-MM(Master側) ライトベースアドレス .PRM_CMD (8'h03 ), // input wire [ 7:0] PRM_CMD , // @@ RAMコマンド .PRM_ADD (24'h00_0000 ), // input wire [23:0] PRM_ADD , // @@ FRAMアドレス .SAV_WEN (fram_asi_wen ), // input wire SAV_WEN , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) ライトイネーブル .SAV_REN (fram_asi_ren ), // input wire SAV_REN , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) リードイネーブル .SAV_ADD (fram_asi_add ), // input wire [ 5:0] SAV_ADD , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) リード/ライトイネーブル .SAV_WDT (fram_asi_wdt ), // input wire [31:0] SAV_WDT , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) ライトデータ .SAV_WIT (fram_asi_wit ), // output wire SAV_WIT , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) ウェイトリクエスト .SAV_RVL (fram_asi_rvl ), // output wire SAV_RVL , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) リードデータイネーブル .SAV_RDT (fram_asi_rdt ), // output wire [31:0] SAV_RDT , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) リードデータ .MAV_WEN (fram_ami_wen ), // output wire MAV_WEN , // @@ [CPU_CLK↑同期] Avalon-MM(Master側) ライトイネーブル .MAV_ADD (fram_ami_add ), // output wire [31:0] MAV_ADD , // @@ [CPU_CLK↑同期] Avalon-MM(Master側) ライトアドレス .MAV_BEN (fram_ami_ben ), // output wire [ 3:0] MAV_BEN , // @@ [CPU_CLK↑同期] Avalon-MM(Master側) バイトイネーブル .MAV_WDT (fram_ami_wdt ), // output wire [ 7:0] MAV_WDT , // @@ [CPU_CLK↑同期] Avalon-MM(Master側) ライトデータ .MAV_WIT (1'b0 ), // input wire MAV_WIT , // @@ [CPU_CLK↑同期] Avalon-MM(Master側) ウェイトリクエスト .CPU_IRQ (fram_cpu_irq ), // output wire CPU_IRQ , // @@ [CPU_CLK↑同期] 割り込み信号 .MON_ENB (/** OPEN **/ ), // output wire MON_ENB , // @@ [CPU_CLK↑同期] 動作モニタ [0:停止中 1:動作中] .FRAM_CS_N (FRAM_CS_N ), // output wire FRAM_CS_N , // @@ [SYS_CLK↑同期] FRAM SPI チップセレクト .FRAM_SCLK (FRAM_SCLK ), // output wire FRAM_SCLK , // @@ [SYS_CLK↑同期] FRAM SPI シリアルクロック .FRAM_MOSI (FRAM_MOSI ), // output wire FRAM_MOSI , // @@ [SYS_CLK↑同期] FRAM SPI シリアル出力 .FRAM_MISO (FRAM_MISO ), // input wire FRAM_MISO , // @@ [SYS_CLK↑同期] FRAM SPI シリアル入力 .FRAM_OUTE (/** OPEN **/ ) // output wire FRAM_OUTE // @@ [SYS_CLK↑同期] FRAM SPI 出力イネーブル[1:出力 0:Hi-Z] ); // @@ // @@ CRC // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ parameter P_IND_BIT_WIDTH = 8 ; // 入力データのbit幅 parameter P_CRC_BIT_WIDTH = 16 ; // CRCのbit幅 (32まで) parameter P_INI_CRCV = 16'h0000 ; // レジスタ初期値 CRC初期値 parameter P_INI_POLY = 16'h1021 ; // レジスタ初期値 生成多項式 parameter P_INI_XOROUT = 16'h0000 ; // レジスタ初期値 CRC値反転 parameter P_INI_REFI = 1'b0 ; // レジスタ初期値 入力bit反転(0:正転 1:反転) parameter P_INI_REFO = 1'b0 ; // レジスタ初期値 CRC bit反転(0:正転 1:反転) parameter P_PRM_FIX = 1'b0 ; // モード レジスタ固定(1:上記P_INI_*のみ有効[書き込みできない]) NML_CRC #( .P_IND_BIT_WIDTH(P_IND_BIT_WIDTH), // parameter P_IND_BIT_WIDTH = 8 , // 入力データのbit幅 .P_CRC_BIT_WIDTH(P_CRC_BIT_WIDTH), // parameter P_CRC_BIT_WIDTH = 16 , // CRCのbit幅 (32まで) .P_INI_CRCV (P_INI_CRCV ), // parameter P_INI_CRCV = 16'h0000 , // レジスタ初期値 CRC初期値 .P_INI_POLY (P_INI_POLY ), // parameter P_INI_POLY = 16'h1021 , // レジスタ初期値 生成多項式 .P_INI_XOROUT (P_INI_XOROUT ), // parameter P_INI_XOROUT = 16'h0000 , // レジスタ初期値 CRC値反転 .P_INI_REFI (P_INI_REFI ), // parameter P_INI_REFI = 1'b0 , // レジスタ初期値 入力bit反転(0:正転 1:反転) .P_INI_REFO (P_INI_REFO ), // parameter P_INI_REFO = 1'b0 , // レジスタ初期値 CRC bit反転(0:正転 1:反転) .P_PRM_FIX (P_PRM_FIX ) // parameter P_PRM_FIX = 1'b0 // モード レジスタ固定(1:上記P_INI_*のみ有効[書き込みできない]) ) UnNML_CRC ( .CLK (cpu_clk ), // input wire CLK , // システムクロック .RESET_N (cpu_rst_n ), // input wire RESET_N , // システムリセット .AVA_WEN (crc_asi_wen ), // input wire AVA_WEN , // Avalon-MM(Slave側) ライトイネーブル .AVA_REN (crc_asi_ren ), // input wire AVA_REN , // Avalon-MM(Slave側) リードイネーブル .AVA_ADD (crc_asi_add ), // input wire [ 5:0] AVA_ADD , // Avalon-MM(Slave側) リード/ライトアドレス .AVA_WDT (crc_asi_wdt ), // input wire [31:0] AVA_WDT , // Avalon-MM(Slave側) ライトデータ .AVA_WIT (crc_asi_wit ), // output wire AVA_WIT , // Avalon-MM(Slave側) ウェイトリクエスト .AVA_RVL (crc_asi_rvl ), // output reg AVA_RVL , // Avalon-MM(Slave側) リードデータイネーブル .AVA_RDT (crc_asi_rdt ), // output reg [31:0] AVA_RDT , // Avalon-MM(Slave側) リードデータ .MON_CRC (/** OPEN **/ ) // output reg [31:0] MON_CRC // CRC結果 ); endmodule
Platform Designerは以下のような実装となります。
※CRCを追加しました。
Quartusの実行
FPGAに実装し、結果は以下の通りです。
STA結果は、50MHzクロックでMetしました。
尚、前回のFRAMI/Fのみ結果は以下を参照ください。
nao-milk.hatenablog.com
Summary
Resorce
ソフトウェア
NIOSでCRCブロックにアクセスができ、CRC結果が期待値と一致するか、確認するソースは以下の通りです。
ソース
関数main
mainのソースには、前回のFRAM I/Fのヘッダーファイルも含まれています。
nao-milk.hatenablog.com
// @@ // @@ Nios program // @@ // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #define _MAIN_C_ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "system.h" #include "io.h" #include "sys/alt_irq.h" #include "altera_avalon_pio_regs.h" #include "nml_framif.h" #include "nml_crc.h" //#define DBG_PRINT(...) printf(__VA_ARGS__) #define DBG_PRINT(...) // ** // ** Main program // *************************************************************************************** int main(void){ T_CRC_INFO crc_info; int test_crc_status = -1; // == // == Test // ========================================================================= // ++ // ++ CRC TEST // +++++++++++++++++++++++++++++++++++++++++++ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x01); // Step No crc_info = NML_CRC_INFO(); if( crc_info.fix_mode == NML_CRC_FIXMODE ){ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x7F); return 1; } IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0x02); // Step No test_crc_status = NML_CRC_TEST(); // ++++++ Final Message +++++ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0xFF); if( test_crc_status == NML_CRC_TEST_OK ) printf(" >>>>> Test End : OK\n"); else if( test_crc_status == NML_CRC_TEST_SKIP ) printf(" >>>>> Test End : Skip\n"); else printf(" >>>>> Test End : %d Error\n",test_crc_status); return 0; }
nml_crc.h
// @@ // @@ Functions for CRC // @@ // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #ifndef _NML_CRC_H_ #define _NML_CRC_H_ #include "system.h" #include "io.h" // -- // -- Define // ----------------------------------------------------------------------------- #define NML_CRC_FIXMODE (1) #define NML_CRC_TEST_OK (0) #define NML_CRC_TEST_SKIP (-1) #define NML_CRC_TEST_SRCON // @@ CRC test source switch // -- // -- Register for CRC // ----------------------------------------------------------------------------- #define NML_CRC_SETREG_INI(ini) (IOWR(CRC_BASE,0x00, (ini ))) #define NML_CRC_SETREG_DAT(dat) (IOWR(CRC_BASE,0x01, (dat ))) #define NML_CRC_SETREG_INIT(init) (IOWR(CRC_BASE,0x04, (init))) #define NML_CRC_SETREG_POLY(poly) (IOWR(CRC_BASE,0x05, (poly))) #define NML_CRC_SETREG_XORO(xoro) (IOWR(CRC_BASE,0x06, (xoro))) #define NML_CRC_SETREG_REFL(refl) (IOWR(CRC_BASE,0x07, (refl))) #define NML_CRC_GETREG_INI(void) (IORD(CRC_BASE,0x00)) #define NML_CRC_GETREG_DAT(void) (IORD(CRC_BASE,0x01)) #define NML_CRC_GETREG_CRC(void) (IORD(CRC_BASE,0x02)) #define NML_CRC_GETREG_INFO(void) (IORD(CRC_BASE,0x03)) #define NML_CRC_GETREG_INIT(void) (IORD(CRC_BASE,0x04)) #define NML_CRC_GETREG_POLY(void) (IORD(CRC_BASE,0x05)) #define NML_CRC_GETREG_XORO(void) (IORD(CRC_BASE,0x06)) #define NML_CRC_GETREG_REFL(void) (IORD(CRC_BASE,0x07)) // -- // -- typdef for CRC // ----------------------------------------------------------------------------- typedef struct { unsigned char dat_bit_width; // 入力データのbit幅 unsigned char crc_bit_width; // CRC結果のbit幅 unsigned char fix_mode; // パラメータ固定モード (1:固定モード) } T_CRC_INFO; // -- // -- Function for CRC // ----------------------------------------------------------------------------- #ifdef _NML_CRC_C_ T_CRC_INFO NML_CRC_INFO(void); // ** CRC information function void NML_CRC_SETUP( // ** Initial setting unsigned int Poly , // Polynomial unsigned int Init , // Initial Value unsigned int Xoro , // Final Xor Value unsigned char Iref , // Input reflected unsigned char Oref // Result reflected ); int NML_CRC_TEST(void); // ** CRC test function #else // --------------------------------------------------------------------- extern T_CRC_INFO NML_CRC_INFO(void); // ** CRC information function extern void NML_CRC_SETUP( // ** Initial setting unsigned int Poly , // Polynomial unsigned int Init , // Initial Value unsigned int Xoro , // Final Xor Value unsigned char Iref , // Input reflected unsigned char Oref // Result reflected ); extern int NML_CRC_TEST(void); // ** CRC test function #endif #endif /* _NML_CRC_H_ */
nml_crc.c
関数NML_CRC_TESTがテスト用の関数になります。
ここでは、単体検証で行った設定値と期待値を変数に保存しておき、CRCブロックにデータを与えてCRC結果と比較します。
不一致数は変数errとなり、最後にエラー数を返します。
// @@ // @@ Functions for CRC // @@ // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #ifndef _NML_CRC_C_ #define _NML_CRC_C_ #include <stdio.h> #include <stdlib.h> #include "system.h" #include "io.h" #include "altera_avalon_pio_regs.h" #include "nml_crc.h" // -- // -- CRC information function // ----------------------------------------------------------------------------- T_CRC_INFO NML_CRC_INFO(void){ T_CRC_INFO info; unsigned int temp; // ++ Get Information // +++++++++++++++++++++++++++++++++++++++++++ temp = NML_CRC_GETREG_INFO(); info.fix_mode = (temp>>16)&0x01; info.crc_bit_width = (temp>> 8)&0xFF; info.dat_bit_width = (temp>> 0)&0xFF; return info; } // -- // -- Initial setting // ----------------------------------------------------------------------------- void NML_CRC_SETUP( unsigned int Poly , // Polynomial unsigned int Init , // Initial Value unsigned int Xoro , // Final Xor Value unsigned char Iref , // Input reflected unsigned char Oref // Result reflected ){ T_CRC_INFO info; unsigned int temp; info = NML_CRC_INFO(); if( info.fix_mode != NML_CRC_FIXMODE ){ NML_CRC_SETREG_INIT(Init); NML_CRC_SETREG_POLY(Poly); NML_CRC_SETREG_XORO(Xoro); temp = (unsigned int)((Oref&0x01)<<1) | (unsigned int)((Iref&0x01)<<0); NML_CRC_SETREG_REFL(temp); } NML_CRC_SETREG_DAT(0x00000000); NML_CRC_SETREG_INI(0x00000000); } // -- // -- CRC test function // ----------------------------------------------------------------------------- int NML_CRC_TEST(void){ #ifdef NML_CRC_TEST_SRCON #define CRC08_TEST_NUM (13) #define CRC16_TEST_NUM (24) #define CRC32_TEST_NUM ( 9) #define CRC_TEST_NUM (CRC08_TEST_NUM+CRC16_TEST_NUM+CRC32_TEST_NUM) typedef struct { unsigned int INIT; unsigned int POLY; unsigned int XORO; unsigned int REFL; unsigned int RSLT; } T_EXP; T_EXP CRC_SET_EXP[CRC_TEST_NUM] = { // ** CRC setting and expected value /***** CRC 8bit *****/ {0x00000000,0x00000007,0x00000000,0x00000000,0x000000F4} ,{0x000000FF,0x0000001D,0x000000FF,0x00000000,0x0000004B} ,{0x00000000,0x0000001D,0x00000000,0x00000000,0x00000037} ,{0x000000FF,0x0000002F,0x000000FF,0x00000000,0x000000DF} ,{0x000000FF,0x0000009B,0x00000000,0x00000000,0x000000DA} ,{0x00000000,0x00000039,0x00000000,0x00000003,0x00000015} ,{0x00000000,0x000000D5,0x00000000,0x00000000,0x000000BC} ,{0x000000FF,0x0000001D,0x00000000,0x00000003,0x00000097} ,{0x000000FD,0x0000001D,0x00000000,0x00000000,0x0000007E} ,{0x00000000,0x00000007,0x00000055,0x00000000,0x000000A1} ,{0x00000000,0x00000031,0x00000000,0x00000003,0x000000A1} ,{0x000000FF,0x00000007,0x00000000,0x00000003,0x000000D0} ,{0x00000000,0x0000009B,0x00000000,0x00000003,0x00000025} /***** CRC 16bit *****/ ,{0x00000000,0x00001021,0x00000000,0x00000000,0x000031C3} ,{0x00000000,0x00008005,0x00000000,0x00000003,0x0000BB3D} ,{0x00001D0F,0x00001021,0x00000000,0x00000000,0x0000E5CC} ,{0x00000000,0x00008005,0x00000000,0x00000000,0x0000FEE8} ,{0x0000FFFF,0x00001021,0x00000000,0x00000000,0x000029B1} ,{0x0000FFFF,0x0000C867,0x00000000,0x00000000,0x00004C06} ,{0x0000800D,0x00008005,0x00000000,0x00000000,0x00009ECF} ,{0x00000000,0x00000589,0x00000001,0x00000000,0x0000007E} ,{0x00000000,0x00000589,0x00000000,0x00000000,0x0000007F} ,{0x00000000,0x00003D65,0x0000FFFF,0x00000003,0x0000EA82} ,{0x00000000,0x00003D65,0x0000FFFF,0x00000000,0x0000C2B7} ,{0x0000FFFF,0x00001021,0x0000FFFF,0x00000000,0x0000D64E} ,{0x00000000,0x00008005,0x0000FFFF,0x00000003,0x000044C2} ,{0x0000FFFF,0x00001021,0x00000000,0x00000003,0x00006F91} ,{0x0000B2AA,0x00001021,0x00000000,0x00000003,0x000063D0} ,{0x00000000,0x00008BB7,0x00000000,0x00000000,0x0000D0DB} ,{0x00000000,0x0000A097,0x00000000,0x00000000,0x00000FB3} ,{0x000089EC,0x00001021,0x00000000,0x00000003,0x000026B1} ,{0x0000FFFF,0x00008005,0x0000FFFF,0x00000003,0x0000B4C8} ,{0x0000C6C6,0x00001021,0x00000000,0x00000003,0x0000BF05} ,{0x00000000,0x00001021,0x00000000,0x00000003,0x00002189} ,{0x0000FFFF,0x00008005,0x00000000,0x00000003,0x00004B37} ,{0x0000FFFF,0x00001021,0x0000FFFF,0x00000003,0x0000906E} ,{0x00000000,0x00001021,0x00000000,0x00000000,0x000031C3} /***** CRC 32bit *****/ ,{0xFFFFFFFF,0x04C11DB7,0xFFFFFFFF,0x00000003,0xCBF43926} ,{0xFFFFFFFF,0x04C11DB7,0xFFFFFFFF,0x00000000,0xFC891918} ,{0xFFFFFFFF,0x1EDC6F41,0xFFFFFFFF,0x00000003,0xE3069283} ,{0xFFFFFFFF,0xA833982B,0xFFFFFFFF,0x00000003,0x87315576} ,{0xFFFFFFFF,0x04C11DB7,0x00000000,0x00000000,0x0376E6E7} ,{0x00000000,0x04C11DB7,0xFFFFFFFF,0x00000000,0x765E7680} ,{0x00000000,0x814141AB,0x00000000,0x00000000,0x3010BF7F} ,{0xFFFFFFFF,0x04C11DB7,0x00000000,0x00000003,0x340BC6D9} ,{0x00000000,0x000000AF,0x00000000,0x00000000,0xBD0BE338} }; T_CRC_INFO info; unsigned int start; unsigned int limit; unsigned int num; unsigned int data; unsigned char err; info = NML_CRC_INFO(); if( (info.fix_mode != NML_CRC_FIXMODE) & (info.dat_bit_width == 8) & ( (info.crc_bit_width == 8) |(info.crc_bit_width == 16) |(info.crc_bit_width == 32) ) ); else goto SKIP; if( info.crc_bit_width == 8 ){ start = 0; limit = CRC08_TEST_NUM; } if( info.crc_bit_width == 16 ){ start = CRC08_TEST_NUM; limit = CRC16_TEST_NUM; } if( info.crc_bit_width == 32 ){ start = CRC08_TEST_NUM + CRC16_TEST_NUM; limit = CRC32_TEST_NUM; } err = 0; for(num=0;num<limit;num++){ IOWR_ALTERA_AVALON_PIO_DATA(PORT_B_BASE,start+num); // Step No NML_CRC_SETREG_INIT(CRC_SET_EXP[start+num].INIT); NML_CRC_SETREG_POLY(CRC_SET_EXP[start+num].POLY); NML_CRC_SETREG_XORO(CRC_SET_EXP[start+num].XORO); NML_CRC_SETREG_REFL(CRC_SET_EXP[start+num].REFL); NML_CRC_SETREG_INI(0x00000000); NML_CRC_SETREG_DAT(0x00000031); NML_CRC_SETREG_DAT(0x00000032); NML_CRC_SETREG_DAT(0x00000033); NML_CRC_SETREG_DAT(0x00000034); NML_CRC_SETREG_DAT(0x00000035); NML_CRC_SETREG_DAT(0x00000036); NML_CRC_SETREG_DAT(0x00000037); NML_CRC_SETREG_DAT(0x00000038); NML_CRC_SETREG_DAT(0x00000039); data = NML_CRC_GETREG_CRC(); if( data != CRC_SET_EXP[start+num].RSLT ) err++; } return err; SKIP: #endif // NML_CRC_TEST_SRCOFF return NML_CRC_TEST_SKIP; } #endif /* _NML_CRC_C_ */
協調シミュレーション
FPGAをトップとしたシミュレーションを行い、NIOSとCRCブロックの接続を確認しました。
テストベンチは FRAM I/Fの時と一緒になります。
※以下を参照してください。
nao-milk.hatenablog.com
シミュレーション波形
実行時のシミュレーション波形は以下の通りです。
シミュレーション結果
結果はError無しとなり、接続確認はOKとなります。
ModelSimでmain関数の最終行表示内容を以下に添付します。
【main関数の最終行】
// ++++++ Final Message +++++ IOWR_ALTERA_AVALON_PIO_DATA(PORT_A_BASE,0xFF); if( test_crc_status == NML_CRC_TEST_OK ) printf(" >>>>> Test End : OK\n"); else if( test_crc_status == NML_CRC_TEST_SKIP ) printf(" >>>>> Test End : Skip\n"); else printf(" >>>>> Test End : %d Error\n",test_crc_status); return 0;
【ModelSimの表示内容】