2008/12/23

CUDAで遊ぶ(1)

しばらくPCI-FPGAボードに没頭していましたが、ボード繋がりということで(?)、グラフィックカードを買いました。NVidiaのPCIeカード(初のPCIeカード)で、いわゆるGeForce9500GTという奴が搭載されています。


これで3Dゲームがグリグリ美しく動くぜ...、というつもりで買った訳ではなくて、ネタはGPGPUというかCUDAです。

このあたりこのあたりを参考に、一番コストパフォーマンスの良さそうな物を購入しました。

とりあえず、CUDA対応ドライバとSDKをインストール。以下はSDK添付のbandwtidhtestツールの結果です。ボード内で12GB/s、ホスト/ボード間で1.5GB/s前後となっています(あれ8800シリーズの方がよかったかな??)。

C:\Program Files\NVIDIA Corporation\NVIDIA CUDA SDK\bin\win32\Release>bandwidthtest
Running on......
device 0:GeForce 9500 GT
Quick Mode
Host to Device Bandwidth for Pageable memory
.
Transfer Size (Bytes) Bandwidth(MB/s)
33554432 1856.4

Quick Mode
Device to Host Bandwidth for Pageable memory
.
Transfer Size (Bytes) Bandwidth(MB/s)
33554432 1521.8

Quick Mode
Device to Device Bandwidth
.
Transfer Size (Bytes) Bandwidth(MB/s)
33554432 12892.3

&&&& Test PASSED

Press ENTER to exit...

picasa3とQuickTime Movie

Picasaを3にアップデートしたら、QuickTime Movieが表示できなくなりました。
Webアルバムにはアップロードできるので、それほど大きな問題ではありませんが。

Spartan3 PCIバス付きFPGA評価ボード(12) - 状態遷移不正続き

前回のエントリの状態遷移不正ですが、まだ一部おかしいところがありました。

#003367: AD fa000000, CBE 8(mw ), FRAME# H, DEVSEL# L, IRDY# L, TRDY# L, STOP# L, stat 0, app 0
#003368: AD 87654321, CBE f(---), FRAME# L, DEVSEL# L, IRDY# H, TRDY# L, STOP# L, stat 0, app 0
#003369: AD 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 1, app 0


このstat 0->stat 0の箇所です。状態0はIDLE状態、状態1はアドレス取り込みの状態で、本来IDLE状態でFRAME#がH('0')を検出したら、アドレス取り込み状態へ遷移しなければなりません(少なくとも書いた人の意図は ;-))

VHDLはこんな感じになっています。

-- BUS idle
when IDLE =>
if (N_FRAME_IO = '0' and N_IRDY_IO = '1') then
buscommand <= N_CBE_IO;
address <= AD_IO;
idsel <= IDSEL_I;
nxtstate := ADDR;
else
nxtstate := IDLE;
end if;

-- Address decode
when ADDR =>
if (Hit_device = '1') then
N_DEVSEL_IO <= '0';
TRDY_PORT <= '1';
-- deassert STOP#
STOP_PORT <= '1';
nxtstate := IRDY;
else
nxtstate := BUSY;
end if;


ごく単純な状態遷移機械を書いたつもりなのですが、どうしても一拍待って?しまっています。

良くわからずWebを彷徨っていたら、「状態遷移機械と次状態計算とデータ出力は分けて書いたほうがいい」というTIPSがありました。

要は、

  state <= nextstate

を行うprocess文(状態遷移機械)と、

when state =>
nextstate <= ST_XXX;

を行う組み合わせロジック(次状態計算)と、

when state =>
datax <= xxx;
datay <= yyy;

といったデータ出力ロジックを分けて書けということのようです。

若干半信半疑ながら、そのTIPSにしたがって対処したら綺麗にIDLEステートからADDRステートへ遷移するようになりました。

IDLE(0)→ADDR(1)→IRDY待ち(3)→appcore待ち(4)→DISCONNECT(7)/COMPLETE(5)→COMPLETE2(6)→IDLEという一連の状態遷移が期待通りにできるようになりました。0xfa000004へのライトはバースト転送になっていますが、きちんとDISCONNECTで打ち切っています。

