Alveo U50のUART

Alveo U50 を使うことになって、ちょっとずついろいろ試しているのですが、ようやく Alveo U50 Getting Started に掲載されている Vivado 用の XDC ファイルが更新され、U50 SFP (Production版) のファイルになりました。

以前公開されていた U50DD (ES版) の XDC ファイルは中身がだめだめだったのですが、今回はわりとちゃんとしているようです。PCIe 関係などは XDC がなくてもボードファイルをのぞけばピン配置などがわかったのですが、XDC ファイルにはそれ以外の情報も掲載されていて、たとえば、

# Bank 65 and 68 FPGA UART Interface 0/1/2 to DMB-01 (User selectable Baud) 
#    FPGA_UART0/1/2_RXD  Input from DBM-01 UART to FPGA 
#    FPGA_UART0/1/2_TXD  Output from FPGA to DBM-01 UART 

とあって、どうやらプログラミングケーブルを経由して UART が使えるようです。

で、3つ使える、とあるのですが、試してみたところ使えるのは 0, 1 のみで、2 は未接続な感じです。プログラミングケーブルに搭載されているのは FT4232 で、4ポートの UART ポートがあるのですが、これはどうやら

  1. JTAG
  2. (未接続?)
  3. FPGA_UART0
  4. FPGA_UART1

というふうに接続されているようです。1. の JTAG ポートは、はじめ /dev/ttyUSBx として見えているのですが、Vivado や xsdb などで接続すると消えてしまうので、JTAG ポートということなのでしょう。

なお、プログラミングケーブルには「使わない」と書かれている MicroUSB ポートがもうひとつあるのですが、こちらに接続するとやはり FT4232 が現れます。Vivado の Hardware Manager でのぞいてみると、ARM DAP が現れますので、こちらはサテライトコントローラのMSP432と、その UART ポートが接続されていそうです。

MacPorts で gnutls

研究室の環境もぼちぼちMojaveにアップデートしつつあるのですが、Emacs + Wanderlust でメールを読もうとしたらいきなりクラッシュ。なんでかー、と思って backtrace を眺めたらどうやら IMAP で STARTTLS しようとして、 gnutls-cli を呼んだところで落ちている。Ivy Bridge とか Haswell な Mac だとダメで、いまどきの新しい Mac なら問題ないようだ。つまり、SSEx だとかその手のやつですよね。

というわけで、
% gnutls-cli –startls-proto=imap my.mail.server
としたら本当に落ちるじゃありませんか。しかも Illegal instruction だと…

で、どうやら gnutls の問題じゃなくて、GMP の問題らしい: http://lfsbookja.osdn.jp/7.10/chapter06/gmp.html

MacPorts の枠組みの中でなんとかならんかなー、と思った結果、GMP に core2 という variant があるので、これを使えば Core2 アーキテクチャまでの最適化しかしない、ということで、とりあえず解決。よかった… (まあ GMP でごりごり、みたいなことはしないので、いいか)

FreeBSD + LDAP + tcsh

SunOS4と386BSDでUnixを使い始めて20年ちかく、csh/tcshを使ってきたのですが、研究室の環境をFreeBSD 10.2に更新してから、ctrl+cでシェルが死ぬ、という問題が起こるようになりました。入力しかけのコマンドをキャンセルしたいときとかにもつい押しますし、これすげー困りますよ。

それでちょっと検索してみると、

といったように、どうやらうちの研究室固有の問題ではないということに気づきました。こまったこまった。

ということを Facebook に書いたら、学生時代の研究室の先輩方に「おまえまだ tcsh 使ってんのかよはやく zsh にしろよ」といわれまして、つい乗り換えてしまったのですが、root とかはデフォルトの csh のままなわけでして、難しい作業やってるときにシェルが死ぬと集中力きれて困るわけで。

それで、新しい端末をセットアップしていたときに、ports に nss-pam-ldapd というのが入っていることに気づいて、これを使ってみたら ctrl+c おしても平気。nss_ldap や pam_ldap の派生プロジェクトだそうです。

これにてどうやら解決です。めでたい。

