ロード トップ 参照元 逆検索 検索 ヘルプ

[logo] 電子工作/論理回路入門


SuzTiki:電子工作

論理回路入門とか書いてしまったが、VHDL の記述を勉強してみようという 内容にする。

VHDL をざっとながめてみると、コンピュータ言語にまぁ似ているといえば 似ている。ソフトの人間の立場だと、回路図から入るより VHDL から入った 方が良いのかも知れない。

VHDL の記述で注意しないといけないのは、

らしい。


ここでは、VHDL をつかって簡単なステートマシンを作ることをめざす。

上は 内容的には、ほとんど意味のないもの。

これだけの知識で、ステートマシンを書くのはたいへんそうだ。

をみると、

       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);

タイミングは、

必要な情報はこれだけのはず。


設計してみる。

まずは、タイミングの図を書くことが必要。

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;

できたリポートファイルは、こんな感じ

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 によるハード設計を体験するには良いかもしれない。
実際のデバイスを作ってもどうせどこかでバグっているから、 このあたりは避けて通れない。... ただ、 実際のデバイスを作るのを先にするのは、モチベーションを維持するのに 大切なんだが ...ロジアナとかもっていないし、実機でのデバッグをやみくも にやってもダメのようだ。結局 はまっていたことが、 シミュレータで確認すれば、すぐわかったりするようだ。


(最終更新 Thu Mar 30 19:02:14 2006)