FRAMにアクセス (Verilogコーディング編)
FRAM I/Fのverilogコーディングとなります。
ブロック仕様は以下を参照ください。
nao-milk.hatenablog.com
FRAM I/Fブロック構成
ブロック構成は以下のようになります。
ソースコード
FRAM I/Fブロックトップ
CPUとのI/F用クロック(入力信号CPU_CLK)は50MHz、内部動作用クロック(入力信号SYS_CLK)は200MHzとなります。
クロック乗せ換えは、処理イネーブル(???_reg_enb)と処理イネーブル クリアパルス(???_reg_fin)のみ行い、その他の信号は動作前(処理イネーブルが"1"になる前)に確定しているため、set_false_path指定します。
// ** // ** FRAM I/F // ** // ***************************************************************************** module NML_FRAMIF( input wire CPU_RST_N , // @@ CPU I/F用 リセット input wire CPU_CLK , // @@ CPU I/F用 クロック input wire SYS_RST_N , // @@ システム動作用 リセット input wire SYS_CLK , // @@ システム動作用 クロック input wire MST_SLV , // @@ Avalon-MM Master/Slave切替 [0:Master] input wire PRM_ENB , // @@ 処理イネーブル [1→0:OFF 0→1:ON] input wire [ 3:0] PRM_DIV , // @@ シリアルクロック周波数設定 input wire PRM_POL , // @@ シリアルクロック極性設定 input wire [ 1:0] PRM_TAK , // @@ シリアルデータ取り込みタイミング設定 input wire [20:0] PRM_ACS , // @@ アクセスバイト数 (最大値:1,048,579) input wire [ 1:0] PRM_OTC , // @@ 出力バイト数 (最大値:3) input wire PRM_MSK , // @@ 割り込みマスク input wire PRM_CLR , // @@ 割り込みクリア input wire [31:0] PRM_STA , // @@ Avalon-MM(Master側) ライトベースアドレス input wire [ 7:0] PRM_CMD , // @@ RAMコマンド input wire [23:0] PRM_ADD , // @@ FRAMアドレス input wire SAV_WEN , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) ライトイネーブル input wire SAV_REN , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) リードイネーブル input wire [ 5:0] SAV_ADD , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) リード/ライトイネーブル input wire [31:0] SAV_WDT , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) ライトデータ output wire SAV_WIT , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) ウェイトリクエスト output wire SAV_RVL , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) リードデータイネーブル output wire [31:0] SAV_RDT , // @@ [CPU_CLK↑同期] Avalon-MM(Slave側) リードデータ output wire MAV_WEN , // @@ [CPU_CLK↑同期] Avalon-MM(Master側) ライトイネーブル output wire [31:0] MAV_ADD , // @@ [CPU_CLK↑同期] Avalon-MM(Master側) ライトアドレス output wire [ 3:0] MAV_BEN , // @@ [CPU_CLK↑同期] Avalon-MM(Master側) バイトイネーブル output wire [ 7:0] MAV_WDT , // @@ [CPU_CLK↑同期] Avalon-MM(Master側) ライトデータ input wire MAV_WIT , // @@ [CPU_CLK↑同期] Avalon-MM(Master側) ウェイトリクエスト output wire CPU_IRQ , // @@ [CPU_CLK↑同期] 割り込み信号 output wire MON_ENB , // @@ [CPU_CLK↑同期] 動作モニタ [0:停止中 1:動作中] output wire FRAM_CS_N , // @@ [SYS_CLK↑同期] FRAM SPI チップセレクト output wire FRAM_SCLK , // @@ [SYS_CLK↑同期] FRAM SPI シリアルクロック output wire FRAM_MOSI , // @@ [SYS_CLK↑同期] FRAM SPI シリアル出力 input wire FRAM_MISO , // @@ [SYS_CLK↑同期] FRAM SPI シリアル入力 output wire FRAM_OUTE // @@ [SYS_CLK↑同期] FRAM SPI 出力イネーブル[1:出力 0:Hi-Z] ); parameter P_BUF_ADBIT = 12 ; // @@ バッファのアドレスbit幅 parameter P_BUF_SIZE = 4095 ; // @@ バッファサイズ (サイス-1) wire asi_reg_enb,spi_reg_enb; wire [ 3:0] asi_reg_div,spi_reg_div; wire asi_reg_pol,spi_reg_pol; wire [ 1:0] asi_reg_tak,spi_reg_tak; wire [20:0] asi_reg_acs,spi_reg_acs; wire [20:0] asi_reg_otc,spi_reg_otc; wire asi_reg_fin,spi_reg_fin; wire asi_buf_wen,spi_buf_wen; wire asi_buf_ren,spi_buf_ren; wire [20:0] asi_buf_add,spi_buf_add; wire [ 7:0] asi_buf_wdt,spi_buf_wdt; wire asi_buf_rvl,spi_buf_rvl; wire [ 7:0] asi_buf_rdt,spi_buf_rdt; wire asi_buf_fcr; wire asi_ami_str; wire ami_buf_emp; wire ami_buf_rvl; wire [ 7:0] ami_buf_rdt; wire ami_buf_ren; // @@ // @@ Avalon-MM Slave I/F // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ NML_FRAMIF_ASI #( .P_BUF_ADBIT (P_BUF_ADBIT ), // parameter P_BUF_ADBIT = 12 , // @@ バッファのアドレスbit幅 .P_BUF_SIZE (P_BUF_SIZE ) // parameter P_BUF_SIZE = 4095 // @@ バッファサイズ (サイス-1) ) UnASI( .RESET_N (CPU_RST_N ), // input wire RESET_N , // @@ システムリセット .CLOCK (CPU_CLK ), // input wire CLOCK , // @@ システムクロック .MST_SLV (MST_SLV ), // input wire MST_SLV , // @@ FRAMIF周辺 Avalon-MM Master/Slave切替 [0:Master] .PRM_ENB (PRM_ENB ), // input wire PRM_ENB , // @@ FRAMIF周辺 処理イネーブル [1→0:OFF 0→1:ON] .PRM_DIV (PRM_DIV ), // input wire [ 3:0] PRM_DIV , // @@ FRAMIF周辺 シリアルクロック周波数設定 .PRM_POL (PRM_POL ), // input wire PRM_POL , // @@ FRAMIF周辺 シリアルクロック極性設定 .PRM_TAK (PRM_TAK ), // input wire [ 1:0] PRM_TAK , // @@ FRAMIF周辺 シリアルデータ取り込みタイミング設定 .PRM_ACS (PRM_ACS ), // input wire [20:0] PRM_ACS , // @@ FRAMIF周辺 アクセスバイト数 (最大値:1,048,579) .PRM_OTC (PRM_OTC ), // input wire [ 1:0] PRM_OTC , // @@ FRAMIF周辺 出力バイト数 (最大値:3) .PRM_MSK (PRM_MSK ), // input wire PRM_MSK , // @@ FRAMIF周辺 割り込みマスク .PRM_CLR (PRM_CLR ), // input wire PRM_CLR , // @@ FRAMIF周辺 割り込みクリア .AVA_WEN (SAV_WEN ), // input wire AVA_WEN , // @@ Avalon-MM ライトイネーブル .AVA_REN (SAV_REN ), // input wire AVA_REN , // @@ Avalon-MM リードイネーブル .AVA_ADD (SAV_ADD ), // input wire [ 5:0] AVA_ADD , // @@ Avalon-MM リード/ライトイネーブル .AVA_WDT (SAV_WDT ), // input wire [31:0] AVA_WDT , // @@ Avalon-MM ライトデータ .AVA_WIT (SAV_WIT ), // output wire AVA_WIT , // @@ Avalon-MM ウェイトリクエスト .AVA_RVL (SAV_RVL ), // output reg AVA_RVL , // @@ Avalon-MM リードデータイネーブル .AVA_RDT (SAV_RDT ), // output reg [31:0] AVA_RDT , // @@ Avalon-MM リードデータ .REG_ENB (asi_reg_enb ), // output reg REG_ENB , // @@ レジスタ 処理イネーブル .REG_DIV (asi_reg_div ), // output reg [ 3:0] REG_DIV , // @@ レジスタ シリアルクロック分周 .REG_POL (asi_reg_pol ), // output reg [ 1:0] REG_POL , // @@ レジスタ SPI Mode (0 又は 3のみ受付可能) .REG_TAK (asi_reg_tak ), // output reg [ 1:0] REG_TAK , // @@ レジスタ シリアルデータ取り込みタイミング .REG_ACS (asi_reg_acs ), // output reg [20:0] REG_ACS , // @@ レジスタ アクセスバイト数(設定値+1) .REG_OTC (asi_reg_otc ), // output reg [20:0] REG_OTC , // @@ レジスタ 出力バイト数(設定値+1) .REG_FIN (asi_reg_fin ), // input wire REG_FIN , // @@ レジスタ 処理イネーブル クリアパルス .BUF_WEN (asi_buf_wen ), // output wire BUF_WEN , // @@ バッファ ライトイネーブル .BUF_REN (asi_buf_ren ), // output wire BUF_REN , // @@ バッファ リードイネーブル .BUF_ADD (asi_buf_add ), // output reg [20:0] BUF_ADD , // @@ バッファ リード/ライトアドレス .BUF_WDT (asi_buf_wdt ), // output wire [ 7:0] BUF_WDT , // @@ バッファ ライトデータ .BUF_RVL (asi_buf_rvl ), // input wire BUF_RVL , // @@ バッファ リードデータ有効パルス .BUF_RDT (asi_buf_rdt ), // input wire [ 7:0] BUF_RDT // @@ バッファ リードデータ .BUF_FCR (asi_buf_fcr ), // output reg BUF_FCR , // @@ バッファ FIFOクリア(レベル信号) .AMI_STR (asi_ami_str ), // output reg AMI_STR , // @@ Master 開始パルス .CPU_IRQ (CPU_IRQ ), // output reg CPU_IRQ , // @@ 転送完了割り込み信号(レベル割り込み) .MON_ENB (MON_ENB ) // output reg MON_ENB // @@ 動作モニタ [0:停止中 1:動作中] ); // @@ // @@ Avalon-MM Master I/F // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ NML_FRAMIF_AMI UnAMI( .RESET_N (CPU_RST_N ), // input wire RESET_N , // @@ システムリセット .CLOCK (CPU_CLK ), // input wire CLOCK , // @@ システムクロック .PRM_STA (PRM_STA ), // input wire [31:0] PRM_STA , // @@ Avalon-MM(Master側) ライトベースアドレス .AMI_STR (asi_ami_str ), // input wire AMI_STR , // @@ Master 開始パルス .EMP_AMI (ami_buf_emp ), // input wire EMP_AMI , // @@ FRAMIF_AMI用 FIFOエンプティ .RVL_AMI (ami_buf_rvl ), // input wire RVL_AMI , // @@ FRAMIF_AMI用 リードデータ有効パルス .RDT_AMI (ami_buf_rdt ), // input wire [ 7:0] RDT_AMI , // @@ FRAMIF_AMI用 リードデータ .REN_AMI (ami_buf_ren ), // output reg REN_AMI , // @@ FRAMIF_AMI用 リードリクエスト .AVA_WEN (MAV_WEN ), // output reg AVA_WEN , // @@ Avalon-MM(Master側) ライトイネーブル .AVA_ADD (MAV_ADD ), // output reg [31:0] AVA_ADD , // @@ Avalon-MM(Master側) ライトアドレス .AVA_BEN (MAV_BEN ), // output reg [ 3:0] AVA_BEN , // @@ Avalon-MM(Master側) バイトイネーブル .AVA_WDT (MAV_WDT ), // output reg [ 7:0] AVA_WDT , // @@ Avalon-MM(Master側) ライトデータ .AVA_WIT (MAV_WIT ) // input wire AVA_WIT // @@ Avalon-MM(Master側) ウェイトリクエスト ); // @@ // @@ クロック乗せ換え // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // ++ Buffer // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ NML_FRAMIF_BUF #( .P_BUF_ADBIT (P_BUF_ADBIT ) // parameter P_BUF_ADBIT = 12 // @@ バッファのアドレスbit幅 ) UnBUF( .CPU_RST_N (CPU_RST_N ), // input wire RST_REG_N , // @@ CPU I/F用 リセット .CPU_CLK (CPU_CLK ), // input wire CLK_REG , // @@ CPU I/F用 クロック .SYS_RST_N (SYS_RST_N ), // input wire RST_SPI_N , // @@ システム動作用 リセット .SYS_CLK (SYS_CLK ), // input wire CLK_SPI , // @@ システム動作用 クロック .MST_SLV (MST_SLV ), // input wire MST_SLV , // @@ FRAMIF周辺 Avalon-MM Master/Slave切替 [0:Master] .PRM_CMD (PRM_CMD ), // input wire [ 7:0] PRM_CMD , // @@ FRAMIF周辺 FRAMコマンド .PRM_ADD (PRM_ADD ), // input wire [23:0] PRM_ADD , // @@ FRAMIF周辺 FRAMアドレス .BUF_FCR (asi_buf_fcr ), // input wire BUF_FCR , // @@ バッファ FIFOクリア(レベル信号) .REN_AMI (ami_buf_ren ), // input wire REN_AMI , // @@ FRAMIF_AMI用 リードリクエスト .EMP_AMI (ami_buf_emp ), // output wire EMP_AMI , // @@ FRAMIF_AMI用 FIFOエンプティ .RVL_AMI (ami_buf_rvl ), // output reg RVL_AMI , // @@ FRAMIF_AMI用 リードデータ有効パルス .RDT_AMI (ami_buf_rdt ), // output wire [ 7:0] RDT_AMI , // @@ FRAMIF_AMI用 リードデータ .WEN_ASI (asi_buf_wen ), // input wire WEN_ASI , // @@ FRAMIF_ASI用 ライトイネーブル .REN_ASI (asi_buf_ren ), // input wire REN_ASI , // @@ FRAMIF_ASI用 リードイネーブル .ADD_ASI (asi_buf_add ), // input wire [20:0] ADD_ASI , // @@ FRAMIF_ASI用 リード/ライトアドレス .WDT_ASI (asi_buf_wdt ), // input wire [ 7:0] WDT_ASI , // @@ FRAMIF_ASI用 ライトデータ .RVL_ASI (asi_buf_rvl ), // output reg RVL_ASI , // @@ FRAMIF_ASI用 リードデータ有効パルス .RDT_ASI (asi_buf_rdt ), // output wire [ 7:0] RDT_ASI , // @@ FRAMIF_ASI用 リードデータ .WEN_SPI (spi_buf_wen ), // input wire WEN_SPI , // @@ FRAMIF_SPI用 ライトイネーブル .REN_SPI (spi_buf_ren ), // input wire REN_SPI , // @@ FRAMIF_SPI用 リードイネーブル .ADD_SPI (spi_buf_add ), // input wire [20:0] ADD_SPI , // @@ FRAMIF_SPI用 リード/ライトアドレス .WDT_SPI (spi_buf_wdt ), // input wire [ 7:0] WDT_SPI , // @@ FRAMIF_SPI用 ライトデータ .RVL_SPI (spi_buf_rvl ), // output reg RVL_SPI , // @@ FRAMIF_SPI用 リードデータ有効パルス .RDT_SPI (spi_buf_rdt ) // output reg [ 7:0] RDT_SPI // @@ FRAMIF_SPI用 リードデータ ); // ++ Register // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ NML_FRAMIF_EXC #(.P_WIDTH( 1),.P_INIT( 1'b0)) UnEXC_ENB(.RI(CPU_RST_N),.CI(CPU_CLK),.DI(asi_reg_enb), .RO(SYS_RST_N),.CO(SYS_CLK),.DO(spi_reg_enb) ); assign spi_reg_div = asi_reg_div; assign spi_reg_pol = asi_reg_pol; assign spi_reg_tak = asi_reg_tak; assign spi_reg_acs = asi_reg_acs; assign spi_reg_otc = asi_reg_otc; NML_FRAMIF_EXC #(.P_WIDTH( 1),.P_INIT( 1'b0)) UnEXC_FIN(.RO(CPU_RST_N),.CO(CPU_CLK),.DO(asi_reg_fin), .RI(SYS_RST_N),.CI(SYS_CLK),.DI(spi_reg_fin) ); // @@ // @@ SPI I/F // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ NML_FRAMIF_SPI #( .P_WAITC (3'd7 ), // parameter P_WAITC = 3'd7 , // @@ REG_ENB↑からアクセス開始までの時間 .P_FINWT (4'd8 ) // parameter P_FINWT = 4'd8 // @@ REG_FINのHighパルス幅 ) UnSPI( .RESET_N (SYS_RST_N ), // input wire RESET_N , // @@ システムリセット .CLOCK (SYS_CLK ), // input wire CLOCK , // @@ システムクロック [最大周波数=200MHz] .FRAM_CS_N (FRAM_CS_N ), // output reg FRAM_CS_N , // @@ FRAM SPI チップセレクト .FRAM_SCLK (FRAM_SCLK ), // output reg FRAM_SCLK , // @@ FRAM SPI シリアルクロック [最大周波数= 50MHz] .FRAM_MOSI (FRAM_MOSI ), // output reg FRAM_MOSI , // @@ FRAM SPI シリアル出力 .FRAM_MISO (FRAM_MISO ), // input wire FRAM_MISO , // @@ FRAM SPI シリアル入力 .FRAM_OUTE (FRAM_OUTE ), // output reg FRAM_OUTE , // @@ FRAM SPI 出力イネーブル [1:出力 0:Hi-Z] .REG_ENB (spi_reg_enb ), // input wire REG_ENB , // @@ レジスタ 処理イネーブル .REG_DIV (spi_reg_div ), // input wire [ 3:0] REG_DIV , // @@ レジスタ シリアルクロック分周 .REG_POL (spi_reg_pol ), // input wire REG_POL , // @@ レジスタ シリアルクロック極性 .REG_TAK (spi_reg_tak ), // input wire [ 1:0] REG_TAK , // @@ レジスタ シリアルデータ取り込みタイミング .REG_ACS (spi_reg_acs ), // input wire [20:0] REG_ACS , // @@ レジスタ アクセスバイト数(設定値+1) .REG_OTC (spi_reg_otc ), // input wire [20:0] REG_OTC , // @@ レジスタ 出力バイト数(設定値+1) .REG_FIN (spi_reg_fin ), // output reg REG_FIN , // @@ レジスタ 処理イネーブル クリアパルス .BUF_WEN (spi_buf_wen ), // output reg BUF_WEN , // @@ バッファ ライトイネーブル .BUF_REN (spi_buf_ren ), // output reg BUF_REN , // @@ バッファ リードイネーブル .BUF_ADD (spi_buf_add ), // output reg [20:0] BUF_ADD , // @@ バッファ リード/ライトアドレス .BUF_WDT (spi_buf_wdt ), // output reg [ 7:0] BUF_WDT , // @@ バッファ ライトデータ .BUF_RVL (spi_buf_rvl ), // input wire BUF_RVL , // @@ バッファ リードデータ有効パルス .BUF_RDT (spi_buf_rdt ) // input wire [ 7:0] BUF_RDT // @@ バッファ リードデータ ); endmodule
Avalon-MM Slave I/F
レジスタの配置、Bufferブロックの内蔵RAMのリード/ライト制御を行います。
レジスタは、入力信号MST_SLV[0:Master 1:Salve]に応じて、入力信号PRM_???の入力値 又はCPUからライトされた値を保存します。
// ** // ** Avalon-MM Slave I/F for FRAM // ** // ***************************************************************************** module NML_FRAMIF_ASI #( parameter P_BUF_ADBIT = 12 , // @@ バッファのアドレスbit幅 parameter P_BUF_SIZE = 4095 // @@ バッファサイズ (サイス-1) )( input wire RESET_N , // @@ システムリセット input wire CLOCK , // @@ システムクロック input wire MST_SLV , // @@ FRAMIF周辺 Avalon-MM Master/Slave切替 [0:Master] input wire PRM_ENB , // @@ FRAMIF周辺 処理イネーブル [1→0:OFF 0→1:ON] input wire [ 3:0] PRM_DIV , // @@ FRAMIF周辺 シリアルクロック周波数設定 input wire PRM_POL , // @@ FRAMIF周辺 シリアルクロック極性設定 input wire [ 1:0] PRM_TAK , // @@ FRAMIF周辺 シリアルデータ取り込みタイミング設定 input wire [20:0] PRM_ACS , // @@ FRAMIF周辺 アクセスバイト数 (最大値:1,048,579) input wire [ 1:0] PRM_OTC , // @@ FRAMIF周辺 出力バイト数 (最大値:3) input wire PRM_MSK , // @@ FRAMIF周辺 割り込みマスク input wire PRM_CLR , // @@ FRAMIF周辺 割り込みクリア input wire AVA_WEN , // @@ Avalon-MM ライトイネーブル input wire AVA_REN , // @@ Avalon-MM リードイネーブル input wire [ 5:0] AVA_ADD , // @@ Avalon-MM リード/ライトイネーブル input wire [31:0] AVA_WDT , // @@ Avalon-MM ライトデータ output wire AVA_WIT , // @@ Avalon-MM ウェイトリクエスト output reg AVA_RVL , // @@ Avalon-MM リードデータイネーブル output reg [31:0] AVA_RDT , // @@ Avalon-MM リードデータ output reg REG_ENB , // @@ レジスタ 処理イネーブル output reg [ 3:0] REG_DIV , // @@ レジスタ シリアルクロック分周 output reg REG_POL , // @@ レジスタ SPI Mode (0 又は 3のみ受付可能) output reg [ 1:0] REG_TAK , // @@ レジスタ シリアルデータ取り込みタイミング output reg [20:0] REG_ACS , // @@ レジスタ アクセスバイト数(設定値+1) output reg [20:0] REG_OTC , // @@ レジスタ 出力バイト数(設定値+1) input wire REG_FIN , // @@ レジスタ 処理イネーブル クリアパルス output wire BUF_WEN , // @@ バッファ ライトイネーブル output wire BUF_REN , // @@ バッファ リードイネーブル output reg [20:0] BUF_ADD , // @@ バッファ リード/ライトアドレス output wire [ 7:0] BUF_WDT , // @@ バッファ ライトデータ input wire BUF_RVL , // @@ バッファ リードデータ有効パルス input wire [ 7:0] BUF_RDT , // @@ バッファ リードデータ output reg BUF_FCR , // @@ バッファ FIFOクリア(レベル信号) output reg AMI_STR , // @@ Master 開始パルス output reg CPU_IRQ , // @@ 転送完了割り込み信号(レベル割り込み) output reg MON_ENB // @@ 動作モニタ [0:停止中 1:動作中] ); // @@ // @@ 外部パラメータの取り込み (動作中に変更しないため、False Path) // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reg in_slv; reg in_enb; reg [ 3:0] in_div; reg in_pol; reg [ 1:0] in_tak; reg [20:0] in_acs; reg [ 1:0] in_otc; reg in_msk; reg in_clr; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) begin in_slv <= 1'd0; in_enb <= 1'd0; in_div <= 4'd0; in_pol <= 1'd0; in_tak <= 2'd0; in_acs <= 21'd0; in_otc <= 2'd0; in_msk <= 1'd0; in_clr <= 1'd0; end else begin in_slv <= MST_SLV; in_enb <= PRM_ENB; in_div <= PRM_DIV; in_pol <= PRM_POL; in_tak <= PRM_TAK; in_acs <= PRM_ACS; in_otc <= PRM_OTC; in_msk <= PRM_MSK; in_clr <= PRM_CLR; end end reg mst_enbl; reg mst_enbl_dly1; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) begin mst_enbl <= 1'b0; mst_enbl_dly1 <= 1'b0; end else begin mst_enbl <= ( ~in_slv ) ? in_enb : 1'b0; mst_enbl_dly1 <= mst_enbl; end end wire mst_enbl_set1 = ( ( mst_enbl) & (~mst_enbl_dly1) ); wire mst_enbl_set0 = ( (~mst_enbl) & ( mst_enbl_dly1) ); always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) AMI_STR <= 1'b0; else AMI_STR <= mst_enbl_set1; end always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) BUF_FCR <= 1'b1; else BUF_FCR <= ~mst_enbl; end // @@ // @@ 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 CLOCK 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 CLOCK 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 ); // ++ アクセス制御 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ reg acc_wen; reg acc_ren; wire [ 3:0] acc_add = in_ava_add[5:2]; wire [31:0] acc_wdt = in_ava_wdt; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) begin acc_wen <= 1'b0; acc_ren <= 1'b0; end else begin acc_wen <= ( AVA_WEN & (~in_ava_wen) ) ? 1'b1 : 1'b0; acc_ren <= ( AVA_REN & (~in_ava_ren) ) ? 1'b1 : 1'b0; end end // @@ // @@ レジスタ/バッファ制御 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // ++ レジスタマップ // ++ // ++ 0x00 : 処理イネーブル [ 0]= REG_ENB // ++ 0x04 : 制御パラメータ [ 6:0]={REG_TAK,REG_POL,REG_DIV} // ++ 0x08 : アクセスバイト数 [20:0]= REG_ACS // ++ 0x0C : 出力バイト数 [20:0]= REG_OTC // ++ 0x10 : 割り込みステータス [ 0]=転送完了 // ++ 0x14 : 割り込みマスク [ 0]=転送完了マスク [1:マスク] // ++ 0x18 : バッファリード/ライトアドレス // ++ 0x1C : バッファリード/ライトデータ // ++ 0x20-3F : 予約(アクセス禁止) // ++ リード/ライト制御 (デコード) // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ wire set_enb = ( in_slv & acc_wen & (acc_add==4'h0) ); wire set_cnt = ( in_slv & acc_wen & (acc_add==4'h1) ); wire set_acs = ( in_slv & acc_wen & (acc_add==4'h2) ); wire set_otc = ( in_slv & acc_wen & (acc_add==4'h3) ); wire set_irs = ( in_slv & acc_wen & (acc_add==4'h4) & acc_wdt[0] ); wire set_irm = ( in_slv & acc_wen & (acc_add==4'h5) ); wire set_bad = ( in_slv & acc_wen & (acc_add==4'h6) ); wire set_bdt = ( in_slv & acc_wen & (acc_add==4'h7) ); wire get_enb = ( acc_ren & (acc_add==4'h0) ); wire get_cnt = ( acc_ren & (acc_add==4'h1) ); wire get_acs = ( acc_ren & (acc_add==4'h2) ); wire get_otc = ( acc_ren & (acc_add==4'h3) ); wire get_irs = ( acc_ren & (acc_add==4'h4) ); wire get_irm = ( acc_ren & (acc_add==4'h5) ); wire get_bad = ( acc_ren & (acc_add==4'h6) ); wire get_bdt = ( acc_ren & (acc_add==4'h7) ); // ++ バッファ制御 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ assign BUF_WEN = set_bdt; assign BUF_REN = get_bdt; assign BUF_WDT = acc_wdt[7:0]; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) BUF_ADD <= 21'd0; else if( set_bad ) BUF_ADD <= in_ava_wdt[20:0]; else if( set_bdt | get_bdt ) BUF_ADD <= BUF_ADD + 21'd1; end // ++ レジスタライト制御 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ reg reg_irs; // 割り込みステータス reg reg_irm; // 割り込みマスク wire [31:0] reg_clp = ( acc_wdt > P_BUF_SIZE ) ? P_BUF_SIZE : acc_wdt; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) REG_ENB <= 1'b0; else if( REG_FIN ) REG_ENB <= 1'b0; else if( mst_enbl_set0 ) REG_ENB <= 1'b0; else if( mst_enbl_set1 ) REG_ENB <= 1'b1; else if( set_enb ) REG_ENB <= acc_wdt[0]; end always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) reg_irs <= 1'b0; else if( ~in_slv & in_clr ) reg_irs <= 1'b0; else if( set_irs ) reg_irs <= 1'b0; else if( REG_FIN ) reg_irs <= 1'b1; end always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) MON_ENB <= 1'b0; else MON_ENB <= REG_ENB; end always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) CPU_IRQ <= 1'b0; else CPU_IRQ <= ( reg_irm ) ? 1'b0 : reg_irs; end always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) begin REG_TAK <= 2'd0; REG_POL <= 1'd0; REG_DIV <= 4'd0; REG_ACS <= 21'd0; REG_OTC <= 21'd0; reg_irm <= 1'b1; end else begin REG_TAK <= (~in_slv) ? in_tak : (set_cnt) ? acc_wdt[ 6: 5] : REG_TAK; REG_POL <= (~in_slv) ? in_pol : (set_cnt) ? acc_wdt[ 4] : REG_POL; REG_DIV <= (~in_slv) ? in_div : (set_cnt) ? acc_wdt[ 3: 0] : REG_DIV; REG_ACS <= (~in_slv) ? in_acs : (set_acs) ? reg_clp[20: 0] : REG_ACS; REG_OTC <= (~in_slv) ? {19'd0,in_otc} : (set_otc) ? acc_wdt[20: 0] : REG_OTC; reg_irm <= (~in_slv) ? in_msk : (set_irm) ? acc_wdt[ 0] : reg_irm; end end // ++ レジスタリード制御 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ assign ot_ava_rvl = ( acc_ren & (~get_bdt) ) | BUF_RVL; assign ot_ava_rdt = ( ( get_enb ) ? { {31{1'b0}}, REG_ENB } : 32'd0 ) | ( ( get_cnt ) ? { {25{1'b0}},{REG_TAK,REG_POL,REG_DIV} } : 32'd0 ) | ( ( get_acs ) ? { {11{1'b0}}, REG_ACS } : 32'd0 ) | ( ( get_otc ) ? { {11{1'b0}}, REG_OTC } : 32'd0 ) | ( ( get_irs ) ? { {31{1'b0}}, reg_irs } : 32'd0 ) | ( ( get_irm ) ? { {31{1'b0}}, reg_irm } : 32'd0 ) | ( ( get_bad ) ? { {11{1'b0}}, BUF_ADD } : 32'd0 ) | ( ( BUF_RVL ) ? { {24{1'b0}}, BUF_RDT } : 32'd0 ) ; assign ot_ava_wit = ~ot_ava_rvl; endmodule
Avalon-MM Master I/F
Bufferブロック内のFIFOからのエンプティ信号(入力信号EMP_AMI)がNot Empty(EMP_AMI="0")になると動作を開始します。
シーケンス管理は、内部信号seq[1:0]で行います。
各状態の遷移時に、FIFOにリードイネーブルを生成し、Avaon-MMの制御信号をアサートします。
// ** // ** Avalon-MM Master I/F for FRAM // ** // ***************************************************************************** module NML_FRAMIF_AMI( input wire RESET_N , // @@ システムリセット input wire CLOCK , // @@ システムクロック input wire [31:0] PRM_STA , // @@ Avalon-MM(Master側) ライトベースアドレス input wire AMI_STR , // @@ Master 開始パルス input wire EMP_AMI , // @@ FRAMIF_AMI用 FIFOエンプティ input wire RVL_AMI , // @@ FRAMIF_AMI用 リードデータ有効パルス input wire [ 7:0] RDT_AMI , // @@ FRAMIF_AMI用 リードデータ output reg REN_AMI , // @@ FRAMIF_AMI用 リードリクエスト output reg AVA_WEN , // @@ Avalon-MM(Master側) ライトイネーブル output reg [31:0] AVA_ADD , // @@ Avalon-MM(Master側) ライトアドレス output reg [ 3:0] AVA_BEN , // @@ Avalon-MM(Master側) バイトイネーブル output reg [ 7:0] AVA_WDT , // @@ Avalon-MM(Master側) ライトデータ input wire AVA_WIT // @@ Avalon-MM(Master側) ウェイトリクエスト ); // @@ // @@ シーケンス // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reg [ 1:0] seq; wire seq_str = ( (seq==2'd0) & (~EMP_AMI) ); // FIFO にデータ格納 wire seq_get = ( (seq==2'd1) & ( RVL_AMI) ); // FIFO のデータ取得 wire seq_end = ( (seq==2'd2) & (~AVA_WIT) ); // Avalon-MM 完了 always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) seq <= 2'd0; else if( AMI_STR | seq_end ) seq <= 2'd0; else if( seq_str | seq_get ) seq <= seq + 2'd1; else seq <= seq; end // @@ // @@ バッファ制御 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) REN_AMI <= 1'd0; else REN_AMI <= seq_str; end // @@ // @@ Avalon-MM制御 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reg [31:0] add; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) add <= 32'd0; else if( AMI_STR ) add <= PRM_STA; else if( seq_get ) add <= add + 32'd1; else add <= add; end always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) begin AVA_WEN <= 1'd0; AVA_ADD <= 32'd0; AVA_BEN <= 4'd0; AVA_WDT <= 8'd0; end else if( seq_end ) begin AVA_WEN <= 1'd0; AVA_ADD <= 32'd0; AVA_BEN <= 4'd0; AVA_WDT <= 8'd0; end else if( seq_get ) begin AVA_WEN <= 1'd1; AVA_ADD <= add; AVA_BEN <= (add[1:0]==2'd0) ? 4'b0001 : (add[1:0]==2'd1) ? 4'b0010 : (add[1:0]==2'd2) ? 4'b0100 : 4'b1000; AVA_WDT <= RDT_AMI; end else begin AVA_WEN <= AVA_WEN; end end endmodule
Buffer
Quartusで生成したRAMマクロとFIFOマクロを配置します。
このマクロでCPU_CLK(50MHz)⇔SYS_CLK(200MHz)の乗せ換えを行います。
RAMは、Avalon-MM Slave I/FブロックとSPI I/Fブロックの送受信データを保存するためのメモリであり、FIFOはSPI I/Fブロックで取得したデータをAvalon-MM Master I/Fブロックへ送るためのメモリとなります。
入力信号MST_SLVの入力値に応じて、SPI I/Fブロックからのライト動作をRAMにするか、FIFOにするか切り替えます。
リードデータ有効パルス(出力信号RVL_AMI,RVL_ASI,RVL_SPI)は、リードデータラッチ側でリードデータ遅延を意識しなくても良いように、Bufferブロックでリードデータ取り込み用パルスを生成します。
// ** // ** Buffer for FRAM // ** // ***************************************************************************** module NML_FRAMIF_BUF #( parameter P_BUF_ADBIT = 12 // @@ バッファのアドレスbit幅 )( input wire CPU_RST_N , // @@ CPU I/F用 リセット input wire CPU_CLK , // @@ CPU I/F用 クロック input wire SYS_RST_N , // @@ システム動作用 リセット input wire SYS_CLK , // @@ システム動作用 クロック input wire MST_SLV , // @@ FRAMIF周辺 Avalon-MM Master/Slave切替 [0:Master] input wire [ 7:0] PRM_CMD , // @@ FRAMIF周辺 FRAMコマンド input wire [23:0] PRM_ADD , // @@ FRAMIF周辺 FRAMアドレス input wire BUF_FCR , // @@ バッファ FIFOクリア(レベル信号) input wire REN_AMI , // @@ FRAMIF_AMI用 リードリクエスト output wire EMP_AMI , // @@ FRAMIF_AMI用 FIFOエンプティ output reg RVL_AMI , // @@ FRAMIF_AMI用 リードデータ有効パルス output wire [ 7:0] RDT_AMI , // @@ FRAMIF_AMI用 リードデータ input wire WEN_ASI , // @@ FRAMIF_ASI用 ライトイネーブル input wire REN_ASI , // @@ FRAMIF_ASI用 リードイネーブル input wire [20:0] ADD_ASI , // @@ FRAMIF_ASI用 リード/ライトアドレス input wire [ 7:0] WDT_ASI , // @@ FRAMIF_ASI用 ライトデータ output reg RVL_ASI , // @@ FRAMIF_ASI用 リードデータ有効パルス output wire [ 7:0] RDT_ASI , // @@ FRAMIF_ASI用 リードデータ input wire WEN_SPI , // @@ FRAMIF_SPI用 ライトイネーブル input wire REN_SPI , // @@ FRAMIF_SPI用 リードイネーブル input wire [20:0] ADD_SPI , // @@ FRAMIF_SPI用 リード/ライトアドレス input wire [ 7:0] WDT_SPI , // @@ FRAMIF_SPI用 ライトデータ output reg RVL_SPI , // @@ FRAMIF_SPI用 リードデータ有効パルス output reg [ 7:0] RDT_SPI // @@ FRAMIF_SPI用 リードデータ ); // @@ // @@ 外部パラメータの取り込み (動作中に変更しないため、False Path) // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reg in_mode_sys; reg [ 7:0] in_comm_sys; reg [23:0] in_addr_sys; always @( posedge SYS_CLK or negedge SYS_RST_N ) begin if( ~SYS_RST_N ) begin in_mode_sys <= 1'b0; in_comm_sys <= 8'd0; in_addr_sys <= 24'd0; end else begin in_mode_sys <= MST_SLV; in_comm_sys <= PRM_CMD; in_addr_sys <= PRM_ADD; end end // @@ // @@ マスタモード用 (FIFOを配置) // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // ++ SYS_CLK同期 ライト側 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ reg fifo_wreq_sys; reg [ 7:0] fifo_wdat_sys; always @( posedge SYS_CLK or negedge SYS_RST_N ) begin if( ~SYS_RST_N ) begin fifo_wreq_sys <= 1'b0; fifo_wdat_sys <= 8'd0; end else begin fifo_wreq_sys <= ( ~in_mode_sys ) ? WEN_SPI : 1'b0; fifo_wdat_sys <= ( ~in_mode_sys ) ? WDT_SPI : 8'd0; end end // ++ FIFO // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ NML_FRAMIF_FIFO UnFIFO( .wrclk (SYS_CLK ), // input wrclk; .wrreq (fifo_wreq_sys ), // input wrreq; .data (fifo_wdat_sys ), // input [ 7:0] data; .wrempty (/** OPEN **/ ), // output wrempty; .wrfull (/** OPEN **/ ), // output wrfull; .wrusedw (/** OPEN **/ ), // output [ 9:0] wrusedw; .aclr (BUF_FCR ), // input aclr; .rdclk (CPU_CLK ), // input rdclk; .rdreq (REN_AMI ), // input rdreq; .q (RDT_AMI ), // output [ 7:0] q; .rdempty (EMP_AMI ), // output rdempty; .rdfull (/** OPEN **/ ), // output rdfull; .rdusedw (/** OPEN **/ ) // output [ 9:0] rdusedw; ); // ++ CPU_CLK同期 リード側 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ reg [ 1:0] tmp_ami; always @( posedge CPU_CLK or negedge CPU_RST_N ) begin if( ~CPU_RST_N ) {RVL_AMI,tmp_ami} <= {1'b0,2'b0}; else {RVL_AMI,tmp_ami} <= {tmp_ami,REN_AMI}; end // @@ // @@ スレーブモード用 (RAMを配置) // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // ++ SYS_CLK同期 A側 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ reg ram_wen_sys; reg ram_ren_sys; reg [20:0] ram_add_sys; reg [ 7:0] ram_wdt_sys; wire [ 7:0] ram_rdt_sys; reg [ 1:0] ram_tmp_sys; always @( posedge SYS_CLK or negedge SYS_RST_N ) begin if( ~SYS_RST_N ) begin ram_wen_sys <= 1'b0; ram_ren_sys <= 1'b0; ram_add_sys <= 21'd0; ram_wdt_sys <= 8'd0; end else begin ram_wen_sys <= ( in_mode_sys ) ? WEN_SPI : 1'b0; ram_ren_sys <= REN_SPI; ram_add_sys <= ADD_SPI; ram_wdt_sys <= WDT_SPI; end end always @( posedge SYS_CLK or negedge SYS_RST_N ) begin if( ~SYS_RST_N ) RDT_SPI <= 8'd0; else if( in_mode_sys ) RDT_SPI <= ram_rdt_sys; else if( ram_ren_sys ) begin RDT_SPI <= ((ram_add_sys==21'd0) ? in_comm_sys[ 7: 0] : 8'd0) | ((ram_add_sys==21'd1) ? in_addr_sys[23:16] : 8'd0) | ((ram_add_sys==21'd2) ? in_addr_sys[15: 8] : 8'd0) | ((ram_add_sys==21'd3) ? in_addr_sys[ 7: 0] : 8'd0); end else RDT_SPI <= RDT_SPI; end always @( posedge SYS_CLK or negedge SYS_RST_N ) begin if( ~SYS_RST_N ) {RVL_SPI,ram_tmp_sys} <= {1'b0,2'b0}; else {RVL_SPI,ram_tmp_sys} <= {ram_tmp_sys,ram_ren_sys}; end // ++ RAM // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ NML_FRAMIF_RAM UnRAM01( .clock_a (SYS_CLK ), // input clock_a; .wren_a (ram_wen_sys ), // input wren_a; .rden_a (ram_ren_sys ), // input rden_a; .address_a (ram_add_sys[P_BUF_ADBIT-1:0] ), // input [11:0] address_a; .data_a (ram_wdt_sys ), // input [ 7:0] data_a; .q_a (ram_rdt_sys ), // output [ 7:0] q_a; .clock_b (CPU_CLK ), // input clock_b; .wren_b (WEN_ASI ), // input wren_b; .rden_b (REN_ASI ), // input rden_b; .address_b (ADD_ASI[P_BUF_ADBIT-1:0] ), // input [11:0] address_b; .data_b (WDT_ASI ), // input [ 7:0] data_b; .q_b (RDT_ASI ) // output [ 7:0] q_b; ); // ++ CPU_CLK同期 B側 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ reg [ 1:0] ram_tmp_asi; always @( posedge CPU_CLK or negedge CPU_RST_N ) begin if( ~CPU_RST_N ) {RVL_ASI,ram_tmp_asi} <= {1'b0,2'b0}; else {RVL_ASI,ram_tmp_asi} <= {ram_tmp_asi,REN_ASI}; end endmodule
SPI I/F
設定値に応じて、FRAMのSPI制御信号を生成します。
SPI出力(送信時)は、Bufferブロックからリードデータを取得し、SPI出力します。
SPI入力(受信時)は、シリアルデータを8bitパラレルに変換し、Bufferブロックにライトします。
主な内部構成は以下の通りです。
// ** // ** SPI I/F for FRAM // ** // ***************************************************************************** module NML_FRAMIF_SPI #( parameter P_WAITC = 3'd7 , // @@ REG_ENB↑からアクセス開始までの時間 parameter P_FINWT = 4'd8 // @@ REG_FINのHighパルス幅 ) ( input wire RESET_N , // @@ システムリセット input wire CLOCK , // @@ システムクロック [最大周波数=200MHz] output reg FRAM_CS_N , // @@ FRAM SPI チップセレクト output reg FRAM_SCLK , // @@ FRAM SPI シリアルクロック [最大周波数= 50MHz] output reg FRAM_MOSI , // @@ FRAM SPI シリアル出力 input wire FRAM_MISO , // @@ FRAM SPI シリアル入力 output reg FRAM_OUTE , // @@ FRAM SPI 出力イネーブル [1:出力 0:Hi-Z] input wire REG_ENB , // @@ レジスタ 処理イネーブル input wire [ 3:0] REG_DIV , // @@ レジスタ シリアルクロック分周 input wire REG_POL , // @@ レジスタ シリアルクロック極性 input wire [ 1:0] REG_TAK , // @@ レジスタ シリアルデータ取り込みタイミング input wire [20:0] REG_ACS , // @@ レジスタ アクセスバイト数(設定値+1) input wire [20:0] REG_OTC , // @@ レジスタ 出力バイト数(設定値+1) output reg REG_FIN , // @@ レジスタ 処理イネーブル クリアパルス output reg BUF_WEN , // @@ バッファ ライトイネーブル output reg BUF_REN , // @@ バッファ リードイネーブル output reg [20:0] BUF_ADD , // @@ バッファ リード/ライトアドレス output reg [ 7:0] BUF_WDT , // @@ バッファ ライトデータ input wire BUF_RVL , // @@ バッファ リードデータ有効パルス input wire [ 7:0] BUF_RDT // @@ バッファ リードデータ ); // @@ // @@ 処理イネーブル // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reg enb_d1; wire init; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) enb_d1 <= 1'b0; else enb_d1 <= REG_ENB; end assign init = ( REG_ENB & (~enb_d1) ) ? 1'b1 : 1'b0; // @@ // @@ 開始ウェイト (バッファの最初のデータ読み期間) // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reg wit_enbl; reg [ 2:0] wit_cont; wire wit_term; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) wit_enbl <= 1'b0; else if( ~REG_ENB ) wit_enbl <= 1'b0; else if( wit_term ) wit_enbl <= 1'b0; else if( init ) wit_enbl <= 1'b1; else wit_enbl <= wit_enbl; end always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) wit_cont <= 3'h0; else if( ~REG_ENB ) wit_cont <= 3'h0; else if( ~wit_enbl ) wit_cont <= 3'h0; else wit_cont <= wit_cont + 3'h1; end assign wit_term= ( wit_enbl & (wit_cont==P_WAITC) ) ? 1'b1 : 1'b0; // @@ // @@ アクセス制御 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reg acc_enbl; wire acc_term; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) acc_enbl <= 1'b0; else if( ~REG_ENB ) acc_enbl <= 1'b0; else if( acc_term ) acc_enbl <= 1'b0; else if( wit_term ) acc_enbl <= 1'b1; else acc_enbl <= acc_enbl; end reg [ 2:0] end_cont; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) end_cont <= 3'd0; else if( ~REG_ENB ) end_cont <= 3'd0; else if( acc_term ) end_cont <= 3'd1; else if( end_cont!=3'd0 ) end_cont <= end_cont + 3'd1; else end_cont <= end_cont; end // @@ // @@ シリアルクロック周波数 // @@ // @@ SPI_SCLK周波数 = CLOCK周波数 / ((REG_DIV+1)*4) // @@ 例) // @@ CLOCK周波数 = 200MHz // @@ REG_DIV = 0 // @@ SPI_SCLK周波数 => 50MHz // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reg [ 6:0] sck_cont; wire [ 6:0] sck_cycl = {1'b0,REG_DIV,2'b11}; wire sck_pose; wire sck_nege; // ++ Division // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) sck_cont <= 7'h00; else if( ~REG_ENB ) sck_cont <= 7'h00; else if( ~acc_enbl | acc_term ) sck_cont <= 7'h00; else if( sck_nege ) sck_cont <= 7'h00; else sck_cont <= sck_cont + 7'h01; end assign sck_pose= ( sck_cont=={1'b0,sck_cycl[6:1]} ) ? 1'b1 : 1'b0; assign sck_nege= ( sck_cont== sck_cycl ) ? 1'b1 : 1'b0; // @@ // @@ 管理カウンタ // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // ++ Bit Count // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ reg [ 2:0] bit_cont; wire bit_term; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) bit_cont <= 3'd0; else if( ~REG_ENB ) bit_cont <= 3'd0; else if( ~acc_enbl | acc_term ) bit_cont <= 3'd0; else if( sck_nege ) bit_cont <= bit_cont + 3'd1; else bit_cont <= bit_cont; end assign bit_term= ( bit_cont==3'd7 ) ? sck_nege : 1'b0; // ++ Byte Count // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ reg [20:0] byt_cont; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) byt_cont <= 21'd0; else if( ~REG_ENB ) byt_cont <= 21'd0; else if( ~acc_enbl | acc_term ) byt_cont <= 21'd0; else if( bit_term ) byt_cont <= byt_cont + 21'd1; else byt_cont <= byt_cont; end assign acc_term= ( byt_cont==REG_ACS ) ? bit_term : 1'b0; // @@ // @@ SPI 入出力切替 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reg spi_flag; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) spi_flag <= 1'b0; else if( ~REG_ENB ) spi_flag <= 1'b0; else if( wit_term ) spi_flag <= 1'b1; else if( ~acc_enbl | acc_term ) spi_flag <= 1'b0; else if( bit_term & (byt_cont==REG_OTC) ) spi_flag <= 1'b0; else spi_flag <= spi_flag; end // @@ // @@ バッファ制御 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reg [ 7:0] rbf_temp; reg rbf_flag; wire rbf_enbl; wire [20:0] rbf_addr; reg wbf_flag; wire wbf_enbl; wire [20:0] wbf_addr; wire [ 7:0] wbf_data; // ++ Enable generation // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ wire [20:0] prm_oct = REG_OTC - 21'd1; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) rbf_flag <= 1'b0; else if( ~REG_ENB ) rbf_flag <= 1'b0; else if( wit_term ) begin if( REG_OTC==21'd0 ) rbf_flag <= 1'b0; else rbf_flag <= 1'b1; end else if( ~acc_enbl | acc_term ) rbf_flag <= 1'b0; else if( bit_term & (byt_cont==prm_oct) ) rbf_flag <= 1'b0; else rbf_flag <= rbf_flag; end always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) wbf_flag <= 1'b0; else if( ~REG_ENB ) wbf_flag <= 1'b0; else if( ~acc_enbl | acc_term ) wbf_flag <= 1'b0; else if( bit_term & (byt_cont==REG_OTC) ) wbf_flag <= 1'b1; else wbf_flag <= wbf_flag; end assign rbf_enbl= ( rbf_flag & acc_enbl & sck_pose & (bit_cont==3'd3) ); always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) BUF_WEN <= 1'b0; else if( ~REG_ENB ) BUF_WEN <= 1'b0; else BUF_WEN <= wbf_enbl; end always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) BUF_REN <= 1'b0; else if( ~REG_ENB ) BUF_REN <= 1'b0; else BUF_REN <= init | rbf_enbl; end // ++ Address generation // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ assign rbf_addr= byt_cont + 21'd1; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) BUF_ADD <= 21'd0; else if( ~REG_ENB ) BUF_ADD <= 21'd0; else BUF_ADD <= ( rbf_enbl ) ? rbf_addr : ( wbf_enbl ) ? wbf_addr : 21'd0; end // ++ S/P conversion // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) rbf_temp <= 8'h00; else if( ~REG_ENB ) rbf_temp <= 8'h00; else if( wbf_flag ) rbf_temp <= 8'h00; else if( BUF_RVL ) rbf_temp <= BUF_RDT; else rbf_temp <= rbf_temp; end always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) BUF_WDT <= 8'h00; else if( ~REG_ENB ) BUF_WDT <= 8'h00; else BUF_WDT <= ( wbf_enbl ) ? wbf_data : 8'h00; end // @@ // @@ SPI I/F 信号 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ // ++ SPI signal generation // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ wire bas_cs_n; wire bas_sclk; reg bas_mosi; reg [ 6:0] bas_temp; assign bas_cs_n= ~( REG_ENB & acc_enbl ); assign bas_sclk= ( bas_cs_n ) ? REG_POL : ( sck_cont>{1'b0,sck_cycl[6:1]} ) ? 1'b1 : 1'b0; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) {bas_mosi,bas_temp} <= 8'h00; else if( ~REG_ENB ) {bas_mosi,bas_temp} <= rbf_temp; else if( (~acc_enbl) | bit_term ) {bas_mosi,bas_temp} <= rbf_temp; else if( sck_nege ) {bas_mosi,bas_temp} <= {bas_temp,1'b0}; else {bas_mosi,bas_temp} <= {bas_mosi,bas_temp}; end always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) begin FRAM_CS_N <= 1'b1; FRAM_SCLK <= 1'b0; FRAM_MOSI <= 1'b0; FRAM_OUTE <= 1'b0; end else begin FRAM_CS_N <= (~wit_term) & bas_cs_n & (~((~end_cont[2]) & (end_cont[1:0]!=2'b00))); FRAM_SCLK <= bas_sclk; FRAM_MOSI <= bas_mosi & acc_enbl & (~wbf_flag); FRAM_OUTE <= spi_flag; end end // ++ SPI 入力信号 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ reg in_miso; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) in_miso <= 1'b0; else in_miso <= FRAM_MISO; end // ++ Capture timing // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ reg cap_jdge,cap_jdtm; reg [20:0] cap_jdad; reg cap_enbl,cap_entm; reg [20:0] cap_enad; reg [ 6:0] cap_temp; reg cap_vlid; reg [20:0] cap_addr; reg [ 7:0] cap_data; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) begin cap_jdtm <= 1'b0; cap_jdge <= 1'b0; cap_jdad <= 21'd0; end else if( ~REG_ENB ) begin cap_jdtm <= 1'b0; cap_jdge <= 1'b0; cap_jdad <= 21'd0; end else begin cap_jdtm <= wbf_flag & bit_term; cap_jdge <= wbf_flag & sck_nege; cap_jdad <= byt_cont; end end // -- 取り込み遅延 reg cap_jdtm_dly1,cap_jdtm_dly2,cap_jdtm_dly3; reg cap_jdge_dly1,cap_jdge_dly2,cap_jdge_dly3; reg [20:0] cap_jdad_dly1,cap_jdad_dly2,cap_jdad_dly3; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) begin cap_jdtm_dly1 <= 1'b0; cap_jdge_dly1 <= 1'b0; cap_jdad_dly1 <= 21'd0; cap_jdtm_dly2 <= 1'b0; cap_jdge_dly2 <= 1'b0; cap_jdad_dly2 <= 21'd0; cap_jdtm_dly3 <= 1'b0; cap_jdge_dly3 <= 1'b0; cap_jdad_dly3 <= 21'd0; end else if( ~REG_ENB ) begin cap_jdtm_dly1 <= 1'b0; cap_jdge_dly1 <= 1'b0; cap_jdad_dly1 <= 21'd0; cap_jdtm_dly2 <= 1'b0; cap_jdge_dly2 <= 1'b0; cap_jdad_dly2 <= 21'd0; cap_jdtm_dly3 <= 1'b0; cap_jdge_dly3 <= 1'b0; cap_jdad_dly3 <= 21'd0; end else begin cap_jdtm_dly1 <= cap_jdtm; cap_jdge_dly1 <= cap_jdge; cap_jdad_dly1 <= cap_jdad; cap_jdtm_dly2 <= cap_jdtm_dly1; cap_jdge_dly2 <= cap_jdge_dly1; cap_jdad_dly2 <= cap_jdad_dly1; cap_jdtm_dly3 <= cap_jdtm_dly2; cap_jdge_dly3 <= cap_jdge_dly2; cap_jdad_dly3 <= cap_jdad_dly2; end end // ------------------------------------------- always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) begin cap_entm <= 1'b0; cap_enbl <= 1'b0; cap_enad <= 21'd0; end else if( ~REG_ENB ) begin cap_entm <= 1'b0; cap_enbl <= 1'b0; cap_enad <= 21'd0; end else begin case( REG_TAK ) 2'd1 : begin cap_entm <= cap_jdtm_dly1; cap_enbl <= cap_jdge_dly1; cap_enad <= cap_jdad_dly1; end 2'd2 : begin cap_entm <= cap_jdtm_dly2; cap_enbl <= cap_jdge_dly2; cap_enad <= cap_jdad_dly2; end 2'd3 : begin cap_entm <= cap_jdtm_dly3; cap_enbl <= cap_jdge_dly3; cap_enad <= cap_jdad_dly3; end default : begin cap_entm <= cap_jdtm; cap_enbl <= cap_jdge; cap_enad <= cap_jdad; end endcase end end // ++ P/S conversion // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) cap_temp <= 7'h00; else if( ~REG_ENB ) cap_temp <= 7'h00; else if( cap_enbl ) cap_temp <= {cap_temp[5:0],in_miso}; else cap_temp <= cap_temp; end always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) begin cap_vlid <= 1'b0; cap_addr <= 21'd0; cap_data <= 8'h00; end else begin cap_vlid <= cap_entm; cap_addr <= cap_enad; cap_data <= {cap_temp,in_miso}; end end assign wbf_enbl= cap_vlid; assign wbf_addr= cap_addr; assign wbf_data= cap_data; // @@ // @@ レジスタ I/F // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ reg [ 3:0] fin_cont; always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) fin_cont <= 4'd0; else if( fin_cont==P_FINWT ) fin_cont <= 4'd0; else if( end_cont==3'd7 ) fin_cont <= 4'd1; else if( fin_cont!=4'd0 ) fin_cont <= fin_cont + 4'd1; else fin_cont <= fin_cont; end always @( posedge CLOCK or negedge RESET_N ) begin if( ~RESET_N ) REG_FIN <= 1'b0; else if( fin_cont==P_FINWT ) REG_FIN <= 1'b0; else if( end_cont==3'd7 ) REG_FIN <= 1'b1; else REG_FIN <= REG_FIN; end endmodule
このブロックは200MHzで動作します。
21bitのbyteカウンタは、以下の経路をset_false_path指定します。
- byt_cont[20:0] → byt_cont[20:0]
- byt_cont[20:0] → BUF_ADD[20:0]
これは、+1した値をラッチするもので、1クロック以内で確定する必要のないものとなります。
起点byt_cont[20:0]となる経路を以下に示します。
内部信号byt_cont[20:0]は最小32クロック後に+1加算され、BUF_ADD[20:0]も13クロック以内に+1した値が確定していれば良いようになります。
タイミング図を以下に示します。
Clock transfer
2段FFによるクロック乗せ換えとなります。
パラメータでデータ幅と初期値が設定可能になっていますが、これは流用性を考慮しています。
尚、レジスタ値用の乗せ換えとなります。
// ** // ** Clock transfer for FRAM // ** // ***************************************************************************** module NML_FRAMIF_EXC #( parameter P_WIDTH = 32 , // データ幅 parameter P_INIT = 32'd0 // 初期値 ) ( input wire RI , // @@ 入力データ用 リセット input wire CI , // @@ 入力データ用 クロック input wire [P_WIDTH-1:0] DI , // @@ 入力データ input wire RO , // @@ 出力データ用 リセット input wire CO , // @@ 出力データ用 クロック output reg [P_WIDTH-1:0] DO // @@ 出力データ ); reg [P_WIDTH-1:0] in_d; reg [P_WIDTH-1:0] as_d; always @( posedge CI or negedge RI ) begin if( ~RI ) in_d <= P_INIT; else in_d <= DI; end always @( posedge CO or negedge RO ) begin if( ~RO ) as_d <= P_INIT; else as_d <= in_d; end always @( posedge CO or negedge RO ) begin if( ~RO ) DO <= P_INIT; else DO <= as_d; end endmodule
シミュレーション波形
FRAM I/FブロックをTOPとしたRTLシミュレーション波形を以下に示します。
マスタモードとスレーブモードの波形となり、「デバイスID読み出し」の場合のシミュレーション波形となります。
マスタモード
スレーブモード
最後に
設計では、どこを「set_false_path」にするかも検討する必要があります。
どのタイミングで変化するのか、どれくらいまでに値が確定しておけば良いのか、把握する必要があります。
また、STA結果も、set_false_path指定した起点終点間の遅延量も確認する必要があります。