OpenNTPd で行こう

サーバ関係はずっとFreeBSDで生きているわけですが、いまの職場に移ってきてすごく困ったことのひとつが、外部からのUDP/123が閉じられていること。FreeBSDとか、多くのUnix系OSに含まれているntp.org版のntpdでは、これだと外部のNTPサーバと同期することができません (学内のNTPサーバにも届かない…!)。
それで、いままでどうしていたかというと、ローカルのNTPサーバになるホストをntpdate -u で毎晩外部のNTPサーバと同期させて、あとはそのホストを参照していたわけですが、なぜか突然動かなくなりまして、ntpq -p しても、LOCAL(0) へのreachが0とかなんなの… という状態。ntpdがちゃんと動いているか、動いてないならなんでダメなのか、ログをいろいろあたっても全然わからず。
それで、とりあえずntpdでの外部のサーバへのアクセスがntpdate -u相当 (非特権ポートでのアクセス)になればいいんじゃないの、と思ったけれども、どうやらそれはできないようです。
解決策をいろいろ調べていたら、”openntpdならできるよ!” みたいな記事がちらほら。OpenSSH的に、OpenBSDのプロジェクトの一部として開発されているそうです。たしかに、ntp.orgなntpdはときどきセキュリティホールが見つかったりしてて、ドキドキすることもあるしなあ。OpenBSDらしく、シンプルに堅牢に、ということだそうで、設定ファイルは誰を参照してどのアドレス/ポートをListenするか、ということくらい(あと、何かセンサを持ってる人はそれも)。
マイクロ秒単位での正確性という面ではntp.orgの実装のほうが上だそうですが、うちは別にmakeがおかしくならなければいいよ、という程度なので、精度的には充分です。設定ファイルは簡単で、

listen *
server ntp1.hogehoge.org
server ntp2.hogehoge.org

みたいに書いただけで動きました (どうせ firewall でいろいろきってるので、listen * でOK)。超ステキ。ntpq -p 相当の、いまどこと同期がとれてるかは、

% ntpctl -s all

で見られます。見ていると、安定してきたら外部のサーバをpollingしにいく間隔も長くなるようですし、これはトラフィックの軽減というポイントからは非常にいいですね。
それから、当然NTP準拠なので、Macをはじめ、ローカルのNTPクライアントの設定はそのままで動きます。これからはこれでいこう。

Raspberry Pi 2 + FreeBSD 11 + X.org

ARMv6 な FreeBSD 11-CURRENT では FreeBSD の pkg の提供がはじまっており、べんりべんり。
Raspberry Pi 2 用の起動 SD カードイメージも配布されています。

pkg で xorg と xf86-driver-scfb いれたら X もあがりました。
ただ、auto negotiation 的ないろいろがないので、Xorg -configure みたいなのはできません。
モニタとの解像度などの negotiation は syscons がやってくれるので、scfb driver で X 動きます。
遅いんですが、まあなんとか使えるかな、という感じでもあります。本体のメモリがあんまりないので X 端末的な感じでしょうか。

というわけでこんな xorg.conf で動きました。

Section "Files"
EndSection
Section "Module"
  Load        "dbe"
  Disable    "dri"
  Disable    "dri2"
  Disable    "glx"

  SubSection  "extmod"
    Option  "omit xfree86-dga"
  EndSubSection
EndSection

Section "ServerFlags"
  Option    "AIGLX"        "false"
  Option    "NoAccel"    "True"
  Option    "NoDRI"        "True"
  Option    "DRI"        "False"
  Option    "DRI2"        "False"
EndSection

Section "InputDevice"
  Identifier  "Keyboard1"
  Driver      "kbd"
EndSection

Section "InputDevice"
  Identifier  "Mouse1"
  Driver      "mouse"
  Option      "Protocol"      "auto"
  Option      "Device"        "/dev/sysmouse"
EndSection

Section "Monitor"
  Identifier  "Monitor"
  Mode "1680x1050"
    DotClock        147.14
    HTimings        1680 1784 1968 2256
    VTimings        1050 1051 1054 1087
  EndMode
