ずっとFPGA初心者（その17：JKフリップフロップ(3)）

# JKフリップフロップ at FPGAボード
[前々回](https://qiita.com/infinite1oop/items/9698be8215f267b8a651)および[前回](https://qiita.com/infinite1oop/items/9248bd8421f6afd3ed1b)の続き。実際のFGPAボード（Odyssey MAX10 FPGA Eval KitおよびQuartus利用）でJKフリップフロップの動作を確認する。

## 回路および真理値表
復習。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/8eb4de70-78e5-2a52-b41d-39b7678f588b.png)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/8cff2afb-7519-91a0-70f2-749957d60d0b.png", width=40%>

## ソースコード
ここでは、[その６：組み合わせ回路](https://qiita.com/infinite1oop/items/3e631fa60f0a8100f4ca)や[その12：関数](https://qiita.com/infinite1oop/items/74cbf7eeb4354bd094e9)の復習も兼ねて、コンポーネント呼び出しや関数を用いている。

まずは、コンポーネント呼び出しのため、回路「JK」を再掲。
```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;
```

下記が、今回のメイン回路（コード）となる。
```vhdl:JKflipflop.vhd
library ieee;
use ieee.std_logic_1164.all;

entity JKflipflop is
  port (CLK : in std_logic;           -- ①
		LED0, LED7 : out std_logic);  -- ②
end;

architecture RTL of JKflipflop is
component JK                          -- ③
  port (
    CLK, J, K : in std_logic;
    Q, Qbar : out std_logic);
end component;

procedure getJK (                         -- ④
	constant NUM : in integer;            -- ⑤
	signal toJ, toK : out std_logic) is   -- ⑥
	begin
		case (NUM mod 14) is              -- ⑦
			when 0	=> toJ <= '0';	toK <= '1';			
			when 3	=> toJ <= '1';	toK <= '1';
			when 4	=> toJ <= '1';	toK <= '1';
			when 7	=> toJ <= '1';	toK <= '0';
			when 10	=> toJ <= '1';	toK <= '1';
			when 11	=> toJ <= '1';	toK <= '1';
			when others => toJ <= '0'; toK <= '0';
		end case;
end getJK;

constant CYCLE : integer := 50000000;          -- ⑧
signal CNT : integer range 0 to CYCLE-1 := 0;  -- ⑨
signal SEC : integer := 0;                     -- ⑩
signal inputJ : std_logic := '0';              -- ⑪
signal inputK : std_logic := '1';
signal outputQ : std_logic := '0';
signal outputQbar : std_logic := '1';
signal TRIG : std_logic := '0';                -- ⑫

begin
	process (CLK)
	begin
		if (rising_edge(CLK)) then             -- ⑬
			if (CNT = CYCLE-1) then
				CNT <= 0;
				SEC <= SEC+1;
				getJK(SEC, inputJ, inputK);    -- ⑭
				TRIG <= '1';                   -- ⑮
			else
				CNT <= CNT+1;
				TRIG <= '0';
			end if;
		end if;
	end process;
	
	LED0 <= not outputQ;                       -- ⑯
	LED7 <= not outputQbar;                    -- ⑰
	
	U1: JK port map(CLK => TRIG, J => inputJ, K => inputK, Q => outputQ, Qbar => outputQbar);                    -- ⑱
	--U1: JK port map(CLK => CLK, J => inputJ, K => inputK, Q => outputQ, Qbar => outputQbar); -- does not work  -- ⑲
	
end RTL;
```
- ①：入力（ここでは、FPGAボードのクロックを割り当てる）
- ②：出力（ここでは、FPGAボードのLED2つ(0と7)を割り当てる）
- ③：回路「JK」（フリップフロップ回路本体）をコンポーネントとして呼び出す手続き
- ④：信号JおよびKに入力するパターンを得るprocedure getJK（関数）
    - ⑤：getJKへの入力（起動からの経過時間(秒)）
    - ⑥：getJKからの出力（信号JおよびKの値）
    - ⑦：14秒を1サイクルとし、毎秒、信号JおよびKを変化させる（目で追える程度の変化）
        - 開始時のQを'0'(Q#を'1')とし、3秒後に反転、4秒後に反転、7秒後にQが'1'、10秒後に反転、11秒後に反転、それ以外は変化なし
- ⑧：本ボードのCPUクロック(50MHz)
- ⑨：クロック用カウンタ
- ⑩：経過時間(秒)
- ⑪：コンポーネントJKへの入力変数および本回路の出力変数
- ⑫：コンポーネントJKへのクロック信号
- ⑬：クロック立ち上がり時の処理
    - ⑭：毎秒、コンポーネントJK用の信号JおよびKを得る
    - ⑮：コンポーネントJKへのクロック信号をON
- ⑯、⑰：QおよびQ#(Qbar)をLEDに反映（負論理のため「not」を使用）
- ⑱：コンポーネントJKの呼び出し

## 実験
上記コードを実行したときの様子。
![S2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/b24e34c2-36e9-57e7-6f12-5c769ce56d4f.gif)
TRIGの値が'1'のときのみ、コンポーネントJKが動作する状況では（コンポーネントJK内のCLKが立ち上がる）、一応、期待どおりとなっている。

### 不具合時
⑱の代わりに⑲を使ったときの状況（1秒ごとではなく、クロック（50MHz）ごとにコンポーネントJKが実質的に動作）が下記であり、QとQbar(Q#)とが同時に'1'（点灯）するタイミングがあった。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/8386f233-824c-ddc2-ae3d-9b25ec06e535.png", width=40%>
何度か有識者からコメントを頂いているが、センシティビティリスト周辺の厳密な定義が必要なような気もする。

## 終わりに
理論的に本当に正しいFPGAコードであったのだろうか、、、。初心者（シロート）を脱していない小生には判断つかないが、部分的には動作しているので、こんなところか。また、「VHDL JK FlipFlop」などで検索すると、真理値表そのものがコードとなっているものも見つかる。
- [VHDL for FPGA Design/JK Flip Flop](https://en.wikibooks.org/wiki/VHDL_for_FPGA_Design/JK_Flip_Flop)

ANDなどの基本ロジック回路だけで、JKフリップフロップをVHDLでつくるのは、？なのかもしれない。ただし、Quartusでは、回路図からVHDLコードを作成できるらしいので、いずれ、その内容を本編の続きとしてトライ（記載）することにした。