FT601を使った通信システムを設計してみよう(その1)
前回の「FTDI SuperSpeed-FIFO Bridge FT601を使ってみよう」では、FTDI社のFT601を紹介しつつ、FT601+FPGAによるUSBデバイスの設計例として、USBホスト側であるPCから送られたデータをそのままPC側へ送り返す”ループバック”を実現する回路を作ってみました。PC側で送受信データの一致を確認することで、USBデバイス内でのFT601の制御やデータの受け渡しの設計に問題が無いことを確認しました。
ここでは、実用的なシステムへ発展させるすべく、PCからUSBによるデータ送受信で制御するUSBデバイスの通信システムについて、その設計例を示します。(FPGAの回路はすべてVHDLで記述しています。開発環境はQurtus Prime Lite Edition 20.1.1で、メガファンクションのFIFO-IPを使っています。)
どんな仕様にするか
このUSBデバイスを制御するPCのソフトウェアから見て、このUSBデバイスはリードライト可能なアドレス空間4KBとリード専用のアドレス空間4KBの合計8KBのリソースがあるものとします。PCのソフトウェアはこのUSBデバイスを制御するにあたり、4KBのデータ(リードライト可能なアドレス空間の全データ)を送信し、8KBのデータを(リードライト可能かアドレス空間とリード専用のアドレス空間を合わせた全データ受信することとします。

USBデバイスの仕様を示します。
今回作成したUSBデバイスは、PCソフトウェアからの命令に応じてFPGAに接続されたLEDを点灯制御すること、FPGAに接続されたスイッチ入力の状態をモニタしてPCに返すこと、これだけの機能を持ちます。そのUSBデバイスをどように構築するか示してきます。

USBデバイスはFT601とFPGAで構成されます。FPGAの中は、主にFT601制御部とローカル回路制御部、そしてこれらの間をつなぐ、IN-FIFO部とOUT-FIFO部で構成されます。それぞれのFIFOは32bit幅×深さ1024の4KBずつの大きさです。
FT601からローカル制御部へのデータの流れ
FT601制御部は、FT601から”データ読み出し可能”イベントを受け取るとFT601からデータ(今回の仕様では4KB)を全て読み出してOUT-FIFO部にデータを書き込みます。OUT-FIFO部が満タンになるとローカル回路制御部がOUT-FIFOのデータをすべて読み出してローカル回路制御部配下の各回路(レジスタ)へ分配します。(図では、この各回路は、デバイス1-0(R/W)、デバイス1-1(R/W)、デバイス1-2(R/W)、デバイス1-3(R/W)が該当します。いずれもリード・ライト可能なレジスタを持った回路です。)
ローカル制御部からFT601へのデータの流れ
IN-FIFO部が空になるとローカル回路制御部が配下の回路(レジスタ)からデータを集荷して、IN-FIFO部に書き込みを行いIN-FIFO部を満たします。IN-FIFO部が満タンになるとFT601制御部はIN-FIFO部からデータを読み込んでFT601に書き込みます。(図では、この各回路は、デバイス1-0(R/W)、デバイス1-1(R/W)、デバイス1-2(R/W)、デバイス1-3(R/W)、デバイス2-0(R)、デバイス2-1(R)、デバイス2-2(R)、デバイス2ー3(R)が該当します。後半3つの回路はリードオンリーのレジスタを持った回路です。)
クロックドメイン
青色で示したクロックドメインと、緑色で示したクロックドメインがあります。青色で示したクロックドメインでは、FT601から出力されるクロック(100MHz)に同期して動作します。緑色で示したクロックドメインではFPGAで生成したクロック(100MHz)に同期して動作します。この両者のクロックは非同期です。
FIFOを境にデータの受け渡し方法や速度速度が異なる
IN-FIFO部やOUT-FIFO部はどちらもライト制御とリード制御は別々のクロックにより動作する非同期FIFOです。それぞれのFIFOは1クロックにつきデータのライトやリードを行うことができる高速なインターフェースを持ちます。FT601制御部はFT601のクロックに同期してFT601からデータをリードしたりFT601にライトするサイクルを発行します。同様にOUT-FIFO部へのライトサイクルやIN-FIFO部へのリードサイクルも1クロックについきデータをリードまたはライトします。FT601と両方のFIFOの間のデータのやりとりはバーストアクセスで行うため非常に高速です。
一方、ローカル回路制御部からはそれぞれのFIFOに対して、ローカル回路側のクロックに同期して比較的遅いアクセスサイクル(1クロックではなく数クロック使う)でデータのライトやリードが実行されます。FIFO側は上述のとおり高速動作可能ですが、FIFOへ書き込むデータの準備や、FIFOやら読み出したデータの受け取りがゆっくりな仕様としているということです。このようにFIFOを境に異なるインターフェース設計としているのは、ローカル回路制御部配下にはいろんなインターフェスを持った回路、遅い回路が繋がる可能性があるため、FT601側のような高速な仕様とすることを避けました。

システムのイメージを持ってもらったところで、それぞれの回路の役割を見ていきましょう。
FT601制御部
FT601制御部は、FT601を245同期モードで制御する回路です。FT601は送信用受信用をともに4KBのFIFOを持ったモードにしておきます。(これはFT601のコンフィグレーションツールソフトウェアで可能です。)このFIFOが”空である””満タンである”というステータス情報をFT601が出力するので、FT601制御部はFT601のFIFOに対してデータを読み出したり書き込んだりします。100MHzクロックに同期して1クロックで32bit幅データを連続で読み書きできるため非常に高速に処理できます。
FT601制御部はFPGA内に用意したFIFOに対するデータの書き込みや読み込み処理も行います。これはFT601から供給されるクロックに同期して行われます。FT601制御部がFT601とFPGA内FIFOの双方を制御することで、FT601とFPGA内FIFOの間のデータ転送を担います。
FPGA内FIFO
これは、Quartus Primeで無償で提供されるメガファンクション・ウィザードを用いて、入力と出力が非同期でデータ幅が32bit深さが1024のFIFOを定義し、2つのインスタンスを作りました。一つはFT601からFPGA内回路へのデータ転送に用いるためのOUT-FIFO用として、他方はFPGA内回路からFT601へのデータ転送に用いるためのIN-FIFO部用として。
ローカル回路制御部(バスコントローラー、アドレスデコーダー、各デバイス)
ここではソフトウエアで制御したい各デバイスをローカル回路と呼び、それとアドレスデコーダー、バスコントローラ-とを合わせてローカル回路制御部と呼ぶこととします。バスコントローラーはアドレスバスやデータバスをコントロールするもので、一般にはCPUが担います。ソフトウェアがアクセスしたいレジスタに割り当てられたアドレスを発行し、データのライトサイクルやリードサイクルを発行します。下図は一般的なバスコントローラとアドレスデコーダー、各デバイスの接続や役割をを示した図です。

今回は、CPUは用いていていませんので、このバスコントローラーを実装することにします。ソフトウェアもいませんのでデータのやりとりをするアドレスも生成しなければなりません。ここで実装するバスコントローラはOUT-FIFO部から読み出された4KBのデータを各デバイスに配分するために、デバイスに対してアドレスを発行しながらライトサイクルを実行します。このときアドレスバスの信号をデコードして、どのデバイスにデータを配りたいのかセレクトする信号をアドレスレコーダーが作り出します。このセレクト信号をCS(チップセレクト)信号と呼びます。(セレクト信号と呼ぶかも)このアドレスデコーダーの仕様は後述するアドレスマップに基づいて設計します。デバイスからのデータの読み出しも同様にアドレスバスを駆動して、データのリードサイクルを実行することで各デバイスのレジスタからデータを読み出して、IN-FIFO部へ書き込んでいきます。

”OUT-FIFOが満タンだ”という信号をトリガーとして、バスコントロールシーケンサが、FT601→デバイス方向の流れのデータ転送のためのサイクルをシーケンシャルに作動します。 そして”IN-FIFOが満タンだ”という信号をトリガーとして、バスコントロールシーケンサが、デバイス→FT601方向のデータ転送のためのサイクルをシーケンシャルに作動します。
アドレス空間
PCのソフトウェアを設計するエンジニアとUSBデバイスを設計するエンジニアとの間で、「○○番地はLED制御用のレジスタで、そのレジスタのbit2は、LED2を制御するよう割り付けしよう!」とアドレスマップ(メモリマップとも言うことも)を取り決めます。ここで送信データについて考えると送信データは4KBあるわけで、4KBのデータのうち、どのデータが何用のレジスタに定義されているのか取り決めが無いと双方のエンジニアが設計できませんよね。また、先頭から何番目というインデックス指定で設計は可能ですが、それぞれのレジスタに具体的なアドレス(番地)が付与されているようが、議論や実装及び設計検証が容易になるでしょう。ここでは、次のようにアドレスマップを定義しました。


合計8KBの空間があるのですが、使ってるのはわずかですね。10個のLEDを点灯制御するのと14個のスイッチの状態を読み取るだけなので、ほとんどが未使用のデータ空間になります。
実際のコード設計
ここまでは、紹介する設計の動き全般、大まかな仕様を把握してもらうために、概念的な話をしてきました。いきなりコードを見る前にぼんやりとでも概要を把握していた方がコードを理解するのが楽だからです。今回のFPGAのプロジェクトのRTL一覧を示します。
- TOP.vhd
- FT601_245SYNCFIFO.vhd
- BUS_SEQYEBCE_MASTER.vhd
- DECODE.vhd
- DEVICE_01.vhd
- DEVICE_02.vhd
- AdressPackage_IN.vhd
- AdressPackage_OUT.vhd
- ASYNC_FIFO.vhd -- Mega function FIFO IPを利用 ( 32 bits x 1024 words Async FIFO として)
"TOP.vhd"は文字どおりTOPのデザインであり、FPGA外部とのインタフェース信号やクロックの定義、使用するコンポーネントやIPの定義、コンポーネント間の接続を記述しFPGA内回路の全体配線図ともいえます。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity TOP is
port(
SYSTEM_CLK : in std_logic; -- CLOCK_50_B7A, H12:Cyclone5 GX Pin number
-- interface with FT601
RST_N : in std_logic; -- CYclone5 starter kit CPU_Reset Sw(KEY4) is connected AB24: FPGA Pin number
CLK_IN : in std_logic; -- from FT601
TXE_N : in std_logic; -- from FT601, It means that Transmit FIFO is empty
WR_N : out std_logic;
BE : inout std_logic_vector(3 downto 0);
RXF_N : in std_logic; -- from FT601, It means that Receive FIFO is empty
OE_N : out std_logic;
RD_N : out std_logic;
DATA : inout std_logic_vector(31 downto 0) ;
-- interface with Cylone5 starter kit resouces
LEDR0_OUT : out std_logic; -- is connected F7:Cyclone5 GX Pin number
LEDR1_OUT : out std_logic; -- is connected F6:Cyclone5 GX Pin number
LEDR2_OUT : out std_logic; -- is connected G6:Cyclone5 GX Pin number
LEDR3_OUT : out std_logic; -- is connected G7:Cyclone5 GX Pin number
LEDR4_OUT : out std_logic; -- is connected J8:Cyclone5 GX Pin number
LEDR5_OUT : out std_logic; -- is connected J7:Cyclone5 GX Pin number
LEDR6_OUT : out std_logic; -- is connected K10:Cyclone5 GX Pin number
LEDR7_OUT : out std_logic; -- is connected K8:Cyclone5 GX Pin number
SW0_IN : in std_logic; -- is connected AC9:CYcvlone5 Gx Pin number
SW1_IN : in std_logic; -- is connected AE10:CYcvlone5 Gx Pin number
SW2_IN : in std_logic; -- is connected AD13:CYcvlone5 Gx Pin number
SW3_IN : in std_logic; -- is connected AC8:CYcvlone5 Gx Pin number
SW4_IN : in std_logic; -- is connected W11:CYcvlone5 Gx Pin number
SW5_IN : in std_logic; -- is connected AB10:CYcvlone5 Gx Pin number
SW6_IN : in std_logic; -- is connected V10:CYcvlone5 Gx Pin number
SW7_IN : in std_logic; -- is connected AC10:CYcvlone5 Gx Pin number
SW8_IN : in std_logic; -- is connected Y11:CYcvlone5 Gx Pin number
SW9_IN : in std_logic; -- is connected AE19:CYcvlone5 Gx Pin number
KEY0_IN : in std_logic; -- is connected P11:CYcvlone5 Gx Pin number
KEY1_IN : in std_logic; -- is connected P12:CYcvlone5 Gx Pin number
KEY2_IN : in std_logic; -- is connected Y15:CYcvlone5 Gx Pin number
KEY3_IN : in std_logic; -- is connected Y16:CYcvlone5 Gx Pin number
-- for debugging
db_RXF_N_LED : out std_logic; -- LEDG0 is connected L7:Cyclone5 GX Pin number
db_TXE_N_LED : out std_logic; -- LEDG1 is connected K6:Cyclone5 GX Pin number
db_MyFIFO_IN_EMPTY_LED : out std_logic; -- LEDG4 is connected A5:Cyclone5 GX Pin number
db_MyFIFO_IN_FULL_LED : out std_logic; -- LEDG5 is connected B6:Cyclone5 GX Pin number
db_MyFIFO_OUT_EMPTY_LED : out std_logic; -- LEDG6 is connected H8:Cyclone5 GX Pin number
db_MyFIFO_OUT_FULL_LED : out std_logic -- LEDG7 is connected H9:Cyclone5 GX Pin number
);
end entity;
architecture RTL of TOP is
component PLL_100M is
port (
refclk : in std_logic := 'X'; -- clk
rst : in std_logic := 'X'; -- reset
outclk_0 : out std_logic; -- clk 200MHz: not used
outclk_1 : out std_logic; -- clk 100MHz
locked : out std_logic -- export
);
end component PLL_100M;
component FT601_245SYNCFIFO port (
RST_N : in std_logic;
-- interface with FT601
CLK_IN : in std_logic; -- from FT601
TXE_N : in std_logic; -- from FT601, It means that Transmit FIFO is empty
WR_N : out std_logic;
BE : inout std_logic_vector(3 downto 0);
RXF_N : in std_logic; -- from FT601, It means that Receive FIFO is Full
OE_N : out std_logic;
RD_N : out std_logic;
DATA : inout std_logic_vector(31 downto 0);
-- interface with user cercuit
Tx_DATA : in std_logic_vector(31 downto 0); -- write data to FT601
Rx_DATA : out std_logic_vector(31 downto 0); -- read data from FT601
RX_Ready : in std_logic;
TX_Ready : in std_logic;
DATA_SendRequest : out std_logic;
DATA_ReceiveRequest : out std_logic;
FIFO_DATA_Received : out std_logic;
DATA_Received_length : out std_logic_vector(15 downto 0);
FIFO_DATA_Transmitted : out std_logic
);
end component;
-- Mega function FIFO IP ( 32 bits x 1024 words Async FIFO )
component ASYNC_FIFO
PORT
(
aclr : IN STD_LOGIC := '0';
data : IN STD_LOGIC_VECTOR (31 DOWNTO 0);
rdclk : IN STD_LOGIC ;
rdreq : IN STD_LOGIC ;
wrclk : IN STD_LOGIC ;
wrreq : IN STD_LOGIC ;
q : OUT STD_LOGIC_VECTOR (31 DOWNTO 0);
rdempty : OUT STD_LOGIC ;
rdfull : OUT STD_LOGIC ;
wrempty : OUT STD_LOGIC ;
wrfull : OUT STD_LOGIC
);
end component;
component BUS_SEQUENCE_MASTER
port
(
RST_N : in std_logic ; --
CLK_IN : in std_logic ; --
-- IN_FIFO interface
IN_FIFO_FULL : in std_logic ; --
IN_FIFO_EMPTY : in std_logic ; --
IN_FIFO_WCLK : out std_logic ; --
IN_FIFO_WRITE_REQUEST : out std_logic ; --
IN_FIFO_DATA : out std_logic_vector (31 downto 0) ; --
-- OUT_FIFO_interface
OUT_FIFO_FULL : in std_logic ; --
OUT_FIFO_EMPTY : in std_logic ; --
OUT_FIFO_READ_REQUEST : out std_logic ; --
OUT_FIFO_RCLK : out std_logic ; --
OUT_FIFO_DATA : in std_logic_vector (31 downto 0) ; --
-- User interface
WR_CYCLE : out std_logic ; --
RD_CYCLE : out std_logic ; --
AS : out std_logic ; --
WR_PLS : out std_logic ; --
DACK : in std_logic ; --
ABUS : out std_logic_vector (23 downto 0) ; --
DBUS_WR : out std_logic_vector (31 downto 0) ; --
DBUS_RD : in std_logic_vector (31 downto 0) ; --
DEBUG_1 : out std_logic ; --
DEBUG_2 : out std_logic --
);
end component;
component DECODE
port(
RSTb : in std_logic;
CLK_IN : in std_logic;
--* BUS SEQUENCE MASTER Interface *--
AS : in std_logic;
RD_CYCLE : in std_logic;
WR_PLS : in std_logic;
A_BUS : in std_logic_vector (23 downto 0);
DBUS_RD : out std_logic_vector (31 downto 0);
DTACK : out std_logic;
-- Local Device(Chip) Interface --
H_ABUS : out std_logic_vector (23 downto 16);
M_ABUS : out std_logic_vector (15 downto 8);
L_ABUS : out std_logic_vector (7 downto 0);
RDATA : in std_logic_vector (31 downto 0);
RDb : out std_logic;
WR_PLSb : out std_logic;
LACK : in std_logic;
-- Chip Select (Active low) --
-- Read and Write Area --
FD00XX_CSb : out std_logic;
FD01XX_CSb : out std_logic;
FD02XX_CSb : out std_logic;
FD03XX_CSb : out std_logic;
-- Read Only Area --
FE00XX_CSb : out std_logic;
FE01XX_CSb : out std_logic;
FE02XX_CSb : out std_logic;
FE03XX_CSb : out std_logic
);
end component;
component DEVICE_01
port(
CLK_IN : in std_logic;
RSTb : in std_logic;
-- BUS SEQUENCE MASTER / DECODE Interface --
CSb : in std_logic;
RDb : in std_logic;
WR_PLSb : in std_logic;
LADRS : in std_logic_vector (7 downto 0);
WDATA : in std_logic_vector (31 downto 0);
RDATA : out std_logic_vector (31 downto 0);
ACK : out std_logic;
-- External Device Interface --
OUTPUT_0 : out std_logic;
OUTPUT_1 : out std_logic;
OUTPUT_2 : out std_logic;
OUTPUT_3 : out std_logic;
OUTPUT_4 : out std_logic;
OUTPUT_5 : out std_logic;
OUTPUT_6 : out std_logic;
OUTPUT_7 : out std_logic;
-- DEBUG --
DEVICE_DEBUG_1 : out std_logic; --
DEVICE_DEBUG_2 : out std_logic --
);
end component;
component DEVICE_02
port(
--/* global */--
CLK_IN : in std_logic;
RSTb : in std_logic;
-- BUS SEQUENCE MASTER / DECODE Interface --
CSb : in std_logic;
RDb : in std_logic;
-- WR_PLSb : in std_logic;
LADRS : in std_logic_vector (7 downto 0);
-- WDATA : in std_logic_vector (31 downto 0);
RDATA : out std_logic_vector (31 downto 0);
ACK : out std_logic;
-- External Device Interface --
iNPUT_0 : in std_logic;
INPUT_1 : in std_logic;
INPUT_2 : in std_logic;
INPUT_3 : in std_logic;
INPUT_4 : in std_logic;
INPUT_5 : in std_logic;
INPUT_6 : in std_logic;
INPUT_7 : in std_logic;
INPUT_8 : in std_logic;
INPUT_9 : in std_logic;
INPUT_10 : in std_logic;
INPUT_11 : in std_logic;
INPUT_12 : in std_logic;
INPUT_13 : in std_logic;
INPUT_14 : in std_logic;
INPUT_15 : in std_logic;
-- DEBUG --
DEVICE_DEBUG_1 : out std_logic; --
DEVICE_DEBUG_2 : out std_logic --
);
end component;
-- internal signal or buffer
signal i_Tx_DATA : std_logic_vector(31 downto 0);
-- signal i_Tx_DATA_Shifted : std_logic_vector(31 downto 0);
signal i_Rx_DATA : std_logic_vector(31 downto 0);
signal i_RX_Ready : std_logic;
signal i_TX_Ready : std_logic;
signal i_FIFO_DATA_Received : std_logic;
signal i_DATA_Received_length : std_logic_vector(15 downto 0);
signal i_FIFO_DATA_Transmitted : std_logic;
signal i_TXE_N : std_logic;
signal i_RXF_N : std_logic;
signal i_CLK_IN : std_logic;
signal i_MyDATA_RD_REQUEST : std_logic;
signal i_MyDATA_WR_REQUEST : std_logic;
signal i_CLEAR_FIFO : std_logic;
signal i_SYSTEM_CLK : std_logic;
signal i_SYSTEM_CLK_200 : std_logic;
signal i_wrempty_to_FT : std_logic;
signal i_wrfull_to_FT : std_logic;
signal i_rdempty_to_FT : std_logic;
signal i_rdfull_to_FT : std_logic;
signal i_MyFIFO_IN_EMPTY : std_logic;
signal i_MyFIFO_IN_FULL : std_logic;
signal i_MyFIFO_OUT_EMPTY : std_logic;
signal i_MyFIFO_OUT_FULL : std_logic;
signal i_LOCAL_RDATA : std_logic_vector(31 downto 0);
signal i_LOCAL_WDATA : std_logic_vector(31 downto 0);
signal i_wrempty_to_LOCAL : std_logic;
signal i_wrfull_to_LOCAL : std_logic;
signal i_rdempty_to_LOCAL : std_logic;
signal i_rdfull_to_LOCAL : std_logic;
signal i_rdreq_from_LOCAL : std_logic;
signal i_wrreq_from_LOCAL : std_logic;
-- DECODE
signal i_AS : std_logic;
signal i_WR_CYCLE : std_logic;
signal i_RD_CYCLE : std_logic;
signal i_DACK : std_logic;
signal i_WR_PLS : std_logic;
signal i_ABUS : std_logic_vector(23 downto 0);
signal i_DBUS_WR : std_logic_vector(31 downto 0);
signal i_DBUS_RD : std_logic_vector(31 downto 0);
signal i_RCLK : std_logic;
signal i_WCLK : std_logic;
-- DEVICE
signal i_H_ABUS : std_logic_vector(23 downto 16);
signal i_M_ABUS : std_logic_vector(15 downto 8);
signal i_L_ABUS : std_logic_vector(7 downto 0);
signal i_RDATA_DEV : std_logic_vector(31 downto 0);
signal i_RDb : std_logic;
signal i_WR_PLSb : std_logic;
signal i_ACK_DEV : std_logic;
signal i_ACK_DEV_FD00XX : std_logic;
signal i_ACK_DEV_FD01XX : std_logic;
signal i_ACK_DEV_FD02XX : std_logic;
signal i_ACK_DEV_FD03XX : std_logic;
signal i_ACK_DEV_FE00XX : std_logic;
signal i_ACK_DEV_FE01XX : std_logic;
signal i_ACK_DEV_FE02XX : std_logic;
signal i_ACK_DEV_FE03XX : std_logic;
signal i_FD00XX_CSb : std_logic;
signal i_FD01XX_CSb : std_logic;
signal i_FD02XX_CSb : std_logic;
signal i_FD03XX_CSb : std_logic;
signal i_FE00XX_CSb : std_logic;
signal i_FE01XX_CSb : std_logic;
signal i_FE02XX_CSb : std_logic;
signal i_FE03XX_CSb : std_logic;
begin
i_CLK_IN <= not CLK_IN;
i_CLEAR_FIFO <= not RST_N;
i_RXF_N <= RXF_N;
i_TXE_N <= TXE_N;
i_ACK_DEV <= '1' when (
i_ACK_DEV_FD00XX = '1' or
i_ACK_DEV_FD01XX = '1' or
i_ACK_DEV_FD02XX = '1' or
i_ACK_DEV_FD03XX = '1' or
i_ACK_DEV_FE00XX = '1' or
i_ACK_DEV_FE01XX = '1' or
i_ACK_DEV_FE02XX = '1' or
i_ACK_DEV_FE03XX = '1' ) else '0';
-- for debugging
db_RXF_N_LED <= not i_RXF_N;
db_TXE_N_LED <= not i_TXE_N;
db_MyFIFO_IN_EMPTY_LED <= i_rdempty_to_FT;
db_MyFIFO_IN_FULL_LED <= i_rdfull_to_FT;
db_MyFIFO_OUT_EMPTY_LED <= i_wrempty_to_FT;
db_MyFIFO_OUT_FULL_LED <= i_wrfull_to_FT;
PLL_0:PLL_100M port map (
refclk => SYSTEM_CLK,
rst => not RST_N,
outclk_0 => i_SYSTEM_CLK_200,
outclk_1 => i_SYSTEM_CLK,
locked => open
);
FT601_0:FT601_245SYNCFIFO port map (
RST_N => RST_N,
-- connected to outside (FT601)
CLK_IN => CLK_IN,
TXE_N => TXE_N,
WR_N => WR_N,
BE => BE,
RXF_N => RXF_N,
OE_N => OE_N,
RD_N => RD_N,
DATA => DATA,
-- connectd to inside
Tx_DATA => i_Tx_DATA,
Rx_DATA => i_Rx_DATA,
RX_Ready => not i_wrfull_to_FT,
TX_Ready => i_rdfull_to_FT,
DATA_SendRequest => i_MyDATA_RD_REQUEST,
DATA_ReceiveRequest => i_MyDATA_WR_REQUEST,
FIFO_DATA_Received => i_FIFO_DATA_Received,
DATA_Received_length => i_DATA_Received_length,
FIFO_DATA_Transmitted => i_FIFO_DATA_Transmitted
);
ASYNC_FIFO_inst_IN : ASYNC_FIFO PORT MAP (
aclr => i_CLEAR_FIFO,
data => i_LOCAL_RDATA, -- from Bus Sequencer
rdclk => i_CLK_IN, -- from FT601
rdreq => i_MyDATA_RD_REQUEST, -- from FT601
wrclk => i_SYSTEM_CLK, -- from Bus Sequencer
wrreq => i_wrreq_from_LOCAL, -- from Bus Sequencer
q => i_Tx_DATA, -- to FT601
rdempty => i_rdempty_to_FT, -- to FT601
rdfull => i_rdfull_to_FT, -- to FT601
wrempty => i_wrempty_to_LOCAL, -- to Bus Sequencer
wrfull => i_wrfull_to_LOCAL -- to Bus Sequencer
);
ASYNC_FIFO_inst_OUT : ASYNC_FIFO PORT MAP (
aclr => i_CLEAR_FIFO,
data => i_Rx_DATA, -- from FT601
rdclk => i_SYSTEM_CLK, -- from Bus Sequencer
rdreq => i_rdreq_from_LOCAL, -- from Bus Sequencer
wrclk => i_CLK_IN, -- from FT601
wrreq => i_MyDATA_WR_REQUEST, -- from FT601
q => i_LOCAL_WDATA, -- to Bus Sequencer
rdempty => i_rdempty_to_LOCAL, -- to Bus Sequencer
rdfull => i_rdfull_to_LOCAL, -- to Bus Sequencer
wrempty => i_wrempty_to_FT, -- to FT601
wrfull => i_wrfull_to_FT -- to FT601
);
BUS_SEQUENCE_MASTER_inst : BUS_SEQUENCE_MASTER PORT MAP (
RST_N => RST_N,
CLK_IN => i_SYSTEM_CLK,
IN_FIFO_FULL => i_wrfull_to_LOCAL, --from ASYNC_FIFO_IN
IN_FIFO_EMPTY => i_wrempty_to_LOCAL, --from ASYNC_FIFO_IN
IN_FIFO_WCLK => i_WCLK,
IN_FIFO_WRITE_REQUEST => i_wrreq_from_LOCAL,
IN_FIFO_DATA => i_LOCAL_RDATA,
OUT_FIFO_FULL => i_rdfull_to_LOCAL,
OUT_FIFO_EMPTY => i_rdempty_to_LOCAL,
OUT_FIFO_READ_REQUEST => i_rdreq_from_LOCAL,
OUT_FIFO_RCLK => i_RCLK,
OUT_FIFO_DATA => i_LOCAL_WDATA,
WR_CYCLE => i_WR_CYCLE,
RD_CYCLE => i_RD_CYCLE,
AS => i_AS,
WR_PLS => i_WR_PLS,
DACK => i_DACK,
ABUS => i_ABUS,
DBUS_WR => i_DBUS_WR,
DBUS_RD => i_DBUS_RD,
DEBUG_1 => open,
DEBUG_2 => open
);
DECODE_inst : DECODE PORT MAP (
RSTb => RST_N,
-- for BUS SEQUENCE MASTER Interface --
CLK_IN => i_SYSTEM_CLK,
AS => i_AS,
RD_CYCLE => i_RD_CYCLE,
WR_PLS => i_WR_PLS,
A_BUS => i_ABUS,
DBUS_RD => i_DBUS_RD,
DTACK => i_DACK,
-- for Device(chip) bus Interface --
H_ABUS => i_H_ABUS,
M_ABUS => i_M_ABUS,
L_ABUS => i_L_ABUS,
RDATA => i_RDATA_DEV,
RDb => i_RDb,
WR_PLSb => i_WR_PLSb,
LACK => i_ACK_DEV,
FD00XX_CSb => i_FD00XX_CSb,
FD01XX_CSb => i_FD01XX_CSb,
FD02XX_CSb => i_FD02XX_CSb,
FD03XX_CSb => i_FD03XX_CSb,
FE00XX_CSb => i_FE00XX_CSb,
FE01XX_CSb => i_FE01XX_CSb,
FE02XX_CSb => i_FE02XX_CSb,
FE03XX_CSb => i_FE03XX_CSb
);
FD00XX_inst : DEVICE_01 PORT MAP(
CLK_IN => i_SYSTEM_CLK,
RSTb => RST_N,
CSb => i_FD00XX_CSb,
RDb => i_RDb,
WR_PLSb => i_WR_PLSb,
LADRS => i_L_ABUS,
WDATA => i_DBUS_WR,
RDATA => i_RDATA_DEV,
ACK => i_ACK_DEV_FD00XX,
OUTPUT_0 => LEDR0_OUT,
OUTPUT_1 => LEDR1_OUT,
OUTPUT_2 => LEDR2_OUT,
OUTPUT_3 => LEDR3_OUT,
OUTPUT_4 => LEDR4_OUT,
OUTPUT_5 => LEDR5_OUT,
OUTPUT_6 => LEDR6_OUT,
OUTPUT_7 => LEDR7_OUT,
DEVICE_DEBUG_1 => open,
DEVICE_DEBUG_2 => open
);
FD01XX_inst : DEVICE_01 PORT MAP(
CLK_IN => i_SYSTEM_CLK,
RSTb => RST_N,
CSb => i_FD01XX_CSb,
RDb => i_RDb,
WR_PLSb => i_WR_PLSb,
LADRS => i_L_ABUS,
WDATA => i_DBUS_WR,
RDATA => i_RDATA_DEV,
ACK => i_ACK_DEV_FD01XX,
OUTPUT_0 => open,
OUTPUT_1 => open,
OUTPUT_2 => open,
OUTPUT_3 => open,
OUTPUT_4 => open,
OUTPUT_5 => open,
OUTPUT_6 => open,
OUTPUT_7 => open,
DEVICE_DEBUG_1 => open,
DEVICE_DEBUG_2 => open
);
FD02XX_inst : DEVICE_01 PORT MAP(
CLK_IN => i_SYSTEM_CLK,
RSTb => RST_N,
CSb => i_FD02XX_CSb,
RDb => i_RDb,
WR_PLSb => i_WR_PLSb,
LADRS => i_L_ABUS,
WDATA => i_DBUS_WR,
RDATA => i_RDATA_DEV,
ACK => i_ACK_DEV_FD02XX,
OUTPUT_0 => open,
OUTPUT_1 => open,
OUTPUT_2 => open,
OUTPUT_3 => open,
OUTPUT_4 => open,
OUTPUT_5 => open,
OUTPUT_6 => open,
OUTPUT_7 => open,
DEVICE_DEBUG_1 => open,
DEVICE_DEBUG_2 => open
);
FD03XX_inst : DEVICE_01 PORT MAP(
CLK_IN => i_SYSTEM_CLK,
RSTb => RST_N,
CSb => i_FD03XX_CSb,
RDb => i_RDb,
WR_PLSb => i_WR_PLSb,
LADRS => i_L_ABUS,
WDATA => i_DBUS_WR,
RDATA => i_RDATA_DEV,
ACK => i_ACK_DEV_FD03XX,
OUTPUT_0 => open,
OUTPUT_1 => open,
OUTPUT_2 => open,
OUTPUT_3 => open,
OUTPUT_4 => open,
OUTPUT_5 => open,
OUTPUT_6 => open,
OUTPUT_7 => open,
DEVICE_DEBUG_1 => open,
DEVICE_DEBUG_2 => open
);
FE00XX_inst : DEVICE_02 PORT MAP(
CLK_IN => i_SYSTEM_CLK,
RSTb => RST_N,
CSb => i_FE00XX_CSb,
RDb => i_RDb,
LADRS => i_L_ABUS,
RDATA => i_RDATA_DEV,
ACK => i_ACK_DEV_FE00XX,
iNPUT_0 => SW0_IN,
INPUT_1 => SW1_IN,
INPUT_2 => SW2_IN,
INPUT_3 => SW3_IN,
INPUT_4 => SW4_IN,
INPUT_5 => SW5_IN,
INPUT_6 => SW6_IN,
INPUT_7 => SW7_IN,
INPUT_8 => SW8_IN,
INPUT_9 => SW9_IN,
INPUT_10 => '0',
INPUT_11 => '0',
INPUT_12 => '0',
INPUT_13 => '0',
INPUT_14 => '0',
INPUT_15 => '0',
DEVICE_DEBUG_1 => open,
DEVICE_DEBUG_2 => open
);
FE01XX_inst : DEVICE_02 PORT MAP(
CLK_IN => i_SYSTEM_CLK,
RSTb => RST_N,
CSb => i_FE01XX_CSb,
RDb => i_RDb,
LADRS => i_L_ABUS,
RDATA => i_RDATA_DEV,
ACK => i_ACK_DEV_FE01XX,
iNPUT_0 => KEY0_IN,
INPUT_1 => KEY1_IN,
INPUT_2 => KEY2_IN,
INPUT_3 => KEY3_IN,
INPUT_4 => '1',
INPUT_5 => '1',
INPUT_6 => '1',
INPUT_7 => '1',
INPUT_8 => '1',
INPUT_9 => '1',
INPUT_10 => '1',
INPUT_11 => '1',
INPUT_12 => '1',
INPUT_13 => '1',
INPUT_14 => '1',
INPUT_15 => '1',
DEVICE_DEBUG_1 => open,
DEVICE_DEBUG_2 => open
);
FE02XX_inst : DEVICE_02 PORT MAP(
CLK_IN => i_SYSTEM_CLK,
RSTb => RST_N,
CSb => i_FE02XX_CSb,
RDb => i_RDb,
LADRS => i_L_ABUS,
RDATA => i_RDATA_DEV,
ACK => i_ACK_DEV_FE02XX,
iNPUT_0 => '1',
INPUT_1 => '1',
INPUT_2 => '1',
INPUT_3 => '1',
INPUT_4 => '1',
INPUT_5 => '1',
INPUT_6 => '1',
INPUT_7 => '1',
INPUT_8 => '1',
INPUT_9 => '1',
INPUT_10 => '1',
INPUT_11 => '1',
INPUT_12 => '1',
INPUT_13 => '1',
INPUT_14 => '1',
INPUT_15 => '1',
DEVICE_DEBUG_1 => open,
DEVICE_DEBUG_2 => open
);
FE03XX_inst : DEVICE_02 PORT MAP(
CLK_IN => i_SYSTEM_CLK,
RSTb => RST_N,
CSb => i_FE03XX_CSb,
RDb => i_RDb,
LADRS => i_L_ABUS,
RDATA => i_RDATA_DEV,
ACK => i_ACK_DEV_FE03XX,
iNPUT_0 => '1',
INPUT_1 => '1',
INPUT_2 => '1',
INPUT_3 => '1',
INPUT_4 => '1',
INPUT_5 => '1',
INPUT_6 => '1',
INPUT_7 => '1',
INPUT_8 => '1',
INPUT_9 => '1',
INPUT_10 => '1',
INPUT_11 => '1',
INPUT_12 => '1',
INPUT_13 => '1',
INPUT_14 => '1',
INPUT_15 => '1',
DEVICE_DEBUG_1 => open,
DEVICE_DEBUG_2 => open
);
end RTL;
"FT601_245SYNCFIFO.vhd"は、冒頭のブロック図では”FT601制御部”として表現している回路です。FT601からのクロックに同期して動作する回路で、FT601内部のFIFOの状態(空、満タン)を観測して、その状態によりFT601からデータをリードしてFPGA内のFIFOにライトする、あるいはFPGA内FIFOからデータを読み出してFT601内部のFIFOにデータを書き込む制御を行います。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity FT601_245SYNCFIFO is
port(
RST_N : in std_logic;
-- interface with FT601
CLK_IN : in std_logic;
TXE_N : in std_logic;
WR_N : out std_logic;
BE : inout std_logic_vector(3 downto 0);
RXF_N : in std_logic;
OE_N : out std_logic;
RD_N : out std_logic;
DATA : inout std_logic_vector(31 downto 0);
-- interface with user cercuit
Tx_DATA : in std_logic_vector(31 downto 0);
Rx_DATA : out std_logic_vector(31 downto 0);
RX_Ready : in std_logic;
TX_Ready : in std_logic;
DATA_SendRequest : out std_logic;
DATA_ReceiveRequest : out std_logic;
FIFO_DATA_Received : out std_logic;
DATA_Received_length : out std_logic_vector(15 downto 0);
FIFO_DATA_Transmitted : out std_logic
);
end entity;
architecture RTL of FT601_245SYNCFIFO is
type state_type is (idle,r1,r2,r3,r4,r5,r6,r7,w1,w2,w3,w4);
signal i_STATE : state_type;
signal i_TXE_N : std_logic;
signal i_RXF_N : std_logic;
signal i_WR_N : std_logic;
signal i_RD_N : std_logic;
signal i_OE_N : std_logic;
signal i_DATA_Received_length : std_logic_vector(15 downto 0);
signal i_DATA_Transmited_length : std_logic_vector(15 downto 0);
begin
OE_N <= i_OE_N;
RD_N <= i_RD_N or i_RXF_N;
WR_N <= i_WR_N;
DATA_Received_length <= i_DATA_Received_length;
process(CLK_IN) begin
if (RST_N = '0') then
i_STATE <= idle;
i_RXF_N <= '1';
i_TXE_N <= '1';
DATA <= (others=>'Z');
BE <= (others=>'Z');
DATA_SendRequest <= '0';
DATA_ReceiveRequest <= '0';
FIFO_DATA_Received <= '0';
FIFO_DATA_Transmitted <= '0';
Rx_DATA <= X"00000000";
i_DATA_Received_length <= X"0000";
i_DATA_Transmited_length <= X"0000";
elsif (CLK_IN'event and CLK_IN = '1') then
i_RXF_N <= RXF_N;
i_TXE_N <= TXE_N;
case i_STATE is
when idle =>
DATA <= (others=>'Z');
BE <= (others=>'Z');
DATA_SendRequest <= '0';
DATA_ReceiveRequest <= '0';
FIFO_DATA_Received <= '0';
FIFO_DATA_Transmitted <= '0';
Rx_DATA <= X"00000000";
i_DATA_Received_length <= X"0000";
i_DATA_Transmited_length <= X"0000";
if((i_RXF_N = '0') and (RX_Ready = '1')) then
BE <= (others=>'Z');
i_STATE <= r1;
elsif((i_TXE_N = '0') and (TX_Ready = '1')) then
BE <= (others=>'1');
i_STATE <= w1;
else
i_OE_N <= '1';
i_RD_N <= '1';
i_WR_N <= '1';
i_STATE <= idle;
end if;
-- read sequence from FT601
when r1 =>
i_STATE <= r2;
when r2 =>
i_OE_N <= '0'; -- Output Enable to FT601
i_STATE <= r3;
when r3 =>
i_RD_N <= '0'; -- Read Enable to FT601
i_STATE <= r4;
when r4 =>
if(i_RXF_N = '0') then
DATA_ReceiveRequest <= '1'; -- to parent circuit
Rx_Data <= DATA; -- Read data from FT601
i_DATA_Received_length <= i_DATA_Received_length + '1';
i_STATE <= r4;
else
i_OE_N <= '1';
i_RD_N <= '1';
DATA_ReceiveRequest <= '0'; -- to parent circuit
i_STATE <= r5;
end if;
when r5 =>
FIFO_DATA_Received <= '1';
i_STATE <= r6;
when r6 =>
i_STATE <= r7;
when r7 =>
i_STATE <= idle;
-- write sequence to FT601
when w1 =>
DATA_SendRequest <='1';
i_STATE <= w2;
when w2 =>
DATA <= Tx_DATA;
i_WR_N <= '0'; -- Write Enable
if(i_TXE_N = '0') then
i_DATA_Transmited_length <= i_DATA_Transmited_length + '1';
i_STATE <= w2;
else
i_WR_N <= '1';
DATA_SendRequest <='0';
i_STATE <= w3;
end if;
when w3 =>
DATA <= (others=>'Z');
FIFO_DATA_Transmitted <= '1';
i_STATE <= w4;
when w4 =>
i_STATE <= idle;
when others =>
i_STATE <= idle;
end case;
end if;
end process;
end RTL;
"BUS_SEQYEBCE_MASTER.vhd"は、上述では”バスコントロールシーケンサ”と表現していた回路です。FPGA内部のFIFOであるIN-FIFO部やOUT-FIFO部(いずれもASYNC_FIFO.vhdで定義するFIFOコンポーネントのインスタンス)の状態(空、満タン)起点に、デバイスとIN-FIFOやOUT-FIFO間のデータ転送のためのバスサイクルを実行します。発行するアドレスは、"AdressPackage_OUT.vhd" や"AdressPackage_IN.vhd"において定数として定義したアドレス値(X"FD0000"等)の配列から一つずつ読み込むことで得ます。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
library work;
use work.AdressPackage_OUT.all;
use work.AdressPackage_IN.all;
entity BUS_SEQUENCE_MASTER is
port(
RST_N : in std_logic ; --
CLK_IN : in std_logic ; --
-- IN_FIFO interface
IN_FIFO_FULL : in std_logic ; --
IN_FIFO_EMPTY : in std_logic ; --
IN_FIFO_WCLK : out std_logic ; --
IN_FIFO_WRITE_REQUEST : out std_logic ; --
IN_FIFO_DATA : out std_logic_vector (31 downto 0) ; --
-- OUT_FIFO_interface
OUT_FIFO_FULL : in std_logic ; --
OUT_FIFO_EMPTY : in std_logic ; --
OUT_FIFO_READ_REQUEST : out std_logic ; --
OUT_FIFO_RCLK : out std_logic ; --
OUT_FIFO_DATA : in std_logic_vector (31 downto 0) ; --
-- User interface
WR_CYCLE : out std_logic ; --
RD_CYCLE : out std_logic ; --
AS : out std_logic ; --
WR_PLS : out std_logic ; --
DACK : in std_logic ; --
ABUS : out std_logic_vector (23 downto 0) ; --
DBUS_WR : out std_logic_vector (31 downto 0) ; --
DBUS_RD : in std_logic_vector (31 downto 0) ; --
DEBUG_1 : out std_logic ; --
DEBUG_2 : out std_logic --
);
end entity;
architecture RTL of BUS_SEQUENCE_MASTER is
signal i_OUT_REQUEST_CYCLE : std_logic;
signal i_IN_REQUEST_CYCLE : std_logic;
type out_process_state_type is (idle, adr_set, data_set, data_write_1, data_write_2, wait_dack, w_end_1, w_end_2);
signal i_OUT_PROCESS_STATE : out_process_state_type;
signal i_ABUS_WR : std_logic_vector(23 downto 0);
signal i_ABUS_RD : std_logic_vector(23 downto 0);
signal i_AS_WR : std_logic;
signal i_WR_PLS : std_logic;
signal I_DACK_OUT_FSM : std_logic;
signal i_WR_CYCLE : std_logic;
signal i_DBUS_WR : std_logic_vector(31 downto 0);
signal i_ADRESS_CNT_WR : std_logic_vector(15 downto 0);
signal WR_CNT_1023 : std_logic_vector(15 downto 0) := X"03FF"; -- 1023
signal i_OUT_FIFO_READ_REQUEST : std_logic;
signal i_OUT_FIFO_FULL : std_logic;
signal i_OUT_FIFO_EMPTY : std_logic;
type in_process_state_type is (idle, adr_set, data_read, read_end_1, read_end_2);
signal i_IN_PROCESS_STATE : in_process_state_type;
signal i_AS_RD : std_logic;
signal I_DACK_IN_FSM : std_logic;
signal i_RD_CYCLE : std_logic;
signal i_DBUS_RD : std_logic_vector(31 downto 0);
-- signal i_RD : std_logic_vector(31 downto 0);
signal i_ADRESS_CNT_RD : std_logic_vector(15 downto 0);
signal RD_CNT_1023 : std_logic_vector(15 downto 0) := X"03FF"; -- 1023
signal IN_PROCESS_CNT_3 : std_logic_vector(7 downto 0) := X"03"; -- 3
signal i_IN_CNT : std_logic_vector(7 downto 0);
signal i_IN_FIFO_WRITE_REQUEST : std_logic;
signal i_IN_FIFO_FULL : std_logic;
signal i_IN_FIFO_EMPTY : std_logic;
begin
i_DBUS_WR <= OUT_FIFO_DATA;
DBUS_WR <= i_DBUS_WR when i_WR_CYCLE ='1' else (others=>'0');
i_DBUS_RD <= DBUS_RD;
IN_FIFO_DATA <= i_DBUS_RD when i_RD_CYCLE = '1' else (others=>'0');
ABUS <= i_ABUS_RD when i_RD_CYCLE = '1' else i_ABUS_WR;
AS <= i_AS_RD when i_RD_CYCLE = '1' else i_AS_WR;
WR_CYCLE <= i_WR_CYCLE;
RD_CYCLE <= i_RD_CYCLE;
WR_PLS <= i_WR_PLS;
OUT_FIFO_RCLK <= not CLK_IN;
OUT_FIFO_READ_REQUEST <= i_OUT_FIFO_READ_REQUEST;
IN_FIFO_WRITE_REQUEST <= i_IN_FIFO_WRITE_REQUEST;
IN_FIFO_WCLK <= not CLK_IN;
-- OUT_FIFO_FSM (FT601) -->> OUT_FIFO -->> Local BUS
process(CLK_IN) begin
if (RST_N = '0') then
-- i_OUT_REQUEST_CYCLE <= '0';
i_OUT_PROCESS_STATE <= idle;
i_ABUS_WR <= (others=>'Z');
i_OUT_FIFO_FULL <= '0';
i_AS_WR <='0';
i_WR_CYCLE <='0';
i_WR_PLS <='0';
i_ADRESS_CNT_WR <= X"0000";
i_OUT_FIFO_READ_REQUEST <= '0';
elsif (CLK_IN'event and CLK_IN = '1') then
I_DACK_OUT_FSM <= DACK;
i_OUT_FIFO_FULL <= OUT_FIFO_FULL;
case i_OUT_PROCESS_STATE is
when idle =>
i_ABUS_WR <= (others=>'Z');
i_ADRESS_CNT_WR <= X"0000";
-- if( (i_IN_REQUEST_CYCLE = '0') and (i_OUT_FIFO_FULL = '1' ))then
if( (i_RD_CYCLE = '0') and (i_OUT_FIFO_FULL = '1' ))then
i_OUT_PROCESS_STATE <= adr_set;
i_OUT_REQUEST_CYCLE <= '1';
else
i_OUT_PROCESS_STATE <= idle;
end if;
when adr_set =>
i_WR_CYCLE <='1';
i_ABUS_WR <= OUT_ADR_FDXXXX(conv_integer(unsigned(i_ADRESS_CNT_WR)));
i_AS_WR <= '1';
i_OUT_FIFO_READ_REQUEST <= '1';
i_OUT_PROCESS_STATE <= data_set;
when data_set =>
i_OUT_FIFO_READ_REQUEST <= '0';
i_OUT_PROCESS_STATE <= data_write_1;
when data_write_1 =>
i_WR_PLS <='1';
i_OUT_PROCESS_STATE <= data_write_2;
when data_write_2 =>
i_WR_PLS <='1';
i_OUT_PROCESS_STATE <= wait_dack;
when wait_dack =>
if I_DACK_OUT_FSM = '1' then
i_WR_PLS <='0';
i_OUT_PROCESS_STATE <= w_end_1;
else
i_OUT_PROCESS_STATE <= wait_dack;
end if;
when w_end_1 =>
i_AS_WR <= '0';
if i_ADRESS_CNT_WR = WR_CNT_1023 then
i_OUT_PROCESS_STATE <= w_end_2;
else
i_ADRESS_CNT_WR <= i_ADRESS_CNT_WR + '1';
i_OUT_PROCESS_STATE <= adr_set;
end if;
when w_end_2 =>
i_WR_CYCLE <='0';
i_OUT_PROCESS_STATE <= idle;
when others =>
i_OUT_REQUEST_CYCLE <= '0';
i_OUT_PROCESS_STATE <= idle;
end case;
end if;
end process;
-- IN_FIFO_FSM Local BUS -->> IN_FIFO -->> (FT601)
process(CLK_IN) begin
if (RST_N = '0') then
-- i_IN_REQUEST_CYCLE <= '0';
i_IN_PROCESS_STATE <= idle;
i_ABUS_RD <= (others=>'Z');
i_IN_FIFO_EMPTY <= '0';
i_AS_RD <='0';
i_RD_CYCLE <='0';
i_IN_CNT <= X"00";
i_ADRESS_CNT_RD <= X"0000";
i_IN_FIFO_WRITE_REQUEST <= '0';
elsif (CLK_IN'event and CLK_IN = '1') then
I_DACK_IN_FSM <= DACK;
i_IN_FIFO_EMPTY <= IN_FIFO_EMPTY;
case i_IN_PROCESS_STATE is
when idle =>
i_ABUS_RD <= (others=>'Z');
i_ADRESS_CNT_RD <= X"0000";
-- if( (i_OUT_REQUEST_CYCLE = '0') and (i_IN_FIFO_EMPTY = '1' ))then
if( (i_WR_CYCLE = '0') and (i_IN_FIFO_EMPTY = '1' ))then
i_IN_PROCESS_STATE <= adr_set;
i_IN_REQUEST_CYCLE <= '1';
else
i_IN_PROCESS_STATE <= idle;
end if;
when adr_set =>
i_RD_CYCLE <='1';
-- address selector
if i_IN_CNT = X"00" then
i_ABUS_RD <= X"FDF000"; -- dummy adress
elsif i_IN_CNT = X"01" then
i_ABUS_RD <= IN_ADR_FDXXXX(conv_integer(unsigned(i_ADRESS_CNT_RD)));
elsif i_IN_CNT = X"02" then
i_ABUS_RD <= IN_ADR_FEXXXX(conv_integer(unsigned(i_ADRESS_CNT_RD)));
else
-- unexpected error --
end if;
i_AS_RD <= '1';
i_IN_PROCESS_STATE <= data_read;
when data_read =>
-- wait for ack from local device ---
if i_DACK_IN_FSM = '1' then
i_IN_FIFO_WRITE_REQUEST <= '1';
i_IN_PROCESS_STATE <= read_end_1;
else
i_IN_PROCESS_STATE <= data_read;
end if;
when read_end_1 =>
i_AS_RD <= '0';
i_IN_FIFO_WRITE_REQUEST <= '0';
if i_ADRESS_CNT_RD = RD_CNT_1023 then
i_IN_PROCESS_STATE <= read_end_2;
i_IN_CNT <= i_IN_CNT + '1';
else
i_ADRESS_CNT_RD <= i_ADRESS_CNT_RD + '1';
i_IN_PROCESS_STATE <= adr_set;
end if;
when read_end_2 =>
i_RD_CYCLE <='0';
if i_IN_CNT = IN_PROCESS_CNT_3 then
i_IN_CNT <= X"00";
else
i_IN_CNT <= i_IN_CNT;
end if;
i_IN_PROCESS_STATE <= idle;
when others =>
i_IN_REQUEST_CYCLE <= '0';
i_IN_PROCESS_STATE <= idle;
end case;
end if;
end process;
end RTL;
"DECODE.vhd"は、上述では”アドレスデコーダー”と表現していた回路です。アドレスマップに従いバスコントロールシーケンサから入力されるアドレスバスデータをデコードしてデバイスを選択するCSb(チップセレクト)信号を作ります。また、デバイスから返される応答信号やデータを中継してバスコントロールシーケンサへ返します。
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity DECODE is
port(
RSTb : in std_logic;
CLK_IN : in std_logic;
--* BUS SEQUENCE MASTER Interface *--
AS : in std_logic;
RD_CYCLE : in std_logic;
WR_PLS : in std_logic;
A_BUS : in std_logic_vector (23 downto 0);
DBUS_RD : out std_logic_vector (31 downto 0);
DTACK : out std_logic;
-- Local Device(Chip) Interface --
H_ABUS : out std_logic_vector (23 downto 16);
M_ABUS : out std_logic_vector (15 downto 8);
L_ABUS : out std_logic_vector (7 downto 0);
RDATA : in std_logic_vector (31 downto 0);
RDb : out std_logic;
WR_PLSb : out std_logic;
LACK : in std_logic;
-- Chip Select (Active low) --
-- Read and Write Area --
FD00XX_CSb : out std_logic;
FD01XX_CSb : out std_logic;
FD02XX_CSb : out std_logic;
FD03XX_CSb : out std_logic;
-- Read Only Area --
FE00XX_CSb : out std_logic;
FE01XX_CSb : out std_logic;
FE02XX_CSb : out std_logic;
FE03XX_CSb : out std_logic
);
end DECODE;
architecture RTL of DECODE is
signal i_H_ADDRESS : unsigned (23 downto 16);
signal i_M_ADDRESS : unsigned (15 downto 8);
signal i_CSb_PATTERN : unsigned (8 downto 0);
signal i_CSb_OUT : unsigned (i_CSb_PATTERN'range);
signal i_ISRDCSb : unsigned (i_CSb_PATTERN'range);
signal i_UNASSIGNED : std_logic;
signal LDBUS_RD : std_logic_vector (RDATA'range);
signal i_DTACK_1 : std_logic;
signal i_DTACK_2 : std_logic;
--/* selector pattern */--
constant CS_FD00XX : unsigned(8 downto 0) := "111111110";
constant CS_FD01XX : unsigned(8 downto 0) := "111111101";
constant CS_FD02XX : unsigned(8 downto 0) := "111111011";
constant CS_FD03XX : unsigned(8 downto 0) := "111110111";
constant CS_FE00XX : unsigned(8 downto 0) := "111101111";
constant CS_FE01XX : unsigned(8 downto 0) := "111011111";
constant CS_FE02XX : unsigned(8 downto 0) := "110111111";
constant CS_FE03XX : unsigned(8 downto 0) := "101111111";
constant CS_UNASSIGNED : unsigned(8 downto 0) := "011111111";
begin
-- Read strobe --
RDb <= AS nand RD_CYCLE;
-- Address Data --
i_H_ADDRESS <= unsigned(A_BUS(i_H_ADDRESS'range));
i_M_ADDRESS <= unsigned(A_BUS(i_M_ADDRESS'range));
H_ABUS <= A_BUS(H_ABUS'range);
M_ABUS <= A_BUS(M_ABUS'range);
L_ABUS <= A_BUS(L_ABUS'range);
-- Address decode process -------------------------------------
process (i_H_ADDRESS, i_M_ADDRESS) begin
case i_H_ADDRESS is
when X"FD" =>
case i_M_ADDRESS is
when X"00" => i_CSb_PATTERN <= CS_FD00XX; --
when X"01" => i_CSb_PATTERN <= CS_FD01XX; --
when X"02" => i_CSb_PATTERN <= CS_FD02XX; --
when X"03" => i_CSb_PATTERN <= CS_FD03XX; --
when others => i_CSb_PATTERN <= CS_UNASSIGNED;--
end case;
when X"FE" =>
case i_M_ADDRESS is
when X"00" => i_CSb_PATTERN <= CS_FE00XX; --
when X"01" => i_CSb_PATTERN <= CS_FE01XX; --
when X"02" => i_CSb_PATTERN <= CS_FE02XX; --
when X"03" => i_CSb_PATTERN <= CS_FE03XX; --
when others => i_CSb_PATTERN <= CS_UNASSIGNED;--
end case;
when others => i_CSb_PATTERN <= CS_UNASSIGNED;
end case;
end process;
--- chip select signal process
process (CLK_IN, RSTb, AS) begin
if (RSTb = '0') or (AS = '0') then
i_CSb_OUT <= (others => '1');
elsif (CLK_IN'event and CLK_IN = '1') then
i_CSb_OUT <= i_CSb_PATTERN;
end if;
end process;
FD00XX_CSb <= i_CSb_OUT(0);
FD01XX_CSb <= i_CSb_OUT(1);
FD02XX_CSb <= i_CSb_OUT(2);
FD03XX_CSb <= i_CSb_OUT(3);
FE00XX_CSb <= i_CSb_OUT(4);
FE01XX_CSb <= i_CSb_OUT(5);
FE02XX_CSb <= i_CSb_OUT(6);
FE03XX_CSb <= i_CSb_OUT(7);
i_UNASSIGNED <= not i_CSb_OUT(8); -- Access flag for unsigned space -- (Active-on)
i_ISRDCSb <= i_CSb_OUT when (AS = '1') and (RD_CYCLE = '1') else (others => '1');
LDBUS_RD <= RDATA when LACK = '1' else (others => '0');
-- Acknowledge --------------------------------------------
DTACK <= i_DTACK_1;
i_DTACK_1 <= '0' when (AS = '0') or ( (LACK = '0') and (i_UNASSIGNED = '0') ) else '1';
-- process (CLK_IN, RSTb, i_DTACK_1, i_DTACK_2) begin
-- if (RSTb = '0') then
-- i_DTACK_2 <= '0';
-- elsif (CLK_IN'event and CLK_IN = '1') then
-- i_DTACK_2 <= i_DTACK_1;
-- end if;
-- end process;
-- Write Plus ---------------------------------------------
process (CLK_IN, RSTb) begin
if (RSTb = '0') then
WR_PLSb <= '1';
elsif (CLK_IN'event and CLK_IN = '1') then
if (AS = '0') then
WR_PLSb <= '1';
elsif WR_PLS = '1' then
WR_PLSb <= '0';
else
WR_PLSb <= '1';
end if;
end if;
end process;
-- Read data -----------------------------------------
process (i_ISRDCSb, LDBUS_RD )
begin
case i_ISRDCSb is
when CS_FD00XX | CS_FD01XX | CS_FD02XX | CS_FD03XX => DBUS_RD <= LDBUS_RD;
when CS_FE00XX | CS_FE01XX | CS_FE02XX | CS_FE03XX => DBUS_RD <= LDBUS_RD;
when CS_UNASSIGNED => DBUS_RD <= (others => '0'); -- unassigned area
when others => DBUS_RD <= (others => '0'); -- unassigned area
end case;
end process;
end RTL;
"DEVICE_01.vhd"は、リードライト可能な32bit幅レジスタを11個持った回路です。そのうち1つのレジスタのみ外部出力する機能を持たせています。10個のレジスタは読み書きするだけの役割しかありません。今回の例ではこの回路のインスタンスを4つ生成していますが、インスタンス1つだけ外部出力の信号をFPGA外部に引っ張りLEDの点灯制御をできるようにしています。これはTOP.vhdにて確認できます。
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity DEVICE_01 is
port (
--/* global */--
CLK_IN : in std_logic;
RSTb : in std_logic;
-- BUS SEQUENCE MASTER / DECODE Interface --
CSb : in std_logic;
RDb : in std_logic;
WR_PLSb : in std_logic;
LADRS : in std_logic_vector (7 downto 0);
WDATA : in std_logic_vector (31 downto 0);
RDATA : out std_logic_vector (31 downto 0);
ACK : out std_logic;
-- External Device Interface --
OUTPUT_0 : out std_logic;
OUTPUT_1 : out std_logic;
OUTPUT_2 : out std_logic;
OUTPUT_3 : out std_logic;
OUTPUT_4 : out std_logic;
OUTPUT_5 : out std_logic;
OUTPUT_6 : out std_logic;
OUTPUT_7 : out std_logic;
-- DEBUG --
DEVICE_DEBUG_1 : out std_logic; --
DEVICE_DEBUG_2 : out std_logic --
);
end DEVICE_01;
architecture RTL of DEVICE_01 is
signal i_CSb_PATTERN : unsigned (12 downto 0);
signal i_ISRDCSb : unsigned (i_CSb_PATTERN'range);
signal i_ISWRCSb : unsigned (i_CSb_PATTERN'range);
-- chip select pattern --
constant CS_XXXX00 : unsigned(12 downto 0) := "1111111111110";
constant CS_XXXX04 : unsigned(12 downto 0) := "1111111111101";
constant CS_XXXX08 : unsigned(12 downto 0) := "1111111111011";
constant CS_XXXX0C : unsigned(12 downto 0) := "1111111110111";
constant CS_XXXX10 : unsigned(12 downto 0) := "1111111101111";
constant CS_XXXX14 : unsigned(12 downto 0) := "1111111011111";
constant CS_XXXX18 : unsigned(12 downto 0) := "1111110111111";
constant CS_XXXX1C : unsigned(12 downto 0) := "1111101111111";
constant CS_XXXX20 : unsigned(12 downto 0) := "1111011111111";
constant CS_XXXX24 : unsigned(12 downto 0) := "1110111111111";
constant CS_XXXX28 : unsigned(12 downto 0) := "1101111111111";
constant CS_UNUSED : unsigned(12 downto 0) := "1011111111111";
constant CS_UNASSIGNED : unsigned(12 downto 0) := "0111111111111";
-- read/write register --
signal REG_XXXX00_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX04_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX08_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX0C_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX10_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX14_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX18_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX1C_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX20_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX24_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX28_OUT : std_logic_vector (31 downto 0);
signal i_RDATA : std_logic_vector (31 downto 0);
signal i_REG_ACK_1 : std_logic;
signal i_REG_ACK_2 : std_logic;
begin
-- address decode
process (CSb, LADRS) begin
if (CSb = '0') then
case LADRS is
when X"00" => i_CSb_PATTERN <= CS_XXXX00;
when X"04" => i_CSb_PATTERN <= CS_XXXX04;
when X"08" => i_CSb_PATTERN <= CS_XXXX08;
when X"0C" => i_CSb_PATTERN <= CS_XXXX0C;
when X"10" => i_CSb_PATTERN <= CS_XXXX10;
when X"14" => i_CSb_PATTERN <= CS_XXXX14;
when X"18" => i_CSb_PATTERN <= CS_XXXX18;
when X"1C" => i_CSb_PATTERN <= CS_XXXX1C;
when X"20" => i_CSb_PATTERN <= CS_XXXX20;
when X"24" => i_CSb_PATTERN <= CS_XXXX24;
when X"28" => i_CSb_PATTERN <= CS_XXXX28;
when X"2C" => i_CSb_PATTERN <= CS_UNUSED;
when X"30" => i_CSb_PATTERN <= CS_UNUSED;
when X"34" => i_CSb_PATTERN <= CS_UNUSED;
when X"38" => i_CSb_PATTERN <= CS_UNUSED;
when X"3C" => i_CSb_PATTERN <= CS_UNUSED;
when others => i_CSb_PATTERN <= CS_UNUSED;
end case;
else
i_CSb_PATTERN <= CS_UNASSIGNED;
end if;
end process;
-- acknowledgment --
ACK <= i_REG_ACK_2 when CSb = '0' else '0';
i_REG_ACK_1 <= '0' when i_CSb_PATTERN = CS_UNASSIGNED else '1';
process (CLK_IN, RSTb) begin
if( RSTb = '0') then
i_REG_ACK_2 <= '0';
elsif ( CLK_IN'event and CLK_IN = '1') then
i_REG_ACK_2 <= i_REG_ACK_1;
end if;
end process;
-- chip selecter --
i_ISRDCSb <= i_CSb_PATTERN when( (CSb = '0') and (RDb = '0') ) else (others => '1');
i_ISWRCSb <= i_CSb_PATTERN when( (CSb = '0') and (WR_PLSb = '0') ) else (others => '1');
-- Register reading control process
RDATA <= i_RDATA when i_REG_ACK_1 = '1' else (others => 'Z');
process (i_ISRDCSb,REG_XXXX00_OUT,REG_XXXX04_OUT,REG_XXXX08_OUT,REG_XXXX0C_OUT,REG_XXXX10_OUT,REG_XXXX14_OUT,REG_XXXX18_OUT,
REG_XXXX1C_OUT,REG_XXXX20_OUT,REG_XXXX24_OUT,REG_XXXX28_OUT ) begin
case i_ISRDCSb is
when CS_XXXX00 => i_RDATA <= REG_XXXX00_OUT;
when CS_XXXX04 => i_RDATA <= REG_XXXX04_OUT;
when CS_XXXX08 => i_RDATA <= REG_XXXX08_OUT;
when CS_XXXX0C => i_RDATA <= REG_XXXX0C_OUT;
when CS_XXXX10 => i_RDATA <= REG_XXXX10_OUT;
when CS_XXXX14 => i_RDATA <= REG_XXXX14_OUT;
when CS_XXXX18 => i_RDATA <= REG_XXXX18_OUT;
when CS_XXXX1C => i_RDATA <= REG_XXXX1C_OUT;
when CS_XXXX20 => i_RDATA <= REG_XXXX20_OUT;
when CS_XXXX24 => i_RDATA <= REG_XXXX24_OUT;
when CS_XXXX28 => i_RDATA <= REG_XXXX28_OUT;
when CS_UNUSED => i_RDATA <= (others => '0');
when others => i_RDATA <= (others => 'Z');
end case;
end process;
-- Control process for writing to registers
process (CLK_IN, RSTb, i_ISWRCSb) begin
if (RSTb = '0') then
REG_XXXX00_OUT <= (others => '0');
elsif ( (CLK_IN'event and CLK_IN = '1') and (i_ISWRCSb = CS_XXXX00) ) then
REG_XXXX00_OUT <= WDATA;
end if;
if (RSTb = '0') then
REG_XXXX04_OUT <= (others => '0');
elsif ( (CLK_IN'event and CLK_IN = '1') and (i_ISWRCSb = CS_XXXX04) ) then
REG_XXXX04_OUT <= WDATA;
end if;
if (RSTb = '0') then
REG_XXXX08_OUT <= (others => '0');
elsif ( (CLK_IN'event and CLK_IN = '1') and (i_ISWRCSb = CS_XXXX08) ) then
REG_XXXX08_OUT <= WDATA;
end if;
if (RSTb = '0') then
REG_XXXX0C_OUT <= (others => '0');
elsif ( (CLK_IN'event and CLK_IN = '1') and (i_ISWRCSb = CS_XXXX0C) ) then
REG_XXXX0C_OUT <= WDATA;
end if;
if (RSTb = '0') then
REG_XXXX10_OUT <= (others => '0');
elsif ( (CLK_IN'event and CLK_IN = '1') and (i_ISWRCSb = CS_XXXX10) ) then
REG_XXXX10_OUT <= WDATA;
end if;
if (RSTb = '0') then
REG_XXXX14_OUT <= (others => '0');
elsif ( (CLK_IN'event and CLK_IN = '1') and (i_ISWRCSb = CS_XXXX14) ) then
REG_XXXX14_OUT <= WDATA;
end if;
if (RSTb = '0') then
REG_XXXX18_OUT <= (others => '0');
elsif ( (CLK_IN'event and CLK_IN = '1') and (i_ISWRCSb = CS_XXXX18) ) then
REG_XXXX18_OUT <= WDATA;
end if;
if (RSTb = '0') then
REG_XXXX1C_OUT <= (others => '0');
elsif ( (CLK_IN'event and CLK_IN = '1') and (i_ISWRCSb = CS_XXXX1C) ) then
REG_XXXX1C_OUT <= WDATA;
end if;
if (RSTb = '0') then
REG_XXXX20_OUT <= (others => '0');
elsif ( (CLK_IN'event and CLK_IN = '1') and (i_ISWRCSb = CS_XXXX20) ) then
REG_XXXX20_OUT <= WDATA;
end if;
if (RSTb = '0') then
REG_XXXX24_OUT <= (others => '0');
elsif ( (CLK_IN'event and CLK_IN = '1') and (i_ISWRCSb = CS_XXXX24) ) then
REG_XXXX24_OUT <= WDATA;
end if;
if (RSTb = '0') then
REG_XXXX28_OUT <= (others => '0');
elsif ( (CLK_IN'event and CLK_IN = '1') and (i_ISWRCSb = CS_XXXX28) ) then
REG_XXXX28_OUT <= WDATA;
end if;
end process;
-- output control
OUTPUT_0 <= REG_XXXX04_OUT(0);
OUTPUT_1 <= REG_XXXX04_OUT(1);
OUTPUT_2 <= REG_XXXX04_OUT(2);
OUTPUT_3 <= REG_XXXX04_OUT(3);
OUTPUT_4 <= REG_XXXX04_OUT(4);
OUTPUT_5 <= REG_XXXX04_OUT(5);
OUTPUT_6 <= REG_XXXX04_OUT(6);
OUTPUT_7 <= REG_XXXX04_OUT(7);
end RTL;
"DEVICE_02.vhd"は、リード専用の32bit幅レジスタを11個持った回路です。そのうち2つのレジスタのみ外部信号を入力する機能を持たせています。残り9個のレジスタはレジスタ内の定数を読み出すだけの役割しか持たせていません。今回の例ではこの回路のインスタンスを4つ生成していますが、インスタンス1つだけ外部の信号をFPGA内部に引っ張りスイッチ入力状態を把握できるようにしています。これはTOP.vhdにて確認できます。スイッチ入力以外のレジスタにはテキトーな固定値を入れています。
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity DEVICE_02 is
port (
--/* global */--
CLK_IN : in std_logic;
RSTb : in std_logic;
-- BUS SEQUENCE MASTER / DECODE Interface --
CSb : in std_logic;
RDb : in std_logic;
-- WR_PLSb : in std_logic;
LADRS : in std_logic_vector (7 downto 0);
-- WDATA : in std_logic_vector (31 downto 0);
RDATA : out std_logic_vector (31 downto 0);
ACK : out std_logic;
-- External Device Interface --
iNPUT_0 : in std_logic;
INPUT_1 : in std_logic;
INPUT_2 : in std_logic;
INPUT_3 : in std_logic;
INPUT_4 : in std_logic;
INPUT_5 : in std_logic;
INPUT_6 : in std_logic;
INPUT_7 : in std_logic;
INPUT_8 : in std_logic;
INPUT_9 : in std_logic;
INPUT_10 : in std_logic;
INPUT_11 : in std_logic;
INPUT_12 : in std_logic;
INPUT_13 : in std_logic;
INPUT_14 : in std_logic;
INPUT_15 : in std_logic;
-- DEBUG --
DEVICE_DEBUG_1 : out std_logic; --
DEVICE_DEBUG_2 : out std_logic --
);
end DEVICE_02;
architecture RTL of DEVICE_02 is
signal i_CSb_PATTERN : unsigned (12 downto 0);
signal i_ISRDCSb : unsigned (i_CSb_PATTERN'range);
-- chip select pattern --
constant CS_XXXX00 : unsigned(12 downto 0) := "1111111111110";
constant CS_XXXX04 : unsigned(12 downto 0) := "1111111111101";
constant CS_XXXX08 : unsigned(12 downto 0) := "1111111111011";
constant CS_XXXX0C : unsigned(12 downto 0) := "1111111110111";
constant CS_XXXX10 : unsigned(12 downto 0) := "1111111101111";
constant CS_XXXX14 : unsigned(12 downto 0) := "1111111011111";
constant CS_XXXX18 : unsigned(12 downto 0) := "1111110111111";
constant CS_XXXX1C : unsigned(12 downto 0) := "1111101111111";
constant CS_XXXX20 : unsigned(12 downto 0) := "1111011111111";
constant CS_XXXX24 : unsigned(12 downto 0) := "1110111111111";
constant CS_XXXX28 : unsigned(12 downto 0) := "1101111111111";
constant CS_UNUSED : unsigned(12 downto 0) := "1011111111111";
constant CS_UNASSIGNED : unsigned(12 downto 0) := "0111111111111";
-- read/write register --
signal REG_XXXX00_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX04_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX08_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX0C_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX10_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX14_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX18_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX1C_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX20_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX24_OUT : std_logic_vector (31 downto 0);
signal REG_XXXX28_OUT : std_logic_vector (31 downto 0);
signal i_REG_ACK_1 : std_logic;
signal i_REG_ACK_2 : std_logic;
signal i_REG_HIGH : std_logic_vector (15 downto 0);
signal i_REG_LOW : std_logic_vector (15 downto 0);
begin
-- address decode
process (CSb, LADRS) begin
if (CSb = '0') then
case LADRS is
when X"00" => i_CSb_PATTERN <= CS_XXXX00;
when X"04" => i_CSb_PATTERN <= CS_XXXX04;
when X"08" => i_CSb_PATTERN <= CS_XXXX08;
when X"0C" => i_CSb_PATTERN <= CS_XXXX0C;
when X"10" => i_CSb_PATTERN <= CS_XXXX10;
when X"14" => i_CSb_PATTERN <= CS_XXXX14;
when X"18" => i_CSb_PATTERN <= CS_XXXX18;
when X"1C" => i_CSb_PATTERN <= CS_XXXX1C;
when X"20" => i_CSb_PATTERN <= CS_XXXX20;
when X"24" => i_CSb_PATTERN <= CS_XXXX24;
when X"28" => i_CSb_PATTERN <= CS_XXXX28;
when X"2C" => i_CSb_PATTERN <= CS_UNUSED;
when X"30" => i_CSb_PATTERN <= CS_UNUSED;
when X"34" => i_CSb_PATTERN <= CS_UNUSED;
when X"38" => i_CSb_PATTERN <= CS_UNUSED;
when X"3C" => i_CSb_PATTERN <= CS_UNUSED;
when others => i_CSb_PATTERN <= CS_UNUSED;
end case;
else
i_CSb_PATTERN <= CS_UNASSIGNED;
end if;
end process;
-- acknowledgment --
ACK <= i_REG_ACK_2 when CSb = '0' else '0';
i_REG_ACK_1 <= '0' when i_CSb_PATTERN = CS_UNASSIGNED else '1';
process (CLK_IN, RSTb) begin
if( RSTb = '0') then
i_REG_ACK_2 <= '0';
elsif ( CLK_IN'event and CLK_IN = '1') then
i_REG_ACK_2 <= i_REG_ACK_1;
end if;
end process;
-- chip selecter --
i_ISRDCSb <= i_CSb_PATTERN when( (CSb = '0') and (RDb = '0') ) else (others => '1');
-- Register reading control process
process (i_ISRDCSb,REG_XXXX00_OUT,REG_XXXX04_OUT,REG_XXXX08_OUT,REG_XXXX0C_OUT,REG_XXXX10_OUT,REG_XXXX14_OUT,REG_XXXX18_OUT,
REG_XXXX1C_OUT,REG_XXXX20_OUT,REG_XXXX24_OUT,REG_XXXX28_OUT ) begin
case i_ISRDCSb is
when CS_XXXX00 => RDATA <= REG_XXXX00_OUT;
when CS_XXXX04 => RDATA <= REG_XXXX04_OUT;
when CS_XXXX08 => RDATA <= REG_XXXX08_OUT;
when CS_XXXX0C => RDATA <= REG_XXXX0C_OUT;
when CS_XXXX10 => RDATA <= REG_XXXX10_OUT;
when CS_XXXX14 => RDATA <= REG_XXXX14_OUT;
when CS_XXXX18 => RDATA <= REG_XXXX18_OUT;
when CS_XXXX1C => RDATA <= REG_XXXX1C_OUT;
when CS_XXXX20 => RDATA <= REG_XXXX20_OUT;
when CS_XXXX24 => RDATA <= REG_XXXX24_OUT;
when CS_XXXX28 => RDATA <= REG_XXXX28_OUT;
when CS_UNUSED => RDATA <= (others => '0');
when others => RDATA <= (others => 'Z');
end case;
end process;
i_REG_HIGH <= X"0000";
i_REG_LOW <= INPUT_15 & INPUT_14 & INPUT_13 & INPUT_12 & INPUT_11 & INPUT_10 & INPUT_9 & INPUT_8 & INPUT_7 & INPUT_6 & INPUT_5 & INPUT_4 & INPUT_3 & INPUT_2 & INPUT_1 & INPUT_0;
-- Control process for writing to registers
process (CLK_IN, RSTb) begin
if (RSTb = '0') then
REG_XXXX00_OUT <= (others => '0');
REG_XXXX04_OUT <= (others => '0');
REG_XXXX08_OUT <= (others => '0');
REG_XXXX0C_OUT <= (others => '0');
REG_XXXX10_OUT <= (others => '0');
REG_XXXX14_OUT <= (others => '0');
REG_XXXX18_OUT <= (others => '0');
REG_XXXX1C_OUT <= (others => '0');
REG_XXXX20_OUT <= (others => '0');
REG_XXXX24_OUT <= (others => '0');
REG_XXXX28_OUT <= (others => '0');
elsif (CLK_IN'event and CLK_IN = '1') then
REG_XXXX00_OUT <= X"00000A0A";
REG_XXXX04_OUT <= i_REG_HIGH & i_REG_LOW;
REG_XXXX08_OUT <= X"00040A0A";
REG_XXXX0C_OUT <= X"00080A0A";
REG_XXXX10_OUT <= X"00100A0A";
REG_XXXX14_OUT <= X"00140A0A";
REG_XXXX18_OUT <= X"00180A0A";
REG_XXXX1C_OUT <= X"001C0A0A";
REG_XXXX20_OUT <= X"00200A0A";
REG_XXXX24_OUT <= X"00240A0A";
REG_XXXX28_OUT <= X"00280A0A";
end if;
end process;
end RTL;
さて、USBデバイスとして、たかだかLEDを点灯したりスイッチの状態を把握するだけの機能の設計を紹介しましたが、この基本的なところを押さえておけば、みなさんの作るかっこいいデバイスをローカル制御部に接続して動作させることができる通信インフラができます。次回はこの回路のテストに使ったPCのソフトウェア設計を紹介します。アビアントー。
2024年5月19日追記:
説明に漏れがありました。ここで紹介したシステムは、ホストPCからみて4KBのデータ送信と8KBのデータ受信を行うと説明しました。しかし、実際には8KBではなく12KBのデータ受信を行っています。ただし、先頭の4KBはダミーデータ(捨てて良い)です。理由を以下に説明します。FPGAの回路は、FPGA内に設けたFIFOが空になる(=ホストPCがFIFOのデータを全て読み出した)ことをトリガーにして、FPGAが管理する全デバイス群のレジスタの値を読み出してFIFOに詰め込みます。このホストPCからのデータ読み出しに備えて、FPGAの回路は先ずはFIFOをダミーデータ(オール0でもオールFでも何でも良い)で埋めます。その状態でホストPCからのデータ読み出しを待機します。この後、ホストPCはいつデータを読み出しにくるかわかりません。1時間後かもしれません。24時間後かもしれません。しかし、この仕組みであればホストPCがデータ読み出しを行った直後のFPGAのレジスタに収まっているデータを読み出すことができます。ホストPCはいつ書き込まれたかわからない(わからなくて良い)ダミーデータは捨てしまえば良いのです。12KBのうち先頭4KBを捨てて残り8KBが意味のあるデータ、そして要求直後の最新のデータとなります。データ転送効率性はものすごく悪いのですが。
“FT601を使った通信システムを設計してみよう(その1)” に対して2件のコメントがあります。
コメントは受け付けていません。