Verilogステートマシンのテストベンチを細かく解説

「ステートマシンの構想」「Verilogのステートマシンを細かく説明」の続きとして、テストベンチの解説を行います。作成したステートマシンが動作しているのかを確認するにはテストベンチでステートマシンの動作を見ます。
テストベンチのソースコードはそれほど難しくありません。全コードを次に示します。
// TITLE: "TB_MCP3002drv.v" // MODULE NAME: TB_MCP3002drv // PROJECT CODE: // AUTHOR: (****@nakaharagiken.com) // CREATION DATE: 2020.7.20 // SOURCE: // LICENSE: Copyright (c) 2020 nakaharagiken All rights reserved. // DESCRIPTION: MCP3002drv.vのテストベンチ // NOTES TO USER: // SOURCE CONTROL: // REVISION HISTORY: v0.1 2020.7.20 First edition // // // // // // // // `timescale 1ns/1ps module TB_MCP3002drv; parameter SYSCLK_PERIOD = 100; // 10MHz reg i_clock; // system clock reg i_nreset; // asynchronous reset ____reset___|~~~normal~~~ reg i_enable; // イネーブル wire o_SPI_ncs; // SPIチップセレクト信号:プルアップ ~~~|_________________|~~~ wire o_SPI_clk; // SPIクロック信号 wire o_SPI_MOSI; // SPI MOSI reg i_SPI_MISO; // SPI MISO :プルダウン wire [9:0] o_ch0_dat; // ADCデータチャンネル0 wire [9:0] o_ch1_dat; // ADCデータチャンネル1 wire o_dataset; // ADCデータチャンネル0と1のデータ確定 _____|~|_________________ wire o_busy; // 本ブロック動作中 _________|~~~busy~~~~~~~~ ////////////////////////////////////////////////////////////////////// // Clock Driver ////////////////////////////////////////////////////////////////////// always @(i_clock) #(SYSCLK_PERIOD / 2.0) i_clock <= !i_clock; ////////////////////////////////////////////////////////////////////// // Main ////////////////////////////////////////////////////////////////////// initial begin i_clock <= 0; i_nreset <= 0; // 初期値 i_enable <= 0; i_SPI_MISO <= 0; // SPI MISO :プルダウン repeat(50) @(posedge i_clock); i_nreset <= 1; repeat(100) @(posedge i_clock); i_enable <= 1'b1; i_SPI_MISO <= 1'b0; wait (o_SPI_ncs == 1'b0); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 1 repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // 2 down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 2 up repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // 3 down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 3 up repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // 4 down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 4 up repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B9 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B9 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B8 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B8 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B7 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B7 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B6 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B6 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B5 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B5 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B4 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B4 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B3 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B3 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B2 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B2 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B1 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B1 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B0 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_ncs == 1'b1); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_ncs == 1'b0); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 1 repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // 2 down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 2 up repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // 3 down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 3 up repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // 4 down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 4 up repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B9 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B9 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B8 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B8 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B7 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B7 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B6 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B6 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B5 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B5 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B4 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B4 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B3 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B3 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B2 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B2 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B1 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B1 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B0 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_ncs == 1'b1); // B0 up null repeat(1) @(posedge i_clock); ////// wait (o_SPI_ncs == 1'b0); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 1 repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // 2 down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 2 up repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // 3 down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 3 up repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // 4 down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 4 up repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B9 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B9 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B8 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B8 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B7 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B7 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B6 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B6 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B5 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B5 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B4 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B4 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B3 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B3 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B2 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B2 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B1 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B1 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B0 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_ncs == 1'b1); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_ncs == 1'b0); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 1 repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // 2 down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 2 up repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // 3 down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 3 up repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // 4 down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // 4 up repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // down repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b1); // up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B9 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B9 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B8 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B8 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B7 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B7 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B6 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B6 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B5 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B5 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B4 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B4 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B3 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B3 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B2 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B2 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B1 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b0; wait (o_SPI_clk == 1'b1); // B1 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B0 down repeat(1) @(posedge i_clock); i_SPI_MISO <= 1'b1; wait (o_SPI_clk == 1'b1); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_clk == 1'b0); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_ncs == 1'b1); // B0 up null repeat(1) @(posedge i_clock); wait (o_SPI_ncs == 1'b0); /////// chip select end MCP3002drv inst_MCP3002drv ( .clock (i_clock), // in system clock 10MHz .nreset (i_nreset), // in asynchronous reset ____reset___|~~~normal~~~ .enable (i_enable), // in シーケンスイネーブル ___disable__|~~enable~~~~ .SPI_ncs (o_SPI_ncs), // ouy SPIチップセレクト信号:プルアップ ~~~|_________________|~~~ .SPI_clk (o_SPI_clk), // out SPIクロック信号 .SPI_MOSI (o_SPI_MOSI), // out SPI MOSI .SPI_MISO (i_SPI_MISO), // in SPI MISO :プルダウン .ch0_dat (o_ch0_dat), // out [9:0] ADCデータチャンネル0 .ch1_dat (o_ch1_dat), // out [9:0] ADCデータチャンネル1 .dataset (o_dataset), // out ADCデータチャンネル0と1のデータ確定 _____|~|_________________ .busy (o_busy) // out 本ブロック動作中 _________|~~~busy~~~~~~~~ ); endmodule
24行目は本テストベンチで使用するクロック周波数の定数宣言です。10MHzで宣言しています。
27~37行目でテストベンチのレジスタを宣言していますが、Verilogの場合入力信号はregで、出力信号はwireで宣言します。VHDLの場合区別はありません。ModelSimを使う場合ですと、入力信号と出力信号の区別がしにくいので、レジスタ名の頭にi_、o_を付けて入力と出力がわかるようにしています。
45行目でクロック信号を生成しています。(SYSCLK_PERIOD / 2.0) i_clock <= !i_clock;としているのは、クロックデューティーが50%だからです。
55~58行目で各入力信号の初期値を入れます。これ以降がテストベンチ動作になります。
68行目でwait (o_SPI_ncs == 1’b0);により、o_SPI_ncsがLowになるまで待ちます。動作の信号は下のデータシートを参照してください。o_SPI_ncsはnCS(一番上の信号:CSの負論理)信号です。
×××を待ってから〇〇〇〇を動かす。というのはテストベンチでは頻繁に発生しますが、verilogの場合はこのようにwaitを使うのが簡単です。

70行目で同じようにwait (o_SPI_clk == 1’b1); はo_SPI_clk信号(CLK信号)がHiになるまで待っています。これがシリアルクロックの1ビット目です。
その後、90行目のi_SPI_MISO <= 1’b1;でMSBビットをi_SPI_MISOに入れています。138行目までが受信のシリアル信号です。
141行目のwait (o_SPI_ncs == 1’b1);でo_SPI_ncsがHiになるのを待っています。
このようにテストベンチは多少野暮ったくても簡素に書く方が動作確認に徹することができると思います。
本ソースコートはステートマシンの説明用に作成したもので、実機での動作確認を行っていません。実機で使用しないようにお願いします。
-
前の記事
Verilogのステートマシンを細かく説明 2020.07.23
-
次の記事
VHDLのステートマシンを細かく説明 2020.07.25

コメントを書く