EndSection

Section "Device"
  Identifier  "Generic FB"
  Driver      "scfb"
  Option    "NoAccel"    "True"
EndSection

Section "Screen"
  Identifier  "Screen"
  Device      "Generic FB"
EndSection

Section "ServerLayout"
  Identifier  "layout"
  Screen      0 "Screen" 0 0
  InputDevice "Mouse1" "CorePointer"
  InputDevice "Keyboard1" "CoreKeyboard"
EndSection

ZYBOでFreeBSDその後

学期が始まってから急に忙しくなって、長らく作業が止まっていたのですが、ちょっと時間がとれたのでいくつかやってみたことがあります。わかったことのまとめ。
– PS の初期化 (CPU clockのPLLとか、PS側のI/Oの設定) は FSBL によって行われる。.bit ファイルではない。
– したがって、boot.bin に .bit ファイルを含めることは必ずしも必須ではない (ZYBOの場合はちがう: 後述)
– FSBL は前半で最低限の設定をし、PL が構成されたら後半の作業をする
– ZYBO の場合、この後半の作業で I2C ROM から MAC アドレスを読み出すが、I2C は PL 経由の EMIO に接続されているので、ここをつなぐ .bit ファイルがロードされていないと FSBL の途中で固まる。
– PS がびっくりしない程度の範囲で PL は起動後に書き換えてもよさそう。たとえば、Master AXI ポートの先の回路が変わるくらいはなんともない模様。ただ、Slave AXI ポートとか、ACP ポートはどうかな…
とりあえず、Master AXI の先に LED とスイッチつないで、/dev/mem を mmap したところ、スイッチの値は読み出せましたが、LED は全然だめで、おそらくこれはキャッシュか何かが悪さをしているのだと思います。
FreeBSD/ARM の /dev/mem はまだ buggy なようで、キャッシュしちゃったりするようです。memcontrol も使えないし、まあ、そのあたりの実装がまだちゃんとできていない、ということなのでしょう。なので、AXI なモジュールつくったら、デバイスドライバ書かないといけない感じですね。というわけで、適当なドライバを書いたあたりで、また記事を書くことにしましょう。

ZYBO で FreeBSD が動くまで (ハードウェア編)

前回までの記事では Digilent が提供している ZYBO Base Design をそのまま使って FreeBSD を起動する、というのをやったのですが、この Base Design には HDMI のコントローラやら何やらが載っており、それなりに PL 部のリソースを使っています。自分で hack する以上は、PL 部はほとんどからっぽ、という状態からスタートしたいのが人情です。
というわけで、自分でやってみました。結果からいうと簡単で自明な理由なのですが、実はけっこうはまりましたので、記録としてここに残しておこうと思います。
作業を始める前に、Digilent のウェブサイトから ZYBO_zynq_def.xml (ZYBO Board Definition File for configuring the Zynq Processing System core in Xilinx Platform Studio and Vivado IP Integrator) をダウンロードしておくと便利です。これを使うと、クロックや MIO の設定などを ZYBO 用に一括で設定可能です (ZedBoard 用もあります)。

  1. Vivado のプロジェクトを作る (XC7Z010-CLG400-1)
  2. Create Block Design で新しいブロックデザインを開く
  3. Add IP で Zynq7 Processing System を加える
  4. 現れた Zynq PS のブロックをダブルクリックして設定画面を開く

これで、”Import XPS Settings” からさきほどの ZYBO_zynq_def.xml を読み込むと、画面が以下のようになります。
zynq-customize.png
I2C や UART1, SD0, USB0, ENET0 などにチェックが入ったら PS の設定は OK です。Clock Configuration や DDR Configuration なども正しく設定されているはずです。このあと、PS 周辺部の設定をしていきます。
ポイントは、

  • DDR と FIXED_IO は Make External する (これは自動でもできる)
  • IIC_0 (I2Cのこと) も Make External する
  • SDIO0_WP は Low に落とす
  • Master AXI GP port のクロックは FCLK_CLK0 をつないでおく

