GHDL を cygwin で使う

VHDL のコンパイラである GHDL を cygwin で使ってみました。

# まずは cygwin(64bit) 上でのコンパイル
GHDL のコンパイルには Ada の環境が必要です。cygwin の setup から gcc-ada:GNU Compiler Collection(Ada) をインストールします。バージョンは 4.9.3-1 です。
Ada がちゃんとインストールされていれば gnatmake というコマンドがインストールされているはずです。Ada のプログラムを書きコンパイル・実行できるか確認してみます。
次のプログラムを example.adb としてセーブします。

```ada
procedure Example is
begin
   null;
end Example;
```

その後、gnatmake example とうちコンパイル可能であることを確認します。

## hanzer/gVHDL を入手しコンパイル
オリジナルの GHDL は 32bit 環境しか対応していないらしくうまくいきませんでした。そこで、github にある hanzer さんの gVHDL を入手します。
[hanzer/gVHDL](https://github.com/hanzer/gVHDL)
また、ghdl のコンパイルに必要な gcc の環境 gcc-4.9.3 のソースも展開しておきます。その後 gVHDL で configure および make copy-sources を実行します。

```
> $ ./configure --with-gcc=/path/to/gcc/source/dir
> $ make copy-sources
```

with-gcc にはgcc-4.9.3 のソースディレクトリを指定します。すると gcc-4.9.3 に ghdl のソースがコピーされます。あとは gcc のコンパイルと同じ要領で enable-languages に vhdl を指定してコンパイル、そしてインストールを実行します。

```
> $ .configure --enable-languages=vhdl --disable-bootstrap
> $ make
> $ make install
```

## GHDL で Hello World
インストールした ghdl がちゃんと動くか Hello World プログラムで確認します。

```vhdl
     --  Hello world program.
     use std.textio.all; --  Imports the standard textio package.
     
     --  Defines a design entity, without any ports.
     entity hello_world is
     end hello_world;
     
     architecture behaviour of hello_world is
     begin
        process
           variable l : line;
        begin
           write (l, String'("Hello world!"));
           writeline (output, l);
           wait;
        end process;
     end behaviour;
```
ghdl では -a でアナライズ、-e でエラボレートすることができます。アナライズでは vhdl のプログラムを解析して cf というファイルにモジュールの情報を生成するようです。-e で実際の実行可能なオブジェクトを生成します。

```
>$ ghdl -a hello.vhdl
>$ ghdl -e hello.vhdl
>ghdl: bad unit name 'hello.vhdl'
>ghdl: (a unit name is required instead of a filename)
>$ ghdl -e hello_world
>$ ls
e~hello_world.o  hello.o  hello.vhdl  hello_world.exe*  work-obj93.cf
>$ ./hello_world.exe
Hello world!
```

# 簡単なテストベンチを動かしてみる
次の簡単なテストベンチを動かしてみます。

```vhdl
ibrary IEEE, std;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use IEEE.numeric_std_unsigned.all;
use IEEE.std_logic_textio.all;
use std.textio.all;

entity text_io_example is
end text_io_example;

architecture beh of text_io_example is
    signal v : std_logic_vector(5 downto 0);
    signal i : integer;
begin
    process is
    variable line0 : line;
    variable c : std_logic;
    begin
        c := '0';
        write(line0, c);
        writeline(output, line0);
        v <= v - 1;
        i <= i - 1;
        wait;
    end process;
end beh;
```
ghdl では makefile をつくるオプションがあります。単純に --gen-makefile を
実行しただけだとエラーになるので、その前に -a で vhdl ファイルを解析しておきます。

```
> $ghdl --gen-makefile --std=08 text_io_example
> ghdl: cannot find entity or configuration text_io_example
> $ghdl -a --std=08 test_tb.vhdl
> $ls
> test_tb.o  test_tb.vhdl  text_io_example.exe*  work-obj08.cf
> $ghdl --gen-makefile --std=08 text_io_example > makefile
> $ls
> makefile  test_tb.o  test_tb.vhdl  text_io_example.exe*  work-obj08.cf
> $make
> ghdl -e --std=08 text_io_example 
```

ここでは --std=08 オプションをつけています。ghdl は表示に厳密に IEEE のライブラリを定義していて numeric_std は v87(指定なしの時のバージョン) にはありますが、numeric_std_unsigned がありません。各ベンダーは IEEE の正式なライブラリを無視しているようです。std_logic_vecotr への足し算引き算ができるようになるために numeric_std_unsigned が本当は必要なようです。

# Xilinx の FIFO を使用してみる
手元の PC では Vivado の 2015.3 をインストールしてあったので FIFO を使ってみることにします。FIFO を使うには unisims と unimacro を -i でインポートする必要があります。ここでは先の厳密な IEEE の問題を回避するために --ieee=synopsys というオプションを使っています。

```
> $ghdl -i --ieee=synopsys --work=unisim <パス>/unisims/*.vhd
> $$ghdl -i --ieee=synopsys --work=unisim <パス>/unisims/primitive/*.vhd
> $ghdl -i --ieee=synopsys --work=unimacro <パス>/unimacro/*.vhd
> $ls -1 *.cf
unimacro-obj93.cf
unisim-obj93.cf
```

これで unisim と unimacor の cf というファイルができました。さらに自分で作った fifo_test.vhdl(FIFO_DUALCLOCK_MACRO を使用したプログラム) と fifo_tb.vhdl(テストベンチ) をアナライズします。

```
> $ghdl -a --ieee=synopsys fifo_test.vhdl
> $ghdl -a --ieee=synopsys fifo_tb.vhdl
```

依存関係をチェックしなくて済むように -m というオプションで一気にコンパイルが可能です。

```
> $ ghdl -m --ieee=synopsys fifo_test
> <ワーニング中略>
> unimacro/FIFO_DUALCLOCK_MACRO.vhd:631:20: no declaration ?for "fifo18"
> unimacro/FIFO_DUALCLOCK_MACRO.vhd:631:20: component name expected
> unimacro/FIFO_DUALCLOCK_MACRO.vhd:664:23: no declaration for "fifo18_36"
> unimacro/FIFO_DUALCLOCK_MACRO.vhd:664:23: component name expected
> unimacro/FIFO_DUALCLOCK_MACRO.vhd:696:20: no declaration for "fifo36"
> unimacro/FIFO_DUALCLOCK_MACRO.vhd:696:20: component name expected
> unimacro/FIFO_DUALCLOCK_MACRO.vhd:729:23: no declaration for "fifo36_72"
> unimacro/FIFO_DUALCLOCK_MACRO.vhd:729:23: component name expected
```

残念、エラーです。FIFO_DUALCLOCK_MACRO に Virtex5 用の記述があって primitive にはそれがないようです。unimacro/FIFO_DUALCLOCK_MACRO.vhd の 627 行目からの 137 行を何とかすると何とかなりそうです。

```
> $ghdl -m --ieee=synopsys fifo_test
> <ワーニング中略>
> analyze unisims/unisim_VCOMP.vhd
> analyze unimacro/unimacro_VCOMP.vhd
> analyze fifo_test.vhdl
> analyze unimacro/FIFO_DUALCLOCK_MACRO.vhd
> analyze unisims/unisim_VPKG.vhd
> analyze unisims/primitive/FIFO18E1.vhd
> analyze unisims/primitive/FIFO36E1.vhd
> elaborate fifo_test
```

V5 の記述をうまく回避するとコンパイルが通りました。当然実行することが出来ます。--stop-time でシミュレーションの時間 --vcd で vcd ファイルの指定ができます。

```
> $ ./fifo_test.exe --stop-time=10us --vcd=fifo_test.vcd
> $ ls *.vcd
fifo_test.vcd
```

これで cygwin + ghdl + vi (あるいは emacs ) というシミュレーション環境を構築することができました。vi を使っている人は開発効率があがるでしょう。