« ボードコンピュータ展に出展します | トップページ | テクノフロンティア2009・ボードコンピュータ展に出展しました »

2009.04.14

玄箱ProのPCI Expressに自作拡張機器をつなぐ

Debian化した玄箱ProのPCI Expressに、特電PCI Expressボードをつないで、プログラムを書いて制御することができました。

玄箱Proの正面蓋を開け、特電PCI Expressボードを挿しこみます。
一昨年挑戦
した時は、XILINXのPCI Expressスタータキットを使っていましたが、基板サイズが大きかったため筐体のプラスチックを外さないとだめでした。今年は特電PCI Expressボードなので、筐体を外さなくてもよく、見た目もスマートになりました。
玄箱ProのPCI Expressに自作機器をつなぐ

拡張ボード上のFPGAには、PCIeサポートページにあるPCI Express GPIOのサンプルデザインを論理合成して出来あがったBitStreamを入れておきます。

そして、玄箱Proを起動します。

起動中に次のようなメッセージが出ているのを確認します。


CPU Interface
-------------
SDRAM_CS0 ....base 00000000, size 128MB
SDRAM_CS1 ....disable
SDRAM_CS2 ....disable
SDRAM_CS3 ....disable
PEX0_MEM ....base e0000000, size 128MB
PEX0_IO ....base f2000000, size 1MB
PCI0_MEM ....base e8000000, size 128MB
PCI0_IO ....base f2100000, size 1MB

このメッセージは、PCI Expressには最大で128Mバイトのメモリ空間を割り当てられるよと解釈できます。GPIOサンプルは64kバイトと256バイトのメモリ空間を要求するので、割り当て可能でしょう。

起動したら、早速、lspciコマンドでコンフィグレジスタを見てみます。


kurobox:/home/naitou# lspci -vxxx
00:01.0 DPIO module: Unknown device 5678:1234 (rev 01)
Subsystem: Unknown device 5678:1234
Flags: bus master, fast devsel, latency 0, IRQ 11
Memory at e0010000 (32-bit, non-prefetchable) [size=256]
Memory at e0000000 (32-bit, non-prefetchable) [size=64K]
Capabilities: [60] Message Signalled Interrupts:
Mask- 64bit- Queue=0/0 Enable-
Capabilities: [70] Power Management version 3
Capabilities: [80] Express Endpoint IRQ 0
Capabilities: [100] Unknown (22136)
00: 78 56 34 12 46 01 10 00 01 00 00 11 00 00 00 00
10: 00 00 01 e0 00 00 00 e0 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 78 56 34 12
30: 00 00 00 00 60 00 00 00 00 00 00 00 0b 01 00 00
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: 05 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00
70: 01 80 03 00 00 00 00 00 00 00 00 00 00 00 00 00
80: 10 00 01 00 05 00 00 00 00 20 00 00 11 04 00 00
90: 00 00 11 10 00 00 00 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

コンフィグレジスタは設計値どおりです。認識には問題ないようです。

PCI Expressカードが認識されたので、自作のプログラムを作って制御したいところですが、どうやら玄箱用のPCI Express制御プログラムを作るには、ちゃんとしたLinuxのデバイスドライバを作る必要はなさそうです。
Linuxでは、/dev/memというスペシャルファイルを経由して、メモリ空間の任意の物理アドレスにアクセスできるからです。

この方法を使うには、まずメモリ空間がどこに割り当てられたかを知る必要があります。そのためには、
cat /proc/iomemと打ちます。


kurobox:/home/naitou# cat /proc/iomem
00000000-07ffffff : System RAM
00025000-00372a5f : Kernel text
00374000-003eb333 : Kernel data
e0000000-e7ffffff : PCI Memory Primary
e0000000-e000ffff : 0000:00:01.0
e0010000-e00100ff : 0000:00:01.0
e8000000-efffffff : PCI Memory Primary

どうやら、PCI Expressの拡張ボードは、0xe0010000~の256バイトと、0xe0000000からの65536バイトに割り当てられたようです。おそらく前者がBAR0空間でしょう。

つまり、物理メモリ空間の0xe0010000にアクセスすれば、PCI expressのボード上のFPGA内に作ったBAR0空間のレジスタに指令が伝わるはずです。