というあたりです。
DDR (DDR SDRAM) と、FIXED_IO (固定機能ピン) は右クリックして “Make External” すれば下の図のようにブロックの出力ポートとなり、これはピンが決まっているので、なにもしなくても配置配線後にちゃんと外にでてくれます。
IIC_0 (I2C) も同様に Make External してブロックの外に出しますが、これは Zynq PS の設定の Peripheral I/O Pins の画面で見ると “EMIO” でなっており、PL 部の programmable fabric につながるので、最終的にどこのピンにつながるかを自分で指定する必要があります。
I2C、何に使うのかわからなくて放置していたのですが、実は ZYBO では MAC アドレスが I2C ROM に記録されており、FSBL を書き換えるところのコード (fsbl_hooks.c) ではこの ROM を参照しにいっています。このとき I2C が配線されていないとそこで止まってしまい、OS の起動までたどり着けないので注意しましょう。
また、ZYBO には Micro SD カードスロットが載っていますが、Micro SD なので Write Protect の検出がありません。これも EMIO に出ているピンですので、Add IP で “Constant” を呼び出して、値を 0 にして SDIO0_WP につないでしまいましょう。
Master AXI ポートがひとつありますが、いまのところ使わないので、このクロックは FCLK_CLK0 につないでおけばよいでしょう。何もつながないとエラーになります。
ということで、できあがりの block design は下のようになります。
zynq-block.png
あとは、

  1. Generate Block Design する (Flow navigator で)
  2. Create HDL Wrapper する (デザイン階層でブロックデザインを右クリック)
  3. I2C のピンを制約に追加して bitstream 生成

すれば OK です。
デフォルトで HDL Wrapper に現れる I2C なポートの名前は iic_0_scl_io と iic_0_sda_io だと思いますので、以下を XDC ファイルに追加すれば OK です。これを書かずにやると、I2C のピンがどこか知らないところへ行ってしまうので気を付けましょう。
[code:plain]
set_property PACKAGE_PIN N18 [get_ports iic_0_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports iic_0_scl_io]
set_property PACKAGE_PIN N17 [get_ports iic_0_sda_io]
set_property IOSTANDARD LVCMOS33 [get_ports iic_0_sda_io]
[/code]

ZYBO で FreeBSD が動くまで (3)

前回の記事では ZedBoard 用のカーネルで ZYBO を起動するところまで書きました。ZedBoard 用のカーネルでは、Ethernet のポートとして cgem0 が認識されますが、ifconfig であれやこれや頑張ってみてもどうにも使えません。dmesg をみるとこんな感じです。
[code:plain]
cgem0: mem 0xb000-0xbfff irq 54,55 on simplebus1
miibus0: on cgem0
ukphy0: PHY 0 on miibus0
ukphy0: none, 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, 1000baseT, 1000baseT-master, 1000baseT-FDX, 1000baseT-FDX-master, auto
ukphy1: PHY 1 on miibus0
ukphy1: none, 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, 1000baseT, 1000baseT-master, 1000baseT-FDX, 1000baseT-FDX-master, auto
cgem0: Ethernet address: 00:1e:c0:ac:bf:8e
[/code]
一方、10.1-RELEASE をみると、src/sys/arm/conf/ZEDBOARD には
[code:plain]
device ether
device cgem # Zynq-7000 gig ethernet device
device mii
device e1000phy
[/code]
と書かれており、cgem に e1000phy を組み合わせて使うことになっているようです。e1000phy は Marvell 88E1000 用のドライバですが、ZYBO に載っているのは Realtek RTL8211E なので、rgephy を使うのが正しいです。