[WRITE]
#00169c: AD fa000000, CBE 8(mw ), FRAME# H, DEVSEL# L, IRDY# L, TRDY# L, STOP# L, stat 0, app 0
#00169d: AD 87654321, CBE f(---), FRAME# L, DEVSEL# L, IRDY# H, TRDY# L, STOP# L, stat 1, app 0
#00169e: AD 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 3, app 0
#00169f: AD 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 4, app 0
#0016a0: AD 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 4, app 0
#0016a1: AD 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 4, app 3
#0016a2: AD 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# H, STOP# H, stat 5, app 5
#0016a3: AD 87654321, CBE f(---), FRAME# L, DEVSEL# L, IRDY# L, TRDY# L, STOP# L, stat 6, app 0
#0016a6: AD fa000004, CBE 8(mw ), FRAME# H, DEVSEL# L, IRDY# L, TRDY# L, STOP# L, stat 0, app 0
#0016a7: AD 87654321, CBE f(---), FRAME# H, DEVSEL# L, IRDY# H, TRDY# L, STOP# L, stat 1, app 0
#0016a8: AD 87654321, CBE f(---), FRAME# H, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 3, app 0
#0016a9: AD 87654321, CBE f(---), FRAME# H, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 4, app 0
#0016aa: AD 87654321, CBE f(---), FRAME# H, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 4, app 0
#0016ab: AD 87654321, CBE f(---), FRAME# H, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 4, app 3
#0016ac: AD 87654321, CBE f(---), FRAME# H, DEVSEL# H, IRDY# H, TRDY# H, STOP# H, stat 5, app 5
#0016ad: AD 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# H, stat 7, app 0
#0016ae: AD 87654321, CBE f(---), FRAME# L, DEVSEL# L, IRDY# L, TRDY# L, STOP# L, stat 6, app 0

[READ]
#0048e4: AD fa000000, CBE 9(mr ), FRAME# H, DEVSEL# L, IRDY# L, TRDY# L, STOP# L, stat 0, app 0
#0048e5: AD fa000000, CBE f(---), FRAME# L, DEVSEL# L, IRDY# H, TRDY# L, STOP# L, stat 1, app 0
#0048e6: AD fa000000, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 3, app 0
#0048e7: AD fa000000, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 4, app 0
#0048e8: AD fa000000, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 4, app 0
#0048e9: AD deadbeef, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 4, app 3
#0048ea: AD deadbeef, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# H, STOP# H, stat 5, app 5
#0048eb: AD deadbeef, CBE f(---), FRAME# L, DEVSEL# L, IRDY# L, TRDY# L, STOP# L, stat 6, app 0

論理的にはまったく同じように見えるのに、ハードウェアは奥が深いなあ。結局、回路のレベルでは何か違いが(タイミング問題とか)あるんでしょうけど、解明できていません。

それはそれとして、上のように分けて書くと、if文が二箇所に分散するのであまり記述性がよろしくないと思うのですが、どんなもんなんでしょうね。

2008/12/22

Spartan3 PCIバス付きFPGA評価ボード(11) - 状態遷移不正

前回、簡易PCIアナライザで性能が出ない原因を検証しましたが、よくよく検討するとあまりにも遅すぎです。どうもおかしな状態遷移をしているように見えます。机上では良くわからなかったので、ステートマシンの状態番号までトレースするようにしてデバッグしたところ、不正な状態?(本来生起するはずのないIDLE状態)が途中に入ってしまって遅くなっていたようです。

ISEのログを見るとステートマシンが推論された様子がありません。そのあたりが原因かもしれないと思い、ステートマシンの部分をvariableで書き直したりして、ステートマシンを推論したというメッセージを確認したら、何とかちゃんとした状態遷移をするようになりました。

[WRITE]
#003367: AD fa000000, CBE 8(mw ), FRAME# H, DEVSEL# L, IRDY# L, TRDY# L, STOP# L, stat 0, app 0
#003368: AD 87654321, CBE f(---), FRAME# L, DEVSEL# L, IRDY# H, TRDY# L, STOP# L, stat 0, app 0
#003369: AD 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 1, app 0
#00336a: AD 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 3, app 0
#00336b: AD 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 4, app 0
#00336c: AD 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 4, app 3
#00336d: AD 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# H, STOP# H, stat 4, app 5
#00336e: AD 87654321, CBE f(---), FRAME# L, DEVSEL# L, IRDY# L, TRDY# L, STOP# L, stat 5, app 0
#00336f: AD 87654321, CBE f(---), FRAME# L, DEVSEL# L, IRDY# L, TRDY# L, STOP# L, stat 6, app 0

[READ]
#0067e7: AD fa000000, CBE 9(mr ), FRAME# H, DEVSEL# L, IRDY# L, TRDY# L, STOP# L, stat 0, app 0
#0067e8: AD fa000000, CBE f(---), FRAME# L, DEVSEL# L, IRDY# H, TRDY# L, STOP# L, stat 0, app 0
#0067e9: AD fa000000, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 1, app 0
#0067ea: AD fa000000, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 3, app 0
#0067eb: AD fa000000, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 4, app 0
#0067ec: AD deadbeef, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L, stat 4, app 3
#0067ed: AD deadbeef, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# H, STOP# H, stat 4, app 5
#0067ee: AD deadbeef, CBE f(---), FRAME# L, DEVSEL# L, IRDY# L, TRDY# L, STOP# L, stat 5, app 0
#0067ef: AD deadbeef, CBE f(---), FRAME# L, DEVSEL# L, IRDY# L, TRDY# L, STOP# L, stat 6, app 0


