FPGAで、VHDLで書いたinteger信号の範囲は守られるのだろうか
例えばVHDLで下記のようなintegerの信号を定義したとする。
signal sCountVal : integer range 0 to 9;
この信号は0~9の値を取る、と宣言している。
これはFPGAでどのように論理合成されるのだろうか。
FPGA上では信号線で値を表現するので、例えば信号線3本、3bitの信号なら0~7の値を取り、
信号線4本、4bitの信号なら0~15の値を取る。
値の取りうる範囲は2のべき乗にしかなり得ない。
0~9を表現できるのは4bitだが、では10~15はどうなるのだろうか。
10~15の値にならないように論理合成されるのだろうか。
DE0-CVでちょっと試してみよう。
DE0-CVの4つのプッシュスイッチのうち2つ(KEY0とKEY1)と7セグメントLEDを使って動作を確認する。
KEY0を押したらintegerのカウンターをカウントアップ
KEY1を押したらintegerのカウンターをカウントダウン
カウンターの値を7セグメントLEDに出力
という回路を作った。
コンパイルはQuartus Prime 17.0で行った。
-------------------- -- 略 -------------------- -- DE0-CVのPushスイッチ4つの立ち上がりエッジ信号 signal sKEY_hiedge : std_logic_vector( 3 downto 0); -- integerのカウンター signal sCountVal : integer range 0 to 9; begin -------------------- -- チャタリング除去とか立ち上がりエッジ検出とかの記述 -- 略 -------------------- -- up/down count process (CLOCK_50, RESET_N) is begin if (RESET_N = '0') then sCountVal <= 0; elsif rising_edge(CLOCK_50) then if (sKEY_hiedge(0) = '1') then sCountVal <= sCountVal + 1; -- KEY0を押したらカウントアップ elsif (sKEY_hiedge(1) = '1') then sCountVal <= sCountVal - 1; -- KEY1を押したらカウントダウン end if; end if; end process; -------------------- -- 値を7セグメントLEDに出力 -- 略 --------------------
動かしてみた。
FPGAにsofファイルを書き込むと7セグメントLEDに0が表示される。
KEY0を押すとカウントアップする。
9までカウントアップした。
もしVHDLの記述通り、範囲が0-9であるのであれば次のカウントアップでオーバーフローして値が0になるはずである。
KEY0を押してみた。
7セグメントの値がA(16進表記)に変化した。
VHDLで記述したrangeの範囲を超えてしまった。
そのままカウントアップすると、F(16進表記)まで変化して、
もう一度押すとオーバーフローして0に戻った。
ちなみに0からカウントダウンするとFになった。
つまり、FPGAの実装としては4bit信号でカウンターが構成されているということ。
integerのrangeはあくまで何bitの信号とするのか決めるだけであり、値の範囲の制御はちゃんと記述する必要がある。
これを認識しないと思い違いによるバグを生みかねないので注意しよう。
ちなみにSTARCではintegerのrangeの範囲は2のべき乗にしなければならないというルールがあったはず。
(うろ覚えだけど)
追記:
ModelSimでカウントアップしてみた。
integerの範囲を超えるたときにFatal ErrorになってSimが止まった。
SimのFatal Errorが誤動作の原因になるような記述を見つける指標になると思う。