そういうわけで、ZYBO 用のカーネルコンフィギュレーションは ZEDBOARD のをちょっとだけいじれば OK です。
[code:plain]
-ident ZEDBOARD
+ident ZYBO
[/code]
[code:plain]
device ether
device cgem # Zynq-7000 gig ethernet device
device mii
-device e1000phy
+device rgephy # RealTek GbE PHY
[/code]
FreeBSD のソースコードリポジトリからソースツリーを取得してコンパイルします。root 権限は使わずにふつうにユーザ権限でやればよいでしょう。/usr/obj のかわりにどこにオブジェクトを生成するかは MAKEOBJDIRPREFIX で指定します。
[code:plain]
% setenv MAKEOBJDIRPREFIX=${pwd}/obj
% svn co https://svn0.us-west.freebsd.org/base/stable/10 src
% cd src
% cp sys/arm/conf/ZEDBOARD sys/arm/conf/ZYBO
% vi sys/arm/conf/ZYBO
% make -j8 buildworld TARGET_ARCH=armv6
% make -j8 buildkernel TARGET_ARCH=armv6 KERNCONF=ZEDBOARD
[/code]
あとは SD カードをマウントしてふつうにインストールします。
[code:plain]
% su
# mount /dev/da0s2a/mnt
# setenv MAKEOBJPREFIX=…
# make installworld DESTDIR=/mnt
# make installkernel DESTDIR=/mnt KERNCONF=ZYBO
[/code]
installworld では chflags noschg とかしないといけないところが何カ所かありますが、ま、なんとかなります。

ports とかもふつうに使えるので、ある程度の開発環境は ZYBO ネイティブでやるのがよさそうです。僕の研究室の環境ではふつうに ZYBO のログインを LDAP で認証して、NFS 経由でホームディレクトリが見えています 🙂

ZYBO で FreeBSD が動くまで (2)

前回の記事でブートローダーを作るところまで行ったので、こんどはそれを使って、コンパイルを一切せずに FreeBSD をブートするところまで行きたいと思います。ZedBoard 用に配布されているファイルを使うので Ethernet は使えませんが、それ以外はふつうに使えますし、FreeBSD が動いている環境がなくても OK です。ただ、シリアルコンソールが使える環境を用意してください。

  1. ZedBoard 用のSD カードイメージをダウンロードして書き込む
  2. 起動用のファイルを ZYBO 用に差し替える
  3. 動かしてみる

といった手順で説明していきます。

Step 1: SDカードイメージをダウンロードして書き込む

配布されている SD カードイメージのサイズは 1GB 程度 (大半が空き領域ですが) なので、2GB 以上のカードならば問題ないと思います。Class 10 など、なるべく速いものを用意しましょう。

書き込むと、

  • mmcsd0s1: FAT フォーマットのブート領域
  • mmcsd0s2a: UFS な FreeBSD root filesystem

になりますので、書き込み前に Micro SD カードに入っていた内容は消えてしまいます。注意してください。

SD カードのイメージは、FreeBSD の FTP サイトの、pub/FreeBSD/releases/arm/armv6/ISO-IMAGES/ で配布されています。たとえば、10.1-RELEASE のものなら、10.1/FreeBSD-10.1-RELEASE-arm-armv6-ZEDBOARD.img.bz2 をダウンロードして、bunzip2 (最近のものは xz で圧縮されていますので unxz) で展開してください。これをそのまま dd で書き込めば OK です。
[code:plain]
% dd if=FreeBSD-10.1-RELEASE-arm-armv6-ZEDBOARD.img of=/dev/da0 bs=1048576
[/code]
とかそんな感じです。of= のところはデバイス名なので、OS や環境次第です。Mac でも、/dev/disk1 とかすれば、ちゃんと書き込むことができます。書き込みに成功すると、/dev/ の下にパーティションがふたつ生えてきます。次のステップでは、このうち 1 つ目の、FAT フォーマットのパーティションに、起動に必要なファイルを書き込みます。
Step 2: 起動用のファイルを ZYBO 用に差し替える
SD カードの起動用パーティションには以下のファイルがあります。

  • boot.bin: FSBL + .bit ファイル + u-boot (ZedBoard 用)
  • license.txt
  • ubldr: u-boot 用の FreeBSD ブートローダ
  • uenv.txt: u-boot の設定ファイル (ZedBoard 用)
  • zedboard.dtb: ZedBoard の device tree blob
  • zedboard.dts: zedboard.dts のソース

このうち boot.bin は前の記事で作ったもの、ubldr は SD カードにあるものをそのまま使えますので、最後の3つだけを準備すれば OK です。

