GHDL on OS X

学科の課題でVHDLを書く必要があったのだけれど、持ち合わせてるPCがMacだけだったので、環境構築でいろいろと苦労した。
推奨環境はAltera社のQuartus II Webpackだったのだが、残念ながら今のところwineを使ってもうまく動かせなかったのでGHDLを使うことにした。
(ちなみにXilinx社のISEは驚くべきことにwineで動作したので、またまとめたいと思っている)

GHDLのインストール

まずはシミュレーション用に波形表示ソフトgtkwaveをインストールする

brew install gtkwave

次に、GHDLを公式からダウンロードしてインストールする。

GHDLの使い方

ひとまず全加算器を動かしてみる。

full_adder.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.all;

entity full_adder is port (
	a : in STD_LOGIC;
	b : in STD_LOGIC;
	c : in STD_LOGIC;
	s : out STD_LOGIC;
	cout : out STD_LOGIC);
end full_adder;

architecture Behavioral of full_adder is

begin

	s <= a xor b xor c;
	cout <= (a and b) or (b and c) or (c and a);

end Behavioral;

全加算器の実装は回路をそのままVHDLに起こしただけ。

full_adder_tb.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity full_adder_tb is

end full_adder_tb;

architecture Behavioral of full_adder_tb is
	component full_adder port (
		a : in STD_LOGIC;
		b : in STD_LOGIC;
		c : in STD_LOGIC;
		s : out STD_LOGIC;
		cout : out STD_LOGIC);
	end component;

	signal a : STD_LOGIC;
	signal b : STD_LOGIC;
	signal c : STD_LOGIC;
	signal s : STD_LOGIC;
	signal cout : STD_LOGIC;

begin
	u0: full_adder port map (
		a => a,
		b => b,
		c => c,
		s => s,
		cout => cout);

process
	type pattern_type is record
		a : STD_LOGIC;
		b : STD_LOGIC;
		c : STD_LOGIC;
		s : STD_LOGIC;
		cout : STD_LOGIC;
	end record;

	type pattern_array is array (natural range <>) of pattern_type;
	constant patterns : pattern_array :=
	(('0','0','0','0','0'),
	('0','0','1','1','0'),
	('0','1','0','1','0'),
	('0','1','1','0','1'),
	('1','0','0','1','0'),
	('1','0','1','0','1'),
	('1','1','0','0','1'),
	('1','1','1','1','1'));

begin
	for i in patterns'range loop
		a <= patterns(i).a;
		b <= patterns(i).b;
		c <= patterns(i).c;
		wait for 1 ns;
		assert patterns(i).s = s and patterns(i).cout = cout
		report "wrong result for patterns " & integer'image(i) severity error;
	end loop;

	assert false report "end of test" severity note;
	wait;

end process;
end Behavioral;

テストベンチの方は入力の総パターン8つを入れて、それぞれに対応する正しい結果とつきあわせる。

まずは本体のコンパイル

ghdl -a --ieee=synopsys full_adder.vhd

synopsysはSTD_LOGIC_UNSIGNEDを利用するのに必要そう。

そしてテストベンチをコンパイル

ghdl -a --ieee=synopsys full_adder_tb.vhd

次にテストベンチをelaborateする(僕は詳細に何をやっているのかわかっていないが、チュートリアルを見る限りこの手順を踏む必要がありそう)。

ghdl -e full_adder_tb

最後にテストベンチを走らせる。

ghdl -r full_adder_tb --vcd=full_adder.vcd

ghdl -a --ieee=synopsys full_adder.vhd
ghdl -a --ieee=synopsys full_adder_tb.vhd
ghdl -e --ieee=synopsys full_adder_tb
ghdl -r --ieee=synopsys full_adder_tb --vcd=full_adder.vcd
full_adder_tb.vhd:62:8:@8ns:(assertion note): end of test

こんな風にwrong resultのassertが出ずにend of testが出ればテストが通ったことに鳴る。

ちなみに、実行時にvcdファイルを生成しておくと、gtkwaveでシミュレーション結果を見ることができる。

gtkwave full_adder.vcd

f:id:levelfour:20150126090716p:plain

gtkwaveが立ち上がったら、まずは左下ペインの波形ソースを全部ドラッグして右側の黒い領域に引っ張り込む。
それだけだと波形に変化がなくて失敗したのかと思うけど、gtkwaveのデフォルトのレンジが1fs単位になっていてこれがメチャクチャ細かいので、上部ツールバーの虫眼鏡アイコンのマイナスの方を推しまくって縮尺を小さくする。
すると上のキャプチャのように見えると思う。