Kyoto Maker

Software & Hardware Laboratory Found In Kyoto, 2015.

Helioボードのリファレンスデザインで実装されているSystem IDを取得する実験

はじめに

Helioボードのリファレンスデザインには、System IDと呼ばれるIPコアがFPGAに実装されています。 これは、バスを通して32ビットのIDを返すという単純なIPコアです。

f:id:fixme:20150113223230p:plain

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でインターコネクトを確認します。

f:id:fixme:20150113222951p:plain

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となっています。 このベースアドレスは、プロセス内のアドレスではなく、物理アドレスです。

f:id:fixme:20150113222925p:plain

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 DesignFPGAに書き込んでおきます。

ビルドして、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

f:id:fixme:20150113223230p:plain

参考情報

今回の実験では、以下を参考にしました。

おわりに

簡単な実験でしたが、ユーザーランドからFPGA側のデバイスにアクセスするコツがわかってきました。