論理回路入門とか書いてしまったが、VHDL の記述を勉強してみようという 内容にする。
VHDL をざっとながめてみると、コンピュータ言語にまぁ似ているといえば 似ている。ソフトの人間の立場だと、回路図から入るより VHDL から入った 方が良いのかも知れない。
VHDL の記述で注意しないといけないのは、
らしい。
ここでは、VHDL をつかって簡単なステートマシンを作ることをめざす。
-- ライブラリ宣言 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; -- エンティティ宣言 entity usb_null is Port ( DATA : inout std_logic_vector(7 downto 0); CLK : in std_logic; RXF : in std_logic; TXF : in std_logic; EEGNT : in std_logic; RESET : in std_logic; RD : out std_logic; WR : out std_logic; EEREQ : out std_logic; DI1 : in std_logic; DO1 : out std_logic; CK1 : out std_logic; MS1 : out std_logic; DI2 : in std_logic; DO2 : out std_logic; CK2 : out std_logic; MS2 : out std_logic); end usb_null; -- アーキティクチャ本体 architecture behavioral of usb_null is -- 信号宣言 signal ltxf : std_logic; signal lrxf : std_logic; signal data_gate : std_logic; signal out_data : std_logic_vector(7 downto 0); begin DO1 <= 'Z'; CK1 <= 'Z'; MS1 <= 'Z'; DO2 <= 'Z'; CK2 <= 'Z'; MS2 <= 'Z'; EEREQ <= 'Z'; process (CLK) begin if (CLK' event and CLK = '0') then lrxf << RXF; ltxf << TXF; end if; end process; end behavioral;
上は 内容的には、ほとんど意味のないもの。
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity usb_null is Port ( DATA : inout std_logic_vector(7 downto 0); CLK : in std_logic; RXF : in std_logic; :
CK1 <= 'Z';ってのは、いつでも CK1 に 'Z' を入れているってこと。当然ながら、 他のところで、CK1 に値を入れることはできない。ここらあたりが、 逐次処理ではないから気をつけることになるのかな。
process (CLK) begin if (CLK' event and CLK = '0') then lrxf << RXF; ltxf << TXF; end if; end process;
CLK ------+ +--------+ +--------+ +--------+ +--------+ +--------+ +--------+ ↓ ↓ ↓ TXF --------------+ +----------------- +------------------------------+ ltxf >< >< >< >< .......------------------+ +--- +-----------------------------------+ltxf は、こんな風に状態遷移するわけだ。
これだけの知識で、ステートマシンを書くのはたいへんそうだ。
をみると、
type STATE_T is ( S0, S1, S2, S3 ); signal STATE : STATE_T; : case STATE is when S0 => 文1 when S1 => 文2 when S2 => 文3 when S3 => 文4 end case;
なんて記述があるねぇ。
とりあえず case 文を使って state machine を作ってみることにする。
課題
電子工作/ボード設計 に出てくる、 電子工作/XC9572XLと8U245AMで作るUSBシリアルIO用の回路 を使って、もうすこし簡単ななにかを作ってみる。
まずは、データを 受け取ったら それを送り返す そういうものを考えてみる。
入出力で関係するものは以下のもの。
Port ( DATA : inout std_logic_vector(7 downto 0); CLK : in std_logic; RXF : in std_logic; TXF : in std_logic; RD : out std_logic; WR : out std_logic);
タイミングは、
RXF --------- ------------ ↓_____________________↑ RD --------------- ---------------- ↓________↑ DATA --------------< >----------- RD の立ち下がりを契機にして、DATA が出力される。 RD の立ち上がりを契機にして、DATA の出力が止まる。 データが来れば、RXF は、1 -> 0 になる。 RD を↓↑することによって、データが空になれば、RXF は 1 になる。
TXF --------- ___________________↑ WR ---------- ____↑ ↓____________ DATA ----------< >---- WR を ↑↓ することによって、データを書き込むが、↓ の前後でデータが 出ていないといけない。 また、書き込むことによって、バッファが Full になれば、TXF が 0 -> 1 に なる。
必要な情報はこれだけのはず。
設計してみる。
まずは、タイミングの図を書くことが必要。
CLK ----+ +---------+ +---------+ +--------- +---------+ +---------+ +---------+ | | | | | | | RD -----+ +-------------------------------------------------- +---------+ ↑とりこみ | | | | | | | WR +---------+ ------------------------+ +------------------------------- DATA ----------------------< WRITE データ >---------------------- | | | | | | | 状態 | READ ステート | WRITE ステート |
TXF,RXF の存在を無視できれば、上のようなタイミングで READ / WRITE を くり返せばよいわけだ。
で、読もうとするときに RXF がもし 1 なら、READ するデータが ないと いうことになる。 そういう場合は、READ ステートに先だって、RXF 待ちのステートを 挿入する。
また、書こうとするときに WXF がもし 1 なら、buffer full ということになる。 そういう場合は、WRITE ステートに先だって、TXF 待ちのステートを 挿入する。
一応書いてみた。
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity usb_lb is Port ( DATA : inout std_logic_vector(7 downto 0); CLK : in std_logic; RXF : in std_logic; TXF : in std_logic; EEGNT : in std_logic; RESET : in std_logic; RD : out std_logic; WR : out std_logic; EEREQ : out std_logic; DI1 : in std_logic; DO1 : out std_logic; CK1 : out std_logic; MS1 : out std_logic; DI2 : in std_logic; DO2 : out std_logic; CK2 : out std_logic; MS2 : out std_logic); end usb_lb; architecture behavioral of usb_lb is type STATE_T is (Wait_Read, Read, Wait_Write, Write); signal state: STATE_T; signal latch : std_logic_vector(7 downto 0); signal lrxf : std_logic; signal ltxf : std_logic; begin DO1 <= 'Z'; CK1 <= 'Z'; MS1 <= 'Z'; DO2 <= 'Z'; CK2 <= 'Z'; MS2 <= 'Z'; EEREQ <= 'Z'; process (CLK) begin if (RESET = '0') then RD <= '1'; WR <= '0'; DATA <= (others => 'Z'); lrxf <= '1'; state <= Wait_Read; else if (state = Read and CLK = '0') then RD <= '0'; else RD <= '1'; end if; if (state = Write and CLK = '0') then WR <= '1'; else WR <= '0'; end if; if (state = Write) then DATA <= latch; else DATA <= (others => 'Z'); end if; if (CLK' event and CLK = '0') then lrxf <= RXF; ltxf <= TXF; case state is when Wait_Read => if (lrxf = '0') then state <= Read; end if; when Read => if (ltxf = '0') then state <= Write; else state <= Wait_Write; end if; when Wait_Write => if (ltxf = '0') then state <= Write; end if; when Write => if (lrxf = '0') then state <= Read; else state <= Wait_Read; end if; end case; end if; if (CLK' event and CLK = '1') then if (state = Read) then latch <= DATA; end if; end if; end if; end process; end behavioral;
Pin Freeze File: version E.37 9572XL64 XC9572XL-5-VQ64 txf S:PIN1 rxf S:PIN2 reset S:PIN23 clk S:PIN51 rd S:PIN63 wr S:PIN64 ck1 S:PIN45 ck2 S:PIN40 do1 S:PIN44 do2 S:PIN39 eereq S:PIN4 ms1 S:PIN43 ms2 S:PIN38 data<0> S:PIN52 data<1> S:PIN56 data<2> S:PIN57 data<3> S:PIN58 data<4> S:PIN59 data<5> S:PIN60 data<6> S:PIN61 data<7> S:PIN62
できたリポートファイルは、こんな感じ
cpldfit: version E.37 Xilinx Inc. Fitter Report Design Name: usb_lb Date: 8-11-2002, 0:23AM Device Used: XC9572XL-5-VQ64 Fitting Status: Successful **************************** Resource Summary **************************** Macrocells Product Terms Registers Pins Function Block Used Used Used Used Inputs Used 21 /72 ( 29%) 49 /360 ( 13%) 12 /72 ( 16%) 21 /52 ( 40%) 26 /216 ( 12%) Device : XC9572XL-5-VQ64 T T T c d m T G c d m V T T T T I I I k o s I N k o s C I I I I E E E 1 1 1 E D 2 2 2 C E E E E ----------------------------------------------- /48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 \ TIE | 49 32 | TIE TIE | 50 31 | TIE clk | 51 30 | TCK data<0> | 52 29 | TMS TDO | 53 28 | TDI GND | 54 27 | TIE VCC | 55 26 | VCC data<1> | 56 XC9572XL-5-VQ64 25 | TIE data<2> | 57 24 | TIE data<3> | 58 23 | reset data<4> | 59 22 | TIE data<5> | 60 21 | GND data<6> | 61 20 | TIE data<7> | 62 19 | TIE rd | 63 18 | TIE wr | 64 17 | TIE \ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 / ----------------------------------------------- t r V e T T T T T T T T T G T T x x C e I I I I I I I I I N I I f f C r E E E E E E E E E D E E e q
どうも config ファイルは、
-rw-rw-rw- 1 nobody nobody 71928 Aug 11 2002 usb_lb.jed
これらしい。
NAXJP で書いてみる。
# ./naxjp -write usb_lb.jed NAXJP Ver 0.7.3 for Linux (C)Copyright 2001 Nahitafu Device Chain 0. Command 'write'. Device 'XC9572XL-5-VQ64'. File 'usb_lb.jed' Detected device 'XILINX,XC9572XL,Version 3' (ID:39604093) Now processing writing design 'usb_lb.jed'. ............................................................................................................Elapsed time: 8641 ms
おぉ。書けてしまった。
NAXJP のバウンダリスキャンで調べてみる
./naxjp -bscan XC9572VQ64 NAXJP Ver 0.7.3 for Linux (C)Copyright 2001 Nahitafu Device Chain 0. Command 'bscan'. Device 'XC9572VQ64'. -------- Welcome to NAXJP boundary scan shell -------- (1:XC9572VQ64@run)$ pin 1 DEV:1 PIN:1 (FB2_10) STATE=0(i). EXTEST=0(i) # TXF# 送信可能だから 0 の入力で OK。 (1:XC9572VQ64@run)$ pin 2 # RXF DEV:1 PIN:2 (FB2_11) STATE=1(i). EXTEST=0(i) # RXF# 受信データがまだ来ていないから 1 の入力で OK。 (1:XC9572VQ64@run)$ pin 23 DEV:1 PIN:23 (FB1_12) STATE=1(i). EXTEST=0(i) # RESET# 1 になっているので OK。 (1:XC9572VQ64@run)$ pin 63 DEV:1 PIN:63 (FB2_8) STATE=1(o). EXTEST=0(i) # RD# リードしていないから 1 で OK。 (1:XC9572VQ64@run)$ pin 64 DEV:1 PIN:64 (FB2_9) STATE=0(o). EXTEST=0(i) # WR 送信していないから 0 で OK。 (1:XC9572VQ64@run)$ pin 51 DEV:1 PIN:51 (FB4_10) STATE=1(i). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 51 DEV:1 PIN:51 (FB4_10) STATE=0(i). EXTEST=0(i) # CLK 不定の 入力で OK。 (1:XC9572VQ64@run)$ pin 52 DEV:1 PIN:52 (FB4_12) STATE=1(i). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 56 DEV:1 PIN:56 (FB4_15) STATE=1(i). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 57 DEV:1 PIN:57 (FB4_17) STATE=0(i). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 58 DEV:1 PIN:58 (FB2_3) STATE=1(i). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 59 DEV:1 PIN:59 (FB2_4) STATE=1(i). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 60 DEV:1 PIN:60 (FB2_2) STATE=1(i). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 61 DEV:1 PIN:61 (FB2_5) STATE=1(i). EXTEST=0(i) (1:XC9572VQ64@run)$ # DATA 0 .. 7 入力で OK。
だいたい OK っぽいが...
うーんどうやってデバッグしようか.... バウンダリスキャンが 動いているってことは、PIN に出力さえすれば、結構いろんな情報が見える ってことだ。
使っていないピンが多いから、そこになんか出すようにしてみよう。
とりあえず、3 bit のカウンタ CNT_R, CNT_W を作り pin にアサインしてみた。
rd | 63 18 | TIE wr | 64 17 | TIE \ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 / ----------------------------------------------- t r V e T T T c c c c c c G T T x x C e I I I n n n n n n N I I f f C r E E E t t t t t t D E E e _ _ _ _ _ _ q r r r w w w < < < < < < 0 1 2 0 1 2 > > > > > >
そして、立ち上げて 調べてみると...
(1:XC9572VQ64@run)$ pin 8 DEV:1 PIN:8 (FB1_2) STATE=1(o). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 9 DEV:1 PIN:9 (FB1_5) STATE=0(o). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 10 DEV:1 PIN:10 (FB1_6) STATE=0(o). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 11 DEV:1 PIN:11 (FB1_8) STATE=1(o). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 12 DEV:1 PIN:12 (FB1_3) STATE=0(o). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 13 DEV:1 PIN:13 (FB1_4) STATE=0(o). EXTEST=0(i) (1:XC9572VQ64@run)$
... ん。なぜか 1 バイト まわっている。
で、簡単なプログラムを書いて 5 バイト write してみた。
(1:XC9572VQ64@run)$ pin 8 DEV:1 PIN:8 (FB1_2) STATE=0(o). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 9 DEV:1 PIN:9 (FB1_5) STATE=1(o). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 10 DEV:1 PIN:10 (FB1_6) STATE=1(o). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 11 DEV:1 PIN:11 (FB1_8) STATE=0(o). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 12 DEV:1 PIN:12 (FB1_3) STATE=1(o). EXTEST=0(i) (1:XC9572VQ64@run)$ pin 13 DEV:1 PIN:13 (FB1_4) STATE=1(o). EXTEST=0(i) (1:XC9572VQ64@run)$
6 になっているから、5 増えた。 なんか動いていそうだぞ、これは。
とりあえず、テストの 最終版
テストはもういいやという気になった。次は、ちゃんとしたものを 設計する。続きは、電子工作/XC9572XLと8U245AMで作るUSBシリアルIOへ。
おしまい。
02/08/13 その後
NAXJP をリリースしている、なひたふさんのところで ModelSIMの使い方 のページが出来ていることに気がつく。
ModelSIM というのは、Xilinx の開発ツール WebPack についてくる シミュレータで、無償の starter 版ライセンスを手に入れれば使えるようになる もの。500 行までのソースに対応できるそうだ。XC9572XL 程度なら十分。
このツールの使い方がさっぱりわからなかったので、使うのをあきらめていたが、 上のチュートリアルのおかげで、少し使えそうだ。
実際のマシンでのテストでは、信号線の今の状態を バウンダリスキャンで 見ることができるが、状態がどういう風に遷移しているかつかめない。
ModelSIMでは、外部に出ている信号線 の 状態をプログラム?で変化
させることができて、外部に出ている信号線 の 状態遷移を 時間軸にそって
みることができる。使いこなせることができれば、便利そうだ。
実際のデバイスなぞもっていなくても、仮想的に動かすことができるから、
VHDL によるハード設計を体験するには良いかもしれない。
実際のデバイスを作ってもどうせどこかでバグっているから、
このあたりは避けて通れない。... ただ、
実際のデバイスを作るのを先にするのは、モチベーションを維持するのに
大切なんだが ...ロジアナとかもっていないし、実機でのデバッグをやみくも
にやってもダメのようだ。結局 はまっていたことが、
シミュレータで確認すれば、すぐわかったりするようだ。