nao-milkの経験ブログ

25年間の半導体エンジニア経験で知り得た内容を記載したブログです。

FRAMにアクセス (Verilogコーディング編)

f:id:nao-milk:20210419152452p:plain


FRAM I/Fのverilogコーディングとなります。
ブロック仕様は以下を参照ください。
nao-milk.hatenablog.com

FRAM I/Fブロック構成

ブロック構成は以下のようになります。

f:id:nao-milk:20210416124855p:plain
ブロック図

ソースコード

verilog-HDLのソースコードを以下より示します。

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]で行います。

  1. 内部信号seq=0:FIFO Not Empty待ち
  2. 内部信号seq=1:FIFO リードデータ取得待ち
  3. 内部信号seq=2:Avalon-MM Wait信号解除待ち

各状態の遷移時に、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ブロックにライトします。

主な内部構成は以下の通りです。

f:id:nao-milk:20210419132755p:plain
SPI I/Fブロック 内部構成
// **
// **   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指定します。

  1. byt_cont[20:0] → byt_cont[20:0]
  2. byt_cont[20:0] → BUF_ADD[20:0]

これは、+1した値をラッチするもので、1クロック以内で確定する必要のないものとなります。
起点byt_cont[20:0]となる経路を以下に示します。

f:id:nao-milk:20210419140934p:plain
経路 (起点:byt_cont[20:0])

内部信号byt_cont[20:0]は最小32クロック後に+1加算され、BUF_ADD[20:0]も13クロック以内に+1した値が確定していれば良いようになります。
タイミング図を以下に示します。

f:id:nao-milk:20210419141125p:plain
タイミング図(起点:byt_cont[20:0])

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

マクロ生成

RAMマクロ

Bufferブロック内のRAMマクロの生成内容は、以下の通りとなります。

f:id:nao-milk:20210419143520p:plain
RAMマクロ

FIFOマクロ

f:id:nao-milk:20210419143937p:plain
FIFOマクロ

メモリサイズ

FRAM I/Fブロックで使用するブロックメモリサイズは、以下となります。

  • FIFO:M10K Block = 1
  • RAM:M10K Block = 4

FIFOは、BlockRAM=1となるギリギリまでのサイズ、512Word×8bit分取っています。
実際は、そこまでのサイズは必要としませんが、余裕をもっています。

RAMは、4096Word×8bitとしています。

シミュレーション波形

FRAM I/FブロックをTOPとしたRTLシミュレーション波形を以下に示します。
マスタモードとスレーブモードの波形となり、「デバイスID読み出し」の場合のシミュレーション波形となります。

マスタモード

f:id:nao-milk:20210419145925p:plain
シミュレーション波形 (マスタモード)

スレーブモード

f:id:nao-milk:20210419150758p:plain
シミュレーション波形 (スレーブモード)

最後に

設計では、どこを「set_false_path」にするかも検討する必要があります。
どのタイミングで変化するのか、どれくらいまでに値が確定しておけば良いのか、把握する必要があります。
また、STA結果も、set_false_path指定した起点終点間の遅延量も確認する必要があります。