uenv.txt には u-boot がどのファイルをどのアドレスにロードし、どこから起動するか、が記述されています。最低限変更しなければならないのは、device tree blob のファイル名だけです。また、ZedBoard 用に配布されているものは SD カードからの boot だけでなく、tftp での boot にも対応した記述がされていますが、これは不要なら削除しても構いません。たとえば、以下のようにします:
[code:plain]
kernel_addr=0x100000
ubldr_addr=0x100000
dtb_addr=0x1000
dtb_name=zybo.dtb
uenvcmd=echo Booting FreeBSD from SD…; mmcinfo ; fatload mmc 0 ${ubldr_addr} ubldr ; fatload mmc 0 ${dtb_addr} ${dtb_name} ; fdt addr ${dtb_addr} ; bootelf ${ubldr_addr}
[/code]
このうち、kernel_addr は実は使わないのですが、なんとなく残してあります。

これで、起動に必要なファイルを SD カードからメモリにロードして kernel を起動する準備ができました。しかし、 Zynq などで使われているバスは、PCI バスのようなネゴシエーションの仕組みを持っていないので、kernel には (かつて ISA バス時代の FreeBSD や Linux がそうであったように) 各デバイスのアドレスなどを教えてあげる必要があります。ISA バスの時代にはこれらは kernel にハードコードされており、ハードウェアの変更にあわせてカーネルを再構築する必要がありましたが、最近はこれを device tree blob (.dtbファイル) というのを使って再構築なしに簡単に実現する仕掛けが用意されています。.dtb は、簡単な構文のソースファイル (.dts) から生成することができ、.dtb から .dts への逆変換も可能です。

Device tree blob は Linux でも FreeBSD でも使われていますが、記述する内容は OS のバスアーキテクチャやデバイスドライバに依存するため、実質的に内容は OS 依存になります。したがって、Linux 用の .dtb をそのまま使うことはできません。なお、ZYBO + Linux 用の .dtb は Digilent が GitHub に置いている Linux カーネルのリポジトリから手に入れることができます。FreeBSD の場合には、以下で説明するように ZedBoard 用のものを変更するのがよいでしょう。

変更は2カ所必要で、まず一カ所目はタイマの周波数です。Zynq の Global Timer は CPU core clock の半分の周波数で動きますので、これを正しく設定する必要があります。ZedBoard の ARM core は 666MHz 動作ですが、ZYBO では 650MHz になりますので、325MHz を設定します。10進数でも16進数でも構いません。この数字を間違えると、タイマ割り込みの周波数が正しく設定されず、変なところで device timeout が発生したりして、あちこちおかしくなるので注意が必要です (PS への供給クロックかと思って 50MHzにしたら、SD カードがすぐタイムアウトするし、時計が5倍速くらいで進むのでびっくりしました…)。
[code:plain]
timer@f00600 {
compatible = “arm,mpcore-timers”;
– clock-frequency = <0x13de4355>;
+ clock-frequency = <325000000>;
#address-cells = <0x1>;
#size-cells = <0x0>;
reg = <0xf00200 0x100 0xf00600 0x20>;
interrupts = <0x1b 0x1d>;
interrupt-parent = <0x1>;
};
[/code]

もうひとつ、USB host (echi0) からは phy_vbus_ext を削除します。ZedBoard では USB PHY が外付けなのでこれが必要ですが、ZYBO ではこれがついていると USB PHY の初期化が行われず、USB が使えません。
[code:plain]
ehci0: ehci@2000 {
compatible = “xlnx,zy7_ehci”;
reg = <0x2000 0x1000>;
interrupts = <0x35>;
interrupt-parent = <0x1>;
– phy_vbus_ext;
};
[/code]

また、ZYBO 用のファイルですよ、ということをきちんと書いておいてもよいと思います (とりあえず動けばいいよ、というのなら関係ないですが)。
[code:plain]
– model = “zedboard”;
– compatible = “digilent,zedboard”;
+ model = “zybo”;
+ compatible = “digilent,zybo”;
[/code]

