Spartan-3A スタータキット

〜イーサネットでの受信〜


2007/08/12

あなたは 人目のお客様です.

イーサネットのリンクアップはできた. 次は送受信だ.

で,まずは送信を試してみたのだけどうまくいかない. スタータキットとFreeBSDのPCを直結してパケット送信しても, FreeBSD側でパケットキャプチャ(wireshark利用)でキャプチャできていない. 状態遷移は正常に動いているようなのだが...

CRC異常も含め,異常なフレームはイーサネットのチップが捨ててしまうので, FreeBSD側ではまったく見ることができない(キャプチャできない). なのでCRCの値がおかしいのか,TX_ENを上げ下ろしするタイミングがまずいのか, クロックに対する信号タイミングがまずいのか, そもそも送信信号自体が出ていないのか,なんとも判断つかなくて, デバッグに苦戦している.

で,困っていたのだけど,PHYにはループバック機能というのがあって, 自分が送信したフレームをそのまま受信することができるようだ. なので受信機能を実装してうまく受信できれば, 送信が正常に行われているかどうかの確認に使える. ということで,まずは受信を実装することにした.

まあ結果から言うと,受信はサックリと動作した. ちなみに送受信に関しては, イーサネットのリンクアップで紹介した Interface 2005/08 号の「Ethernetにおける内部インターフェース − MIIの動作」 というそのまんまの記事と,あとその後の 「FPGAによるEthernetコントローラの設計事例」という記事が役に立つ.

で,書いたソースコードはこんなかんじ. 上に書いたように,当初は送信機能を実装していたので送信機能も入っているのだけど こちらは正常には動いていない.

main.v
rx.v
tx.v
ether_ctrl.v
ether_rx.v
ether_tx.v
memory.v
s3astarter.ucf

いつものように,シリアル経由でコマンドを入力するとそれに応じて動作するように してある. tx.v, rx.v はシリアル送受信用のモジュールで,相変わらず以前からの流用. あと ether_ctrl.v は前回からの流用. ちなみに s3astarter.ucf では,

NET "E_TX_CLK"      LOC = "E11"  | IOSTANDARD = LVCMOS33 | PERIOD = 40.000 ;
#OFFSET = IN   5.000 VALID 10.000 BEFORE "E_TX_CLK" ;
#OFFSET = OUT 10.000 AFTER "E_TX_CLK" ;

NET "E_RX_CLK"      LOC = "C12"  | IOSTANDARD = LVCMOS33 | PERIOD = 40.000 ;
#OFFSET = IN   5.000 VALID 10.000 BEFORE "E_RX_CLK" ;
#OFFSET = OUT 10.000 AFTER "E_RX_CLK" ;
のようにして,クロックのOFFSETという定義をコメントにしてある. こうしないと論理合成のときになんかエラーになってしまう (遅延が大きすぎるというエラーか?詳細不明)みたいなので.

今回実装してあるコマンドは以下の通り.

まずはSコマンドでリセットし,Gコマンドでリンクアップを確認する. んで送信したいときは,Lコマンドでフレームサイズを指定, 必要ならXコマンドでCRCのビット反転を指定, Dコマンドを繰り返し発行してフレームの内容を設定し, Tコマンドを発行すると送信処理が行われる.(でもまともに動いていない)

受信時には,フレームを受信すると勝手に受信を行いブロックRAM上に格納するので, Aコマンド発行してサイズを取得し, Rコマンドを繰り返し発行すると,フレームの内容を見ることができる.

以下,動作例.まずはコンパイルし, いつもどおりシリアル接続してからFPGAにダウンロード.

hiroaki@teapot:~>% su
Password:
teapot# cu -l /dev/cuad0
Connected
READY
READYメッセージが出力される.次に 前回 のようにクロスケーブルで FreeBSD の PC とスタータキットを接続, ifconfig で udav0 を UP し,SコマンドとGコマンドを発行する.
hiroaki@teapot:~>% su
Password:
teapot# cu -l /dev/cuad0
Connected
READY$S+SET$G+7809$G+780d
ステータスが 0x7809 → 0x780d に変化しているので, リンクアップしていることがわかる. なぜかGコマンドは2回目でリンクアップを検出できるようだ.

AコマンドとRコマンドを発行してみる.

hiroaki@teapot:~>% su
Password:
teapot# cu -l /dev/cuad0
Connected
READY$S+SET$G+7809$G+780d$A+00000000$R+00000000
この状態では受信したフレームが無いので, Aコマンドではサイズゼロが返ってきている. Rコマンドでは,先頭データが返ってきているが, これもフレームを受信していないので,オールゼロになっている.

FreeBSD側からてきとうなフレームを送信してみる. まずは ifconfig で適当なIPアドレスを指定する. とりあえず 192.168.10.1/24 にしてみる.

teapot# ifconfig 
...
udav0: flags=108943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,NEEDSGIANT> mtu 1500
        ether 00:XX:XX:XX:XX:XX
        media: Ethernet 100baseTX
        status: active
...
teapot# ifconfig udav0 192.168.10.1/24 
teapot# ifconfig 
...
udav0: flags=108943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,NEEDSGIANT> mtu 1500
        inet 192.168.10.1 netmask 0xffffff00 broadcast 192.168.10.255
        ether 00:XX:XX:XX:XX:XX
        media: Ethernet 100baseTX
        status: active
...
teapot# exit
で,適当なアドレスに向けて ping を実行する. これによってARPフレームが udav0 に送出されることになる.
teapot# ping 192.168.10.2
PING 192.168.10.2 (192.168.10.2): 56 data bytes
^C
--- 192.168.10.2 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
teapot#
これでスタータキット側ではARPフレームを受信したはずだ. まずはAコマンドでフレームのサイズを取得する.
hiroaki@teapot:~>% su
Password:
teapot# cu -l /dev/cuad0
Connected
READY$S+SET$G+7809$G+780d$A+00000000$R+00000000$A+00000010
Aコマンドの応答として,さっきとは異なりサイズとして 0x00000010 が 返ってきている.データは4バイト単位で管理しているので, 64バイトのフレームを受信していることがわかる.

Rコマンドでフレームの内容を確認する.

hiroaki@teapot:~>% su
Password:
teapot# cu -l /dev/cuad0
Connected
READY$S+SET$G+7809$G+780d$A+00000000$R+00000000$A+00000010$R+ffffffff$R+9a00ffff$R+81000608$R+04060008$R+9a000100
エンディアンが逆になっているのでひっくり返すと, 以下のようなフレームを受信したことになる.
ffffffffffff 009a 08060081 08000604 0001009a
うーん,送信フレームを wireshark でキャプチャした結果と比べると, 微妙にフレームがおかしくなっている. ブロックRAMとのやりとりのあたりで化けてしまっているような気がする.

まあ,とりあえず動いてはいるようなので,あとはまた明日考えよう.眠いし.


メールは kozos(アットマーク)kozos.jp まで