Helioボードのリファレンスデザインで実装されているSystem IDを取得する実験
はじめに
Helioボードのリファレンスデザインには、System IDと呼ばれるIPコアがFPGAに実装されています。 これは、バスを通して32ビットのIDを返すという単純なIPコアです。
System IDはARMプロセッサからアクセスできるようにインターコネクトされています。 LinuxのユーザーランドからこのSystem IDを取得する方法がわかれば、Linux、ARMプロセッサー、FPGAのつながりをより深く理解できると考えました。 そこで今回は、簡単なCのプログラムを通して、FPGAに実装されているSystem IDの値を取得する実験をしてみます。
(手抜きな)クロス開発環境の構築
こちらを参考にします。 これは、本来、ボードでLinuxを動かすために必要なU-Boot、カーネル、ルートファイルシステムを構築するための手順です。 でも、カーネルをビルドするという点に着目すると、どこかにクロス開発環境が作られるはずです。 と、予想して試してみると、/opt/altera-linux/linaro/以下にクロス開発に必要なツールチェーンがインストールされました。 今回は高度なことはしないので、これをクロス開発に使うことにします。
Ubuntu 12.04を用意して以下を実行します。(VirtualBox上にVMとして構築しました)
$ sudo apt-get update $ sudo apt-get upgrade $ sudo apt-get install sed wget cvs subversion git-core coreutils unzip texi2html texinfo libsdl1.2-dev docbook-utils gawk python-pysqlite2 diffstat help2man make gcc build-essential g++ desktop-file-utils chrpath libgl1-mesa-dev libglu1-mesa-dev mercurial autoconf automake groff libtool xterm $ wget http://releases.rocketboards.org/release/2013.11/gsrd/src/linux-socfpga-gsrd-13.1-src.bsx $ chmod +x linux-socfpga-gsrd-13.1-src.bsx $ sudo ./linux-socfpga-gsrd-13.1-src.bsx
普通にgccが動きます。
$ /opt/altera-linux/linaro/gcc-linaro-arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin/arm-linux-gnueabihf-gcc --version arm-linux-gnueabihf-gcc (crosstool-NG linaro-1.13.1-4.7-2012.11-20121123 - Linaro GCC 2012.11) 4.7.3 20121106 (prerelease) Copyright (C) 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
System IDをどうやって取得するのか?
Qsysでインターコネクトを確認します。
h2f_lw_axi_masterからsysid_qsysにインターコネクトされています。この「h2f_lw」は「Lightweight HPS-to-FPGA interface」を表しているようで、h2f_lw_axi_masterなので、「Lightweight HPS-to-FPGA interface」のマスター側です。それに対してsysid_qsysは、Avalon Memory Mapped Slaveという説明からすると「Lightweight FPGA slave」にあたるようです。
Cyclone V Hard Processor System Technical Reference Manualの「Table 1-2: Common Address Space Regions」よると、Lightweight FPGA slavesのベースアドレスは0xFF200000となっています。 このベースアドレスは、プロセス内のアドレスではなく、物理アドレスです。
sysid_qsysのベースアドレスは0x00010000です。Lightweight FPGA slavesからの相対アドレスです。
結局、System IDは、0xFF200000 + 0x00010000の位置を先頭に4バイト分ということになります。
コード
以下のコードを作成しました。/dev/memで物理アドレスにアクセスします。mmap(2)でLightweight FPGA slavesのベースアドレスである0xFF200000をプロセス空間のポインタにマッピングします。そのポインタに対して、sysid_qsysのベースアドレスである0x00010000を足した位置から4バイト分をSystem IDとして読み取ります。
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { int fd; void* mapped_base; void* sysid; off_t LW_FPGA_SLAVES_BASE = 0xff200000; off_t SYSTEM_ID_BASE = 0x10000; int map_length = SYSTEM_ID_BASE + sizeof(int); // sizeof(int) = System ID length (4 byte) fd = open("/dev/mem", O_RDWR | O_SYNC); if (fd < 0) { exit(1); } mapped_base = mmap(NULL, map_length, PROT_READ, MAP_SHARED, fd, LW_FPGA_SLAVES_BASE); if (mapped_base == MAP_FAILED) { close(fd); } sysid = (unsigned char*)(mapped_base + SYSTEM_ID_BASE); printf("System ID: 0x%x\n", *(int*)(sysid)); munmap(mapped_base, map_length); close(fd); return 0; }
ビルド&実行
予めGolden Hardware Reference DesignをFPGAに書き込んでおきます。
ビルドして、Helioボードに実行ファイルを転送します。
$ /opt/altera-linux/linaro/gcc-linaro-arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin/arm-linux-gnueabihf-gcc sysid.c -o sysid $ scp sysid root@helio:
Helioボードで実行します。取得したSystem IDはQsysのSystem IDと一致しているので、正しく取得できています。
root@socfpga:~# ./sysid System ID: 0xacd51402
参考情報
今回の実験では、以下を参考にしました。
- Exploring the Arrow SoCKit Part III - Controlling FPGA from Software
- Tutorial:Getting started with FPGA-SoC and Linux Yocto on Terasic DE1-SoC board
おわりに
簡単な実験でしたが、ユーザーランドからFPGA側のデバイスにアクセスするコツがわかってきました。