.dts をコンパイルして .dtc を作るには Device Tree Compilerが必要です。たいていのプラットフォームで make 一発でビルドできると思います。
[code:plain]
% dtc -I dts -O dtb zybo.dts -o zybo.dtb
[/code]
のようにすると zybo.dts から zybo.dtb を生成することができます。
boot.bin, uenv.txt, zybo.dtb を、Micro SD カードの1つ目のパーティション (FAT) にコピーすれば終わりです。

Step 3: 起動する

ZYBO は基本的に USB からの給電でも動くようですが、USB ハブの先につながっていたりすると、ARM core の負荷がかかったときなどに電源が落ちることがあるようです (僕の環境では起きるのですが、大丈夫な方もいらっしゃるようです)。5V の AC アダプタを用意することをおすすめします。同じ Digilent の Atlys ボードについていたもの (5V 4A) をそのまま使っています。

Micro SD カードを ZYBO の Micro SD スロットに挿し、JP5 のジャンパが “SD” の位置になっていることを確認したら、シリアルコンソールのホストになる PC に USB ケーブルをつないで、ボードの電源を入れましょう。シリアルポート (/dev/cuaU1 あるいは /dev/ttyUSB1 あたり) に 115200bps でつなげば、u-boot → ubldr → FreeBSD kernel の順番に起動し、パスワードなしの root アカウントでログインできると思います。

SD カードイメージに含まれている UFS パーティション (/dev/mmcsd0s2a) は、初回の起動時にカードのサイズいっぱいまで拡大されますので、それで不都合がある場合にはあらかじめ FreeBSD なマシンで Micro SD カード上の /etc/rc.conf を修正しておいてください。

ボードの電源を切る前に、shutdown -h now するのをお忘れなく。

ZYBO で FreeBSD が動くまで (1)