ところが、Linuxのメモリ空間は仮想メモリ空間なので、*(unsigned long *)0xe0010000とやってもアクセスできません。mmapという関数を使ってマップしてやる必要があります。プログラムは次のようになりました。


int main()
{
unsigned char buff[256];
memset(buff,0,256);
int fd = open("/dev/mem",O_RDWR);
if(fd < 0) printf("can not open /dev/mem\n");
unsigned long *mm = mmap(0,0x100,PROT_READ
| PROT_WRITE,MAP_SHARED,fd,0xe0010000);
if(mm != MAP_FAILED)
{
*mm = 0x00030055;
sleep(1);
*mm = 0x000300AA;
sleep(1);
*mm = 0x00030055;
sleep(1);
*mm = 0x000300AA;
sleep(1);
}
close(fd);
}

このプログラムは、まず/dev/memというファイルを開きます。そして、mmap関数を使って0xe0010000からの0x100バイトを仮想アドレス空間に割り当てます。割り当てられた仮想アドレスは、mmというポインタを通じてアクセスできるようになります。
以後、*mmとやれば、物理メモリの0xe0010000番地を読み書きできるというしくみです。
(そういえば、Windowsのデバイスドライバでも同じような関数がありました。根底の部分では似ているのですね)

Linuxの場合、root権限さえあれば本格的なデバイスドライバを書かなくても、ユーザモードのプログラムでPCI Expressに簡単にアクセスできることがわかりました。この場合、ベンダIDもデバイスIDも不要です。どの物理アドレスに割り当てられたかということさえわかればよいようです。

玄箱ProのPCI Expressに自作機器をつなぐ玄箱ProのPCI Expressに自作機器をつなぐ

どこまで高速にできるか、と試してみたくなり、
memcpy(mm,buff,256);
とやればバースト転送ができるかと思ったのですが、そこまで賢くは作られていませんでした。
JTAGロジックアナライザでPIPEの波形を観察したところ、1ワード(4バイト)の転送が64回発行されているのが確認されました。
Kuropro_4

memcpyを使う限りでは、玄箱→FPGA方向へは4MBytes/sec程度、FPGA→玄箱方向は3.2MBytes/sec程度の転送速度でした。動作速度を向上させるには、combined writeや、DMA readを発行させるようにしたほうがよいのでしょう。それには、ちゃんとしたデバイスドライバを作らないといけなさそうです。玄箱ProはARM9なので、combined writeみたいなのがあるかどうかはわかりません。DMAを使えば、FPGA→玄箱方向の転送は190MByesくらい出せるのではないかと思います。

しかし、デバドラ不要の簡単なプログラムでもそこそこの速度が安定して出せるのはPCI Expressの魅力です。USBと違って反応速度が速い(1000倍違う)のも大きな魅力です。

さて、今回使った特電PCI Express IPコアとGPIOサンプルは、あわせてXC3S1200Eの17%くらいのリソースしか使用しません。このボードは120万ゲートのFPGAを使っているので、単純に考えれば残りの100万ゲートほどをユーザが自由に使える計算になります。

『ネットワーク経由で制御されるスタンドアローンのコンピュータに、PCI Express接続のFPGAがつながっていて、100万ゲート相当の回路が自由にカスタマイズできる』というのも、夢が広がって面白いのではないでしょうか。
アイデア次第でいろんなことに応用できそうです。

|

« ボードコンピュータ展に出展します | トップページ | テクノフロンティア2009・ボードコンピュータ展に出展しました »

コメント

ARM9なら、LDM/STM命令で1ワード以上の転送ができるので、アセンブラを使えば、デバイスドライバがなくてもある程度高速に転送できるのではないでしょうか?

投稿: yas | 2009.04.25 00:48

yasさん、コメントありがとうございます。

ARM系のアセンブラには疎いのですが、そういえばそんな命令もありましたよね。実際に複数ワードの転送がPCIeバス上に発行されるかどうかはルートコンプレックスの仕様次第なので、どうなるかわかりませんが、明日、試してみることにします。

投稿: なひたふ | 2009.04.28 01:51

コメントを書く



(ウェブ上には掲載しません)




« ボードコンピュータ展に出展します | トップページ | テクノフロンティア2009・ボードコンピュータ展に出展しました »