VHDLにしても、verilogにしても、その文法や意味論そのものは生成される回路の正当性を保障してくれなくて、結局、回路要素マクロでしかないので仕方ありません。

2008/12/19

Spartan3 PCIバス付きFPGA評価ボード(10) - 簡易PCIバスアナライザによるデータ解析

前回のPCIボード性能測定では、
  • 32MBライト=9.77MB/s
  • 32MBリード=5.28MB/s

という不本意かつアンバランスな結果でした。

この現象を、早速、簡易PCIバスアナライザで解析してみました。

  • メモリリード
    メモリリードを実行しているときのPCIバス状態は以下のようになりました。AD:のfa000000がPCIカードのPCIメモリ空間のアドレスで、以下のデータは0xfa000000を読み終わって0xfa000004を読みにいくところです。先頭の#...はタイムスタンプ(PCIクロックに同期して1増える)です。
#008f5c28: AD: fa000000, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#008f5c29: AD: deadbeef, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#000f5c2a: AD: deadbeef, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# H, STOP# H
← 15クロック →
#008f5c39: AD: fa000004, CBE 9(mr ), FRAME# H, DEVSEL# L, IRDY# L, TRDY# L, STOP# L
#008f5c3a: AD: fa000004, CBE f(---), FRAME# L, DEVSEL# L, IRDY# H, TRDY# L, STOP# L
#008f5c3b: AD: fa000004, CBE f(---), FRAME# L, DEVSEL# L, IRDY# H, TRDY# L, STOP# L
#008f5c3c: AD: fa000004, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#008f5c3d: AD: fa000004, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#008f5c3e: AD: fa000004, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#008f5c3f: AD: fa000004, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#008f5c40: AD: fa000004, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#008f5c41: AD: deadbeef, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#000f5c42: AD: deadbeef, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# H, STOP# H
← 15クロック →
#008f5c51: AD: fa000008, CBE 9(mr ), FRAME# H, DEVSEL# L, IRDY# L, TRDY# L, STOP# L
#008f5c52: AD: fa000008, CBE f(---), FRAME# L, DEVSEL# L, IRDY# H, TRDY# L, STOP# L
1回のメモリリードに0x8f5c39~0x8f5c42までの10クロックを要していることが判ります。しかも、各メモリリードの間に15クロックの隙間が空いてしまっています。 1回の読み出しに10+15=25クロック掛かるとすると、133MB/s/25 = 5.32MB/sとなり、ほぼ実測結果と符合しています。
  • メモリライト
    今度はライトの方を見てみます。やはり一回のライトに10クロック掛かっています。同時に各ライト間に隙間がありますが、こちらの隙間は4クロックで済んでいます。

    133MB/s/(10+4)=9.5MB/sでライトの方も実測値と整合性が取れました。

#00e6cda4: AD: 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#0066cda5: AD: 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# H, STOP# H
← 4クロック →
#00e6cda9: AD: fa000004, CBE 8(mw ), FRAME# H, DEVSEL# L, IRDY# L, TRDY# L, STOP# L
#00e6cdaa: AD: 87654321, CBE f(---), FRAME# H, DEVSEL# L, IRDY# H, TRDY# L, STOP# L
#00e6cdab: AD: 87654321, CBE f(---), FRAME# H, DEVSEL# L, IRDY# H, TRDY# L, STOP# L
#00e6cdac: AD: 87654321, CBE f(---), FRAME# H, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#00e6cdad: AD: 87654321, CBE f(---), FRAME# H, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#00e6cdae: AD: 87654321, CBE f(---), FRAME# H, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#00e6cdaf: AD: 87654321, CBE f(---), FRAME# H, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#00e6cdb0: AD: 87654321, CBE f(---), FRAME# H, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#00e6cdb1: AD: 87654321, CBE f(---), FRAME# H, DEVSEL# H, IRDY# H, TRDY# L, STOP# L
#0066cdb2: AD: 87654321, CBE f(---), FRAME# H, DEVSEL# H, IRDY# H, TRDY# H, STOP# H
#0066cdb3: AD: 87654321, CBE f(---), FRAME# L, DEVSEL# H, IRDY# H, TRDY# H, STOP# H
← 3クロック →
#00e6cdb6: AD: fa000008, CBE 8(mw ), FRAME# H, DEVSEL# L, IRDY# L, TRDY# L, STOP# L
#00e6cdb7: AD: 87654321, CBE f(---), FRAME# H, DEVSEL# L, IRDY# H, TRDY# L, STOP# L
#00e6cdb8: AD: 87654321, CBE f(---), FRAME# H, DEVSEL# L, IRDY# H, TRDY# L, STOP# L
何故このような隙間が空くのかはわかりませんが、マザーボード・チップセット絡みに何か事情があるのでしょう。
  • バースト転送対応
  • PCIバスシーケンサの状態遷移を見直して、より無駄なく状態間を移動できるようにする
などに取り組んで行きます。

Spartan3 PCIバス付きFPGA評価ボード(9) - 簡易PCIバスアナライザ

ひととおりRAMボードのターゲット機能が動くようになったので、何か実用的?なアプリケーションをと考えて思いついたのが(♪タターン♪)簡易PCIバスアナライザです。

まあ、実用でも何でもないのですが、自分でPCIバス上のデータが見られるのも面白いし、今後のデバッグにも役立つかと思ったので作ってみることにしました。

ブロック図は以下のようになっていて、前回よりはモジュール化できてきました。

アドレスデコーダと7セグディスプレイをPCIコアから分離し、全体を管理するpcibrdというエンティティをかぶせました。その上で、PCIバスにPCIコアと並列につながる形でトレーサを用意しています。

トレーサは、PCIクロックに同期して、AD(32bit)、C/BE#、FRAME#、DEVSEL#、IRDY#、TRDY#、STOP#の各PCI信号をトレースします(下図)。



XilinxのROMは最大36ビット(うちパリティ4bit)しか作れないことと、通常のPCIメモリ空間からの32bit幅アクセスと整合性を取るため、32bit幅のRAMを二つ用意しています。余ったビットはタイムスタンプとして使用しています。

トレース時には両RAMに一度に32bitづつ計64bitのデータを書き込み、読み出すときは偶数ワード、奇数ワードに分けてアクセスします。

2008/12/14

物欲リスト

この年になると物欲も薄れて、もっぱら子供のことばかりです。

なんてことは必ずしもなくて、やっぱり欲しいものは欲しい(趣向は徐々に変わってきていますが)。以下、最近ほしい物。
  • XilinxのPCIeの評価ボード(HW-S3PCIE-DK-J)
    まあ、PCI関連の工作が終わったら考えましょうか。
    国内ではあまり見かけなくなっていますが、DigiKeyにはあるようです。

  • AndroidのDevPhone1
    これはまあお約束ですね。一発当てようという程の気力はありませんが。来年ソニエリからAUで出るらしいとのことなので、それとの天秤ですね。

  • CUDAで遊べるGPU
    これも、殊更何を計算しようという意図はないのですが、ちょっといじってみたい程度です。

2008/12/10

Spartan3 PCIバス付きFPGA評価ボード(8)

まだまだ作成途上なので汚いですが、pciコアのソースコードです。

  • PCIコア部分です。RAMを読む部分とPCIコアを分けていて、appcore_start、appcore_doneという信号で同期をとっています(その割には分離性が高くないですが)。このあたりをきちんと考えて設計しないと、バースト転送で速度を上げるのは難しそう。


----------------------------------------------------------------------------------
-- Company:
-- Engineer: taipapa
--
-- Create Date: 21:40:28 11/22/2008
-- Design Name:
-- Module Name: pci1 - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------

-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.


---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity pcicore is
Port (PCI_CLK : in STD_LOGIC;
N_INTA : out STD_LOGIC;
N_RST_I : in STD_LOGIC;
N_FRAME_IO : inout STD_LOGIC;
N_TRDY_IO : inout STD_LOGIC;
N_GNT_I : in STD_LOGIC;
N_STOP_IO : inout STD_LOGIC;
PAR_IO : inout STD_LOGIC;
IDSEL_I : in STD_LOGIC;
N_IRDY_IO : inout STD_LOGIC;
N_DEVSEL_IO : inout STD_LOGIC;
N_PERR_IO : inout STD_LOGIC;
N_SERR_IO : inout STD_LOGIC;
N_REQ_Q : inout STD_LOGIC;
N_CBE_IO : inout STD_LOGIC_VECTOR(3 downto 0);
AD_IO : inout STD_LOGIC_VECTOR(31 downto 0);

-- 7 Segments
SEG_LED_SELECT : out STD_LOGIC_VECTOR(4 downto 0);
SEG_LED_DATA : out STD_LOGIC_VECTOR(7 downto 0);

-- LEDs
LED_2 : out STD_LOGIC;
LED_3 : out STD_LOGIC;
LED_4 : out STD_LOGIC;
LED_5 : out STD_LOGIC);
end pcicore;

architecture Behavioral of pcicore is

component SEGDISP
Port (PCI_CLK : in STD_LOGIC;
RESET: in STD_LOGIC;
SEL : out STD_LOGIC_VECTOR(4 downto 0);
DAT : out STD_LOGIC_VECTOR(7 downto 0);
DIGIT0: in std_logic_vector (3 downto 0);
DIGIT1: in std_logic_vector (3 downto 0);
DIGIT2: in std_logic_vector (3 downto 0);
DIGIT3: in std_logic_vector (3 downto 0));
end component;

component ram
port (
clka: IN std_logic;
dina: IN std_logic_VECTOR(31 downto 0);
addra: IN std_logic_VECTOR(8 downto 0);
wea: IN std_logic_vector(0 downto 0);
douta: OUT std_logic_VECTOR(31 downto 0));
end component;

-- PCI signals
signal AD_PORT: std_logic_vector(31 downto 0);
signal DEVSEL_PORT: std_logic;
signal TRDY_PORT: std_logic;
signal STOP_PORT: std_logic;
signal SERR_PORT : std_logic := 'Z';
signal PERR_PORT : std_logic := 'Z';
signal PAR_PORT : std_logic := 'Z';

-- Latched signals
signal buscommand : std_logic_vector(3 downto 0);
signal address : std_logic_vector(31 downto 0);
signal idsel : std_logic;

-- Address decoder
signal Hit_device : std_logic;
signal Hit_Memory0 : std_logic;
signal Hit_Memory1 : std_logic;
signal Hit_Config : std_logic;

-- State machine
signal curstate: std_logic_vector(3 downto 0);
signal nxtstate: std_logic_vector(3 downto 0);
constant IDLE : std_logic_vector(3 downto 0) := "0000";
constant ADDR : std_logic_vector(3 downto 0) := "0001";
constant BUSY : std_logic_vector(3 downto 0) := "0010";
constant IRDY : std_logic_vector(3 downto 0) := "0011";
constant LOCALWAIT : std_logic_vector(3 downto 0) := "0100";
constant COMP : std_logic_vector(3 downto 0) := "0101";
constant COMP2 : std_logic_vector(3 downto 0) := "0110";
constant DISCON : std_logic_vector(3 downto 0) := "0111";
constant INIT : std_logic_vector(3 downto 0) := "1000";
constant ERR : std_logic_vector(3 downto 0) := "1111";

-- Local State machine
signal l_curstate: std_logic_vector(3 downto 0) := "0000";
signal l_nxtstate: std_logic_vector(3 downto 0) := "0000";
constant L_IDLE : std_logic_vector(3 downto 0) := "0000";
constant L_CFG : std_logic_vector(3 downto 0) := "0001";
constant L_MEM0 : std_logic_vector(3 downto 0) := "0010";
constant L_MEM1 : std_logic_vector(3 downto 0) := "0011";
-- constant L_MEM2 : std_logic_vector(3 downto 0) := "0100";
constant L_COMP : std_logic_vector(3 downto 0) := "0101";
constant L_ERR : std_logic_vector(3 downto 0) := "1111";
signal appcore_start : std_logic;
signal appcore_done : std_logic;

-- PCI bus command
constant CMD_MemRead : std_logic_vector(3 downto 0) := ("0110");
constant CMD_MemWrite : std_logic_vector(3 downto 0) := ("0111");
constant CMD_ConfRead : std_logic_vector(3 downto 0) := ("1010");
constant CMD_ConfWrite : std_logic_vector(3 downto 0) := ("1011");

-- Config Regs
signal CFG_vendorID : std_logic_vector(15 downto 0) := (X"3449");
signal CFG_deviceID : std_logic_vector(15 downto 0) := (X"8000");
signal CFG_command : std_logic_vector(15 downto 0) := (X"0000");
signal CFG_status : std_logic_vector(15 downto 0) := (X"0200");
signal CFG_baseclass : std_logic_vector(7 downto 0) := (X"05");
signal CFG_subclass : std_logic_vector(7 downto 0) := (X"00");
signal CFG_programIF : std_logic_vector(7 downto 0) := (X"00");
signal CFG_revisionID : std_logic_vector(7 downto 0) := (X"01");
signal CFG_headertype : std_logic_vector(7 downto 0) := (X"00");

-- BAR
-- 16Bytes
signal CFG_BAR0 : std_logic_vector(31 downto 4);
-- 1MBytes
signal CFG_BAR1 : std_logic_vector(31 downto 20);

-- test registers accessed through memory space
signal regtest0 : std_logic_vector(31 downto 0) := (X"00100000");

-- ram
signal Ram_din : std_logic_vector(31 downto 0);
signal Ram_dout : std_logic_vector(31 downto 0);
signal Ram_addr : std_logic_vector(8 downto 0);
signal Ram_we : std_logic_vector(0 downto 0);

begin

-- LED connection
LED_2 <= N_FRAME_IO;
LED_3 <= N_DEVSEL_IO;
LED_4 <= N_IRDY_IO;
LED_5 <= DEVSEL_Port;

-- modules: Segment display
segs : SEGDISP port map(
PCI_CLK => PCI_CLK,
RESET => N_RST_I,
SEL => SEG_LED_SELECT,
DAT => SEG_LED_DATA,
DIGIT0 => curstate,
DIGIT1 => regtest0(23 downto 20),
DIGIT2 => regtest0(27 downto 24),
DIGIT3 => regtest0(31 downto 28));

-- the ram
raminst : ram
port map (
clka => PCI_CLK,
dina => Ram_din,
addra => Ram_addr,
wea => Ram_we,
douta => Ram_dout);

-- Address decoder
Hit_device <= Hit_memory0 or Hit_memory1 or Hit_config;
process(idsel, buscommand, address, CFG_BAR0, CFG_BAR1, CFG_command)
begin
-- Check memory space access
if ((buscommand = CMD_MemRead or buscommand = CMD_MemWrite) and
CFG_command(1) = '1') then
if (address(31 downto 4) = CFG_BAR0(31 downto 4)) then
Hit_memory0 <= '1';
Hit_memory1 <= '0';
elsif (address(31 downto 20) = CFG_BAR1(31 downto 20)) then
Hit_memory0 <= '0';
Hit_memory1 <= '1';
else
Hit_memory0 <= '0';
Hit_memory1 <= '0';
end if;
else
Hit_memory0 <= '0';
Hit_memory1 <= '0';
end if;

-- Check config space access
if ((buscommand = CMD_ConfRead or buscommand = CMD_ConfWrite) and
-- am I selected?
idsel = '1' and
-- function 0, type 0
address(10 downto 8) = "000" and address(1 downto 0) = "00")
then
Hit_config <= '1';
else
Hit_config <= '0';
end if;
end process;


-- Application core state machine

-- Higher bits are ignored
Ram_addr <= address(10 downto 2);

process(PCI_CLK, N_RST_I)
begin
if (N_RST_I = '0') then
-- Initialize state machine
l_curstate <= L_IDLE;
l_nxtstate <= L_IDLE;
appcore_done <= '0';

-- Initialize configuration registers
CFG_BAR0 <= (others => '0');
CFG_BAR1 <= (others => '0');
CFG_command <= (others => '0');

-- Ram initialize
Ram_we <= "0";

elsif (PCI_CLK'event and PCI_CLK='1') then

l_curstate <= l_nxtstate;

case l_curstate is
-- Local idle state
when L_IDLE =>
if (appcore_start = '1') then
if (Hit_config = '1') then
l_nxtstate <= L_CFG;
end if;
if (Hit_memory0 = '1') then
l_nxtstate <= L_MEM0;
end if;
if (Hit_memory1 = '1') then
l_nxtstate <= L_MEM1;
end if;
else
l_nxtstate <= L_IDLE;
end if;

-- Configuration space
when L_CFG =>
if (buscommand(0) = '1') then
-- Config Write
case address(7 downto 2) is
-- Command register
when "000001" =>
if (N_CBE_IO(0) = '0') then
-- Memory space bit
CFG_command(1) <= AD_IO(1);
end if;

-- Bar0
when "000100" =>
if (N_CBE_IO(3) = '0') then
CFG_BAR0(31 downto 24) <= AD_IO(31 downto 24);
end if;
if (N_CBE_IO(2) = '0') then
CFG_BAR0(23 downto 16) <= AD_IO(23 downto 16);
end if;
if (N_CBE_IO(1) = '0') then
CFG_BAR0(15 downto 8) <= AD_IO(15 downto 8);
end if;
if (N_CBE_IO(0) = '0') then
CFG_BAR0(7 downto 4) <= AD_IO(7 downto 4);
end if;

-- Bar1
when "000101" =>
if (N_CBE_IO(3) = '0') then
CFG_BAR1(31 downto 24) <= AD_IO(31 downto 24);
end if;
if (N_CBE_IO(2) = '0') then
CFG_BAR1(23 downto 20) <= AD_IO(23 downto 20);
end if;

when others =>
null;
end case;
else
-- Config Read
case address(7 downto 2) is
when "000000" => -- vendor ID/dev ID
AD_Port(31 downto 16) <= CFG_deviceID;
AD_Port(15 downto 0) <= CFG_vendorID;
when "000001" => -- status/command
AD_Port(31 downto 16) <= CFG_status;
AD_Port(15 downto 0) <= CFG_command;
when "000010" => -- class code
AD_Port(31 downto 24) <= CFG_baseclass;
AD_Port(23 downto 16) <= CFG_subclass;
AD_Port(15 downto 8) <= CFG_programIF;
AD_Port(7 downto 0) <= CFG_revisionID;
when "000011" => -- header types
AD_Port(31 downto 24) <= (others => '0');
AD_Port(23 downto 16) <= CFG_headertype;
AD_Port(15 downto 0) <= (others => '0');
when "000100" => -- BAR0
AD_Port(31 downto 4) <= CFG_BAR0(31 downto 4);
AD_Port(3 downto 0) <= (others => '0');
when "000101" => -- BAR1
AD_Port(31 downto 20) <= CFG_BAR1(31 downto 20);
AD_Port(19 downto 0) <= (others => '0');
when "001011" => -- subvendor ID/subsystem ID
AD_Port(31 downto 16) <= CFG_deviceID;
AD_Port(15 downto 0) <= CFG_vendorID;
when others =>
AD_Port(31 downto 0) <= (others => '0');
end case;
end if;
appcore_done <= '1';
l_nxtstate <= L_COMP;

-- BAR0 memory space
when L_MEM0 =>
if (buscommand(0) = '1') then
-- Memory Write
case address(7 downto 0) is
when "00000000" =>
if (N_CBE_IO(3) = '0') then
regtest0(31 downto 24) <= AD_IO(31 downto 24);
end if;
if (N_CBE_IO(2) = '0') then
regtest0(23 downto 16) <= AD_IO(23 downto 16);
end if;
if (N_CBE_IO(1) = '0') then
regtest0(15 downto 8) <= AD_IO(15 downto 8);
end if;
if (N_CBE_IO(0) = '0') then
regtest0(7 downto 0) <= AD_IO(7 downto 0);
end if;
when others =>
null;
end case;
else
-- Memory Read
case address(7 downto 0) is
when "00000000" =>
AD_Port <= regtest0;
when others =>
AD_Port <= (others => '0');
end case;
end if;

appcore_done <= '1';
l_nxtstate <= L_COMP;

-- BAR1 memory space
when L_MEM1 =>
if (buscommand(0) = '1') then
-- Memory Write
Ram_din <= AD_IO;
Ram_we <= "1";
else
-- Memory Read
Ram_we <= "0";
AD_Port <= Ram_dout;
end if;
appcore_done <= '1';
l_nxtstate <= L_COMP;

when L_COMP =>
-- Indicate we finished
appcore_done <= '0';

-- Stop driving AD
AD_Port <= (others => 'Z');

-- stop we
Ram_we <= "0";

l_nxtstate <= L_IDLE;

when L_ERR =>
l_nxtstate <= L_ERR;

when others =>
l_nxtstate <= L_ERR;

end case;
end if;
end process;

-- Main state machine
process(PCI_CLK, N_RST_I)
begin
if (N_RST_I = '0') then
-- Initialize state machine
curstate <= INIT;
nxtstate <= INIT;
elsif (PCI_CLK'event and PCI_CLK='1') then
curstate <= nxtstate;

case curstate is
when INIT =>
appcore_start <= '0';
-- Initialize internal registers
DEVSEL_PORT <= 'Z';
TRDY_PORT <= 'Z';
STOP_PORT <= 'Z';
AD_Port <= (others => 'Z');
nxtstate <= IDLE;

-- BUS idle
when IDLE =>
if (N_FRAME_IO = '0' and N_IRDY_IO = '1') then
buscommand <= N_CBE_IO;
address <= AD_IO;
idsel <= IDSEL_I;
nxtstate <= ADDR;
else
nxtstate <= IDLE;
end if;

-- Address decode
when ADDR =>
if (Hit_device = '1') then
DEVSEL_PORT <= '0';
TRDY_PORT <= '1';
-- deassert STOP#
STOP_PORT <= '1';
nxtstate <= IRDY;
else
nxtstate <= BUSY;
end if;

when BUSY =>
if (N_FRAME_IO = '1' and N_IRDY_IO = '1') then
nxtstate <= IDLE;
else
nxtstate <= BUSY;
end if;

when IRDY =>
if (N_IRDY_IO = '0') then
appcore_start <= '1';
nxtstate <= LOCALWAIT;
else
nxtstate <= IRDY;
end if;

when LOCALWAIT =>
appcore_start <= '0';
if (appcore_done = '1') then
TRDY_PORT <= '0';
-- assert STOP#
STOP_PORT <= '0';
nxtstate <= COMP;
else
nxtstate <= LOCALWAIT;
end if;

when COMP =>
TRDY_PORT <= '1';
AD_Port <= (others => 'Z');

if (N_FRAME_IO = '0') then
-- Burst Transfer
nxtstate <= DISCON;
else
DEVSEL_PORT <= '1';
STOP_PORT <= '1';
nxtstate <= COMP2;
end if;

when DISCON =>
if (N_FRAME_IO = '0') then
nxtstate <= DISCON;
else
DEVSEL_PORT <= '1';
STOP_PORT <= '1';
nxtstate <= COMP2;
end if;

when COMP2 =>
TRDY_PORT <= 'Z';
DEVSEL_PORT <= 'Z';
STOP_PORT <= 'Z';
nxtstate <= IDLE;

when ERR =>
nxtstate <= ERR;

when others =>
nxtstate <= ERR;

end case;
end if;
end process;

N_DEVSEL_IO <= DEVSEL_PORT;
N_TRDY_IO <= TRDY_PORT;
N_STOP_IO <= STOP_PORT;
AD_IO <= AD_Port;

N_SERR_IO <= SERR_PORT;
N_PERR_IO <= PERR_PORT;
PAR_IO <= PAR_PORT;

N_INTA <= '1';

end Behavioral;


  • 7セグメントx4のLEDのドライバです。


----------------------------------------------------------------------------------
-- Company:
-- Engineer: taipapa
--
-- Create Date: 21:40:28 11/22/2008
-- Design Name: 7 seg driver
-- Module Name: seg - Behavioral
-- Project Name: pci1
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------

-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity SEGDISP is
Port (PCI_CLK : in STD_LOGIC;
RESET: in STD_LOGIC;
SEL : out STD_LOGIC_VECTOR(4 downto 0);
DAT : out STD_LOGIC_VECTOR(7 downto 0);
DIGIT0: in std_logic_vector (3 downto 0);
DIGIT1: in std_logic_vector (3 downto 0);
DIGIT2: in std_logic_vector (3 downto 0);
DIGIT3: in std_logic_vector (3 downto 0));
end SEGDISP;

architecture rtl of SEGDISP is
signal cnt : std_logic_vector(15 downto 0);
signal SEG_curdigit : std_logic_vector(1 downto 0);
signal SEG_segval : std_logic_vector(3 downto 0);
type digits_t is array (3 downto 0) of std_logic_vector (3 downto 0);
signal SEG_digits : digits_t;
signal SEG_SEL: std_logic_vector(3 downto 0); -- do not use semicolon
signal SEG_DATA: std_logic_vector(6 downto 0);
begin
process(PCI_CLK, RESET)
begin
if (RESET = '0') then
cnt <= (others => '0');
SEG_curdigit <= "00";
elsif (PCI_CLK'event and PCI_CLK='1') then
SEG_digits(0) <= DIGIT0;
SEG_digits(1) <= DIGIT1;
SEG_digits(2) <= DIGIT2;
SEG_digits(3) <= DIGIT3;
cnt <= cnt + '1';
if (cnt = "0") then
SEG_curdigit <= SEG_curdigit + '1';
end if;
end if;
end process;

-- Selectors (digits bit, segment value)
SEG_segval <= SEG_digits((CONV_INTEGER(SEG_curdigit(1 downto 0))));
with SEG_curdigit select
SEG_SEL <=
"0001" when "00", -- 1
"0010" when "01", -- 10
"0100" when "10", -- 100
"1000" when "11", -- 1000
"1111" when others; -- ?

with SEG_segval select
SEG_DATA <=
"1111110" when "0000", -- 0
"0110000" when "0001", -- 1
"1101101" when "0010", -- 2
"1111001" when "0011", -- 3
"0110011" when "0100", -- 4
"1011011" when "0101", -- 5
"1011111" when "0110", -- 6
"1110000" when "0111", -- 7
"1111111" when "1000", -- 8
"1111011" when "1001", -- 9
"1110111" when "1010", -- A
"0011111" when "1011", -- B
"1001110" when "1100", -- C
"0111101" when "1101", -- D
"1001111" when "1110", -- E
"1000111" when "1111", -- F
"0110111" when others; -- 10-15, H mark

SEL <= '0' & SEG_SEL;
DAT <= not ('0' & SEG_DATA);

end rtl;