Digilent から出ている ZYBO という、Xilinx Zynq-7000 SoC を積んだボードがお手頃価格なので、研究室で何枚か買ってみました。Zynq は FPGA と ARM がひとつのチップに乗った SoC (system on a chip) で、ARM では Linux も動くし、FPGA 部分に載せた回路を周辺デバイスとして動かすこともできるので、けっこう面白いことができそう。ZYBO に載っているチップ (XC7Z010) の FPGA 部分は今となってはそれほど大きいサイズではないのだけれど…
で、僕は Linux のデバイスドライバとかよくわからない (一応書けるけども… なんか苦手) ので、FreeBSD 動くといいなー、と。
同様のボードでひと回り大きいチップを積んだ Zedboard というボードもあり、こちらは FreeBSD 10.1-RELEASE から (まだ Tier1 ではないものの) サポートされている ので、なんとかなるのでは、と思って試しはじめたものの、boot の仕組みから何から全然わからなくて、ちゃんと使えるようになるまで3日かかった。ということで、いちおう記録にまとめておこうと思います。FreeBSD のカーネル構築なんかしたことないよ、とか、FPGA 触ったことないよ、という人にはあまり参考にならないかもしれないけれど。
Step 0: 必要なもの
以下のものが必要です。今回は 1. の部分を書いていきます。Xilinx Vivado が動く開発環境が必要です。僕は Linux でやっていますが、Windows でも大丈夫かもしれません。
1. BOOT.bin 3点セット: Zynq SoCの構成情報, FSBL (First stage boot loader), u-boot
2. Device tree blob + uenv.txt
3. ubldr + FreeBSD
Step 1: SoC を構成する
Zynq は PS (Processing System) と PL (Programmable Logic) のふたつの部分に分かれており、AXI インタフェイスで接続されています。PL 部分はふつうの FPGA だと思えば OK です。
PS には ARM と、メモリコントローラや USB コントローラなどの周辺回路が入っているのだけれど、ただ Micro SD カードにブートローダーを書き込んだだけでは起動できません。Zynq に載っている PLL を使って、ARM コアや SDRAM をはじめとする各所のクロックをどうするか、とか、USB コントローラなどの各種周辺回路をどの MIO (Multiplexed I/O) ピンに引き出すか、といった設定が必要です。Zynq の場合、これらは PL 部分の構成情報といっしょに書き込む必要があります。
とりあえず FreeBSD を動かす、というだけの場合、FPGA の部分についてはあまり考えることはありませんし、HDL を書いて自分で回路を作る、という必要もありません。今回は手っ取り早く Digilent の ZYBO のページにある “ZYBO Base System Design” を使います。同じページにある “Embedded Linux hands-on tutorial for the ZYBO” にこれの説明があります。基本的には、Xilinx の設計ツールである Vivado で、次のような画面でブロックをつないでいくだけです。
block-design.png
Base System Design では HDMI を動かしたりするいろいろが含まれており、PS 以外にもいろいろなブロックが配置されていますが、FreeBSD をきどうするだけならこれらは必須ではありません。この場合のポイントは、Zynq7 Processing System の設定で、
– MIO Configuration: USB0 (MIO28-39), SD0 (MIO40-45), UART1 (MIO48-49), Bank 1: 1.8V
– Clock Configuration: Input Frequency = 50MHz
– DDR Configuration: Memory part = MT41K128M16 JT125
といったあたりです。Base System Design では このあたりは ZYBO のボード事情に合わせて正しく設定されています。Digilent tutorial の通りにして、Vivado で “Generate Bitstream” すると、Zynq の回路を構成するための .bit ファイルが生成されます。
Step 2: u-boot をコンパイルする
順序的には SoC が構成されたあと、FSBL が読み込まれて、そこから u-boot が起動するのですが、FSBL を使うときは Xilinx SDK が出てくるので、先に u-boot の話をしておきます。
u-boot は組み込みシステム向けの、OS 非依存なブートローダで、SD カードや tftp を使って起動することができます。Digilent が配布しているものを使いました (これもチュートリアルにある通りです)。設定とかはないので、make するだけです。
[code:plain]
% git clone -b master-next https://github.com/DigilentInc/u-boot-Digilent-Dev.git
% cd u-boot-Digilent-Dev
% make CROSS_COMPILE=arm-xilinx-linux-gnueabi- zynq_zybo_config
% make CROSS_COMPILE=arm-xilinx-linux-gnueabi-
[/code]
これで u-boot というファイルができるので、それを u-boot.elf に rename しておきます。
Step 3: First stage boot loader をコンパイルする
Zynq PS のアドレスマップなどはハードウェアの構成によって変わるので、Vivado で作ったハードウェアに合わせたブートローダを作る必要があります。これも、Digilent のチュートリアルにある通りの方法で作ることができます。
基本的には、
– Vivado で File → Export Hardware で SDK 用にハードウェアの構成情報を書き出す
– 続いて Vivado で File → Launch SDK を選んで Xilinx SDK を起動する
– File → New → Application Project でプロジェクトを作る際のテンプレートとして Zynq FSBL を選択
– fsbl_hooks.c を Base System Design の配布ファイルにあるものと差し替え (これやらないと MAC アドレスが毎回変わるのだとか…)
という流れです。Vivado 側で (PS から見た) ハードウェアの構成が変化した場合には作り直す必要がありますが、OS 非依存ですので Linux でも FreeBSD でも同じです。
SDK のフォルダの下の、FSBL/Debug/ (FSBL は Application project 名) に FSBL.elf ができるはずです。これが FSBL のバイナリです。
Step 4: BOOT.bin を作る
.bit ファイル → FSBL → u-boot の順で SD カードから読み込まれて Zynq が起動するわけですが、これらは Zynq Boot Image (BOOT.bin) としてひとつのファイルにまとめて SD カードに書き込みます。SDK のメニューバーで、Xilinx Tools → Create Zynq Boot Image を選ぶと作ることができます。
一番下の boot image partitions というところに、
– FSBL.elf
– (自分のFPGA構成情報).bit
– u-boot.elf
をこの順番に Add していけば OK です。FSBL.elf のところには [bootloader] という表示がつきますので、確認してください。
指定したディレクトリに BOOT.bin と、つかったファイルのリストの .bif ファイルが生成されれば、OS を起動する準備はおおむね準備完了です。
(続く、といいなあ)