エレキ素人が何か考える（その10）＆ずっとFPGA初心者（その15）：JKフリップフロップ(1)

# FPGA環境でJKフリップフロップの動作を確認（シミュレーション編）
[エレキ素人が何か考える（その９）：JKフリップフロップ](https://qiita.com/infinite1oop/items/b4eee3e9571997b9b6d6)での予告のどおり、ハードウェアに近い環境であるFPGAで、動作確認を行う。今回はシミュレーション編。

### CLK付きJKフリップフロップ回路
回路の復習。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/d3ece139-b6d5-4174-2556-27c132418428.png)

### 開発環境
[その１](https://qiita.com/infinite1oop/items/4b0f03b97ed859fbd954)からずっと同じOdyssey MAX10 FPGA Eval Kitを対象として、Quartusを利用する。

### コード
#### 本体
```vhdl:JK.vhd  
library ieee;
use ieee.std_logic_1164.all;

entity JK is
  port (CLK, J, K : in  std_logic;  -- ①
        Q, Qbar : out std_logic);   -- ②
end;

architecture RTL of JK is
signal out1 : std_logic := '0';   -- ③
signal out2 : std_logic := '0';
signal out3 : std_logic := '1';
signal out4 : std_logic := '0';

begin
	process (CLK)
	begin
		if (rising_edge(CLK)) then  -- ④
			out1 <= J and out3;
			out2 <= K and out4;
			-- out3 <= not(out1 or out4); -- does not work  -- ⑤
			-- out4 <= not(out2 or out3); -- does not work
		end if;
	end process;
	
	out3 <= not(out1 or out4);  -- ⑥
	out4 <= not(out2 or out3);
	Q <= out4;
	Qbar <= out3;
end RTL;
``` 
- ①：入力信号（CLK、J、K）
- ②：出力信号（Q、Qbar(Q#)）
- ③：回路内信号（out1、out2、out3、out4）の定義および初期化（Q='0'、Q#='1'となるように値を選択）
- begin - end内は同時処理
- ④：CLK（クロック）立ち上がり時の回路内のAND部分の処理
- ⑥：回路内のNOR部分の処理

VHDLが理解できれば、ロジックどおりなので、詳細な説明は不要であろう。

#### シミュレーションコード
信号JおよびKを変化させてシミュレーションする。信号の組み合わせは、(0,0)、(0,1)、(1,0)、(1,1)の4通り、よって状態の変化は、4x3=12通り存在するので、それらをCLKの有無を加えて、シミュレーションするコードが下記となる（全体で10回の繰り返しあり）。
```vhdl:testsim.vhd
library ieee;
use ieee.std_logic_1164.all;

entity testsim is
end testsim;

architecture sim of testsim is
  constant t : time := 1 us;
  signal CLK, J, K : std_logic;
  signal Q : std_logic := '0';
  signal Qbar : std_logic := '1';

  component JK
    port (J, K, CLK : in std_logic;
          Q, Qbar : out std_logic);
  end component;

  begin
    u1: JK
      port map (CLK => CLK, J => J, K => K, Q => Q, Qbar => Qbar);
    process begin
      for N in 1 to 10 loop
        CLK <= '0'; J <= '0'; K <= '1'; wait for t;  -- 0 (0,1)
        CLK <= '1'; J <= '0'; K <= '1'; wait for t;
        CLK <= '0'; J <= '1'; K <= '1'; wait for t;  -- 1 (1,1)
        CLK <= '1'; J <= '1'; K <= '1'; wait for t;
        CLK <= '0'; J <= '1'; K <= '0'; wait for t;  -- 2 (1,0)
        CLK <= '1'; J <= '1'; K <= '0'; wait for t;
        CLK <= '0'; J <= '0'; K <= '0'; wait for t;  -- 3 (0,0)
        CLK <= '1'; J <= '0'; K <= '0'; wait for t;
        CLK <= '0'; J <= '0'; K <= '1'; wait for t;  -- 4 (0,1)
        CLK <= '1'; J <= '0'; K <= '1'; wait for t;
        CLK <= '0'; J <= '0'; K <= '0'; wait for t;  -- 5 (0,0)
        CLK <= '1'; J <= '0'; K <= '0'; wait for t;
        CLK <= '0'; J <= '1'; K <= '1'; wait for t;  -- 6 (1,1)
        CLK <= '1'; J <= '1'; K <= '1'; wait for t;
        CLK <= '0'; J <= '0'; K <= '1'; wait for t;  -- 7 (0,1)
        CLK <= '1'; J <= '0'; K <= '1'; wait for t;
        CLK <= '0'; J <= '1'; K <= '0'; wait for t;  -- 8 (1,0)
        CLK <= '1'; J <= '1'; K <= '0'; wait for t;
        CLK <= '0'; J <= '1'; K <= '1'; wait for t;  -- 9 (1,1)
        CLK <= '1'; J <= '1'; K <= '1'; wait for t;
        CLK <= '0'; J <= '0'; K <= '0'; wait for t;  -- 10 (0,0)
        CLK <= '1'; J <= '0'; K <= '0'; wait for t;
        CLK <= '0'; J <= '1'; K <= '0'; wait for t;  -- 11 (1,0)
        CLK <= '1'; J <= '1'; K <= '0'; wait for t;
                                                     -- 12 (0,1)
      end loop;
    end process;
end sim;
```

## シミュレーションによる検証
上記シミュレーションコード（testsim.vhd）を用いて、本体コード（JK.vhd）をテストした結果（1サイクル+α）が下記となる。
![wave2022Apr23.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/9eb803a4-536f-c8f0-037b-318f23758db6.png)
最初の数回分を一部拡大表示（上から、CLK、J、K、Q、Q#(Qbar)）。さらに真理値表を再掲。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/7dca19a9-6708-4158-1eea-fa0b5a261be1.png)  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/8d139ddc-e6ec-b021-8102-bc49a3b40c6c.png", width=39%>
CLK立ち上がり時に、期待どおりの結果が得られていることがわかる。

また、上述した本体コードの⑥以下2行の代わりに、⑤以下2行を用いたときの結果は下記となり、QとQbarとが反転していないタイミング（同じ値となる）が存在する。
![waveFailure2022Apr23.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/584cb409-2df4-5be5-326d-fce2921de046.png)
回路上の左のAND回路と右のNOR回路は、Process文内で順番に実施してはいけないということを意味するはず、、（FPGA内で同時処理が必要）。
（間違っていたら、どなたか、ご指摘ください。）

## 次は
上記本体コードをコンポーネントとして用い、FPGAボードで検証を行う。