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

「VHDLのステートマシンを細かく説明」で製作したステートマシンのテストベンチを解説します。本稿はVerilogと内容的に同じですので、Verilogでの解説が必要な方はこちらを参照してください。
「VHDLのステートマシンを細かく説明」で作成したステートマシンが動作しているのかを確認するにはテストベンチでステートマシンの動作を見ます。テストベンチの全コードを次に示します。
-- TITLE: "TB_MCP3002drv.vhd" -- MODULE NAME: TB_MCP3002drv -- PROJECT CODE: -- AUTHOR: (****@nakaharagiken.com) -- CREATION DATE: 2020.7.25 -- SOURCE: -- LICENSE: Copyright (c) 2020 nakaharagiken All rights reserved. -- DESCRIPTION: MCP3002drv.vhdのテストベンチ -- NOTES TO USER: -- SOURCE CONTROL: -- REVISION HISTORY: v0.1 2020.7.25 First edition library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_unsigned.all; use IEEE.std_logic_arith.all; entity TB_MCP3002drv is end TB_MCP3002drv; architecture sim of TB_MCP3002drv is component MCP3002drv is port ( clock: in std_logic; -- system clock nreset: in std_logic; -- asynchronous reset ____reset___|~~~normal~~~ enable: in std_logic; -- イネーブル _________|~|_____________ SPI_ncs: out std_logic; -- SPIチップセレクト信号:プルアップ ~~~|_________________|~~~ SPI_clk: out std_logic; -- SPIクロック信号 SPI_MOSI: out std_logic; -- SPI MOSI SPI_MISO: in std_logic; -- SPI MISO :プルダウン ch0_dat: out std_logic_vector(9 downto 0); -- ADCデータチャンネル0 ch1_dat: out std_logic_vector(9 downto 0); -- ADCデータチャンネル1 dataset: out std_logic; -- ADCデータチャンネル0と1のデータ確定 _____|~|_________________ busy: out std_logic -- 本ブロック動作中 _________|~~~busy~~~~~~~~ ); end component; constant SYSCLK_PERIOD : time := 100 ns; -- 10MHz signal i_clock: std_logic; -- system clock signal i_nreset: std_logic; -- asynchronous reset ____reset___|~~~normal~~~ signal i_enable: std_logic; -- イネーブル signal o_SPI_ncs: std_logic; -- SPIチップセレクト信号:プルアップ ~~~|_________________|~~~ signal o_SPI_clk: std_logic; -- SPIクロック信号 signal o_SPI_MOSI: std_logic; -- SPI MOSI signal i_SPI_MISO: std_logic; -- SPI MISO :プルダウン signal o_ch0_dat: std_logic_vector(9 downto 0); -- ADCデータチャンネル0 signal o_ch1_dat: std_logic_vector(9 downto 0); -- ADCデータチャンネル1 signal o_dataset: std_logic; -- ADCデータチャンネル0と1のデータ確定 _____|~|_________________ signal o_busy: std_logic; -- 本ブロック動作中 _________|~~~busy~~~~~~~~ begin inst_MCP3002drv : MCP3002drv port map( clock => i_clock, -- in std_logic system clock nreset => i_nreset, -- in std_logic asynchronous reset ____reset___|~~~normal~~~ enable => i_enable, -- in std_logic イネーブル _________|~|_____________ SPI_ncs => o_SPI_ncs, -- out std_logic SPIチップセレクト信号:プルアップ ~~~|_________________|~~~ SPI_clk => o_SPI_clk, -- out std_logic SPIクロック信号 SPI_MOSI => o_SPI_MOSI, -- out std_logic SPI MOSI SPI_MISO => i_SPI_MISO, -- in std_logic SPI MISO :プルダウン ch0_dat => o_ch0_dat, -- out std_logic_vector(9 downto 0) ADCデータチャンネル0 ch1_dat => o_ch1_dat, -- out std_logic_vector(9 downto 0) ADCデータチャンネル1 dataset => o_dataset, -- out std_logic; ADCデータチャンネル0と1のデータ確定 _____|~|_________________ busy => o_busy -- out std_logic 本ブロック動作中 _________|~~~busy~~~~~~~~ ); ------------------------------------ -- Clock Driver ------------------------------------ process begin i_clock <= '1'; wait for SYSCLK_PERIOD / 2; i_clock <= '0'; wait for SYSCLK_PERIOD / 2; end process; ------------------------------------ -- 信号作成 ------------------------------------ process begin i_nreset <= '0'; -- 初期値 i_enable <= '0'; i_SPI_MISO <= '0'; -- SPI MISO :プルダウン wait for (SYSCLK_PERIOD * 50); i_nreset <= '1'; wait for (SYSCLK_PERIOD * 100); i_enable <= '1'; i_SPI_MISO <= '0'; wait until (o_SPI_ncs = '0'); -- chip select wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 1 wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- 2 down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 2 up wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- 3 down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 3 up wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- 4 down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 4 up wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B9 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B9 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B8 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B8 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B7 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B7 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B6 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B6 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B5 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B5 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B4 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B4 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B3 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B3 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B2 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B2 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B1 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B1 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B0 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B0 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B0 up null wait for (SYSCLK_PERIOD * 1); wait until (o_SPI_ncs = '1'); wait for (SYSCLK_PERIOD * 1); wait until(o_SPI_ncs = '0'); wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 1 wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- 2 down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 2 up wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- 3 down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 3 up wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- 4 down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 4 up wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B9 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B9 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B8 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B8 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B7 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B7 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B6 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B6 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B5 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B5 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B4 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B4 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B3 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B3 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B2 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B2 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B1 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B1 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B0 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B0 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B0 up null wait for (SYSCLK_PERIOD * 1); wait until(o_SPI_ncs = '1'); wait for (SYSCLK_PERIOD * 1); wait until (o_SPI_ncs = '0'); wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 1 wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- 2 down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 2 up wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- 3 down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 3 up wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- 4 down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 4 up wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B9 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B9 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B8 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B8 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B7 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B7 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B6 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B6 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B5 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B5 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B4 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B4 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B3 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B3 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B2 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B2 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B1 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B1 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B0 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B0 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B0 up null wait for (SYSCLK_PERIOD * 1); wait until (o_SPI_ncs = '1'); wait for (SYSCLK_PERIOD * 1); wait until (o_SPI_ncs = '0'); wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 1 wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- 2 down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 2 up wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- 3 down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 3 up wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- 4 down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- 4 up wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- down wait for (SYSCLK_PERIOD * 1); wait until rising_edge(o_SPI_clk); -- up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B9 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B9 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B8 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B8 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B7 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B7 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B6 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B6 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B5 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B5 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B4 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B4 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B3 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B3 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B2 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B2 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B1 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '0'; wait until rising_edge(o_SPI_clk); -- B1 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B0 down wait for (SYSCLK_PERIOD * 1); i_SPI_MISO <= '1'; wait until rising_edge(o_SPI_clk); -- B0 up null wait for (SYSCLK_PERIOD * 1); wait until falling_edge(o_SPI_clk); -- B0 up null wait for (SYSCLK_PERIOD * 1); wait until (o_SPI_ncs = '1'); wait for (SYSCLK_PERIOD * 1); wait until (o_SPI_ncs = '0'); -- chip select end process; end sim;
40行目constant SYSCLK_PERIOD : time := 100 ns; は本テストベンチのクロック周波数の定数定義です。10MHzで動作させます。
42~52行目でテストベンチのレジスタを宣言していますが、VHDLの場合入力信号と出力信号の区別はありません。テストベンチによっては勝手に色分けしてくれるものもありますが、レジスタ名の頭にi_、o_を付けて入力と出力がわかるようにしています。
75~80行目でクロック信号を生成しています。クロックデューティーは50%になっています。
99行目でwait until (o_SPI_ncs = ‘0’);により、o_SPI_ncsがLowになるまで待ちます。動作の信号は下のデータシートを参照してください。o_SPI_ncsはnCS(一番上の信号:CSの負論理)信号です。

101行目の同じようにwait until rising_edge(o_SPI_clk);でo_SPI_clk信号(CLK信号)がHiになるまで待っています。これがシリアルクロックの1ビット目です。
その後、121行目のi_SPI_MISO <= ‘1’;でMSBビットをi_SPI_MISOに入れています。
172行目のwait until (o_SPI_ncs = ‘1’);でo_SPI_ncsがHiになるのを待っています。
このようにテストベンチは多少野暮ったくても簡素に書く方が動作確認に徹することができると思います。
VHDLの場合、〇〇〇が×××まで待つ。というテストベンチを書くときに、wait until rising_edge(o_SPI_clk);のようにwait untilを使うのが便利です。この場合、o_SPI_clkの立ち上がりエッジを待っています。
本ソースコートはステートマシンの説明用に作成したもので、実機での動作確認を行っていません。実機で使用しないようにお願いします。
-
前の記事
VHDLのステートマシンを細かく説明 2020.07.25
-
次の記事
FPGAのPLLとNCO 2020.07.28

コメントを書く