VHDLの簡単なシミュレーション方法(簡易的な任意波形の生成方法)

# FPGAで波形生成

FPGAで波形を生成するには、いつくか方法ある。周期関数で周期を変更することをやりたい場合は、ROMに１周期分の波形をいれておいて、そのサンプリングを間引くことで早い周波数の波を生成される方法として、[ダイレクトデジタルシンセサイザ (DDS)](http://www.picfun.com/vhdleqframe.html) が知られている。ここでは、波形をROMにいれておいて、それを繰り返し再生するだけのシンプルなものを紹介する。

シミュレーションの方法は、[VHDLの簡単なシミュレーション方法(初学者向け)](https://qiita.com/yamadasuzaku/items/d67fedd4fea6ce351718) を前提に記載してます。

## python で波形生成

特に言語は何でもよいが、ここでは、sinを一周期分生成して、そのあとにゼロが続くような例を試すことにする。14bitのDA変換器をイメージして、振幅を13bitのちょっと小さいくらいの設定にしたがこれは何でも良い。

``` python:
import numpy as np
import math
x = np.arange(60)
A = 2**13/4
y = A * np.sin(  (2*math.pi/60)*x)
x2 = np.zeros(150) # ゼロを150個加える
y2 = np.append(y,x2)
y2.astype(int) # VHDL用に整数にする
```

これでy2で生成した文字を下記のコードの signal sine : memory_type を作るのにコピペとかして使う。

## VHDLのコード

生成した波形を integer と std_logic_vector の両方で持つような例を示す。シミュレーションの世界であれば interger でよいが、現実のAD/DA変換を扱う場合などは std_logic_vector にする場合が多いと思うので。

``` VHDL:simplesine_tb.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_signed.all;
--use ieee.numeric_std.all;

entity simplesine_tb is
end entity;

architecture sim of simplesine_tb is

    constant ClockFrequency : integer := 1000e6; -- 1 GHz
    constant ClockPeriod    : time    := 1000 ms / ClockFrequency;

    constant MaxAdc : integer := 2**13; -- max bit of ADC
    constant Maxlen : integer := 210; -- length of buffer

    signal Clk : std_logic := '1';
    signal dataout : std_logic_vector(14 downto 0) := (others => '0');
    signal dataout_i : integer range -MaxAdc to MaxAdc :=0;

    signal i : integer range 0 to Maxlen:=0;

    type memory_type is array (0 to Maxlen-1) of integer range -MaxAdc to MaxAdc -1;
    --ROM for storing the sine values generated by python
    -- import numpy
    -- import math    
    -- x = np.arange(60)
    -- A = 2**13/4 # 0.5 V
    -- y = A * np.sin( (2*math.pi/60)*x )
    -- x2 = np.zeros(150)
    -- y2 = np.append(y,x2)
    -- y2.astype(int)
    signal sine : memory_type := (   
    	0,   214,   425,   632,   832,  1023,  1203,  1370,  1521,
        1656,  1773,  1870,  1947,  2003,  2036,  2048,  2036,  2003,
        1947,  1870,  1773,  1656,  1521,  1370,  1203,  1024,   832,
         632,   425,   214,     0,  -214,  -425,  -632,  -832, -1023,
       -1203, -1370, -1521, -1656, -1773, -1870, -1947, -2003, -2036,
       -2048, -2036, -2003, -1947, -1870, -1773, -1656, -1521, -1370,
       -1203, -1024,  -832,  -632,  -425,  -214,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0,     0,     0,     0,     0,     0,     0,
           0,     0,     0);

begin
    -- Process for generating the clock
    Clk <= not Clk after ClockPeriod / 2;

    genwave : process(Clk)
    begin
      --to check the rising edge of the clock signal
    if(rising_edge(Clk)) then    
        dataout <=  conv_std_logic_vector(sine(i),dataout'LENGTH);
        dataout_i <= sine(i);
        i <= i + 1;
        if(i = Maxlen-1) then
        i <= 0;
        end if;
    end if;
    end process;

    -- Testbench sequence
    clktest: process is
    begin
    	wait for 1000 ns;

        assert (false) report "Simulation End!" severity failure;
        wait; 
    end process clktest;

end architecture;

```

##　コンパイル方法

``` bash:compile.sh
#!/bin/sh 
ghdl -a --ieee=synopsys simplesine_tb.vhd
ghdl -e --ieee=synopsys simplesine_tb
ghdl -r --ieee=synopsys simplesine_tb --vcd=simplesine_tb.vcd
```

## 実行結果

### std_logic_vector の表示を Signed Desimal に変換

![スクリーンショット 2020-12-09 23.35.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/08ce9760-eb60-2419-8611-34d4c952491f.png)

### std_logic_vector の表示をAnalogに変換

![スクリーンショット 2020-12-09 23.35.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/9178553e-1788-c211-e940-914ea2e2651f.png)

### 波形の確認

integer の表示も analog にすると、このような波形が見えるはず。

![スクリーンショット 2020-12-09 23.35.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/47005231-7175-1926-4ba1-fddc2f47d42e.png)

### 注意点

std_logic_vector の表示を binary にすると、パッと見で、全然違うように見える。これは負の数を２進数でどう表現するかということで、なんだっけっと思った人は、[負の数（マイナスの数）は「補数」表現で](http://zaq.g1.xrea.com/2sinsuu8.htm) を一読ください。signedを自作した変数をsingedで表示すれば問題ない。

![スクリーンショット 2020-12-09 23.35.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/b1c94652-5f18-1e03-6cf9-8d2ebbee4113.png)