Kintex-7にMicroblazeを載せる のバックアップ差分(No.7)
更新- バックアップ一覧
- 現在との差分 を表示
- ソース を表示
- バックアップ を表示
- 電気回路/HDL/Kintex-7にMicroblazeを載せる へ行く。
- 追加された行はこの色です。
- 削除された行はこの色です。
[[公開メモ]]
* 概要 [#kb3d846d]
WebPack 版の Vivado を使って Kintex-7 に MicroBlaze を載せ、UART 経由で PC と通信したい。
最近は無償の WebPack 版でも MicroBlaze IP を使えるようになっているのだけれど、
実はソフト開発に使う SDK は WebPack 版では MicroBlaze をサポートしないことを後から知った。
以下の手順で自ら MicroBlaze 用のコンパイラを用意すれば、
ちょっと面倒ながらも MicroBlaze を使ったベアメタルシステムの開発が可能なことが分かったので
まとめておく。
#contents
* 設計方針 [#h7b56e86]
FPGA ボードは以下を装備しているものとする。
- Kintex-7 FPGA
- LED が2つ
- スイッチが2つ
- USB-Serial 変換モジュール
MicroBlaze のプログラムから
自由に LED を光らせたり、スイッチの状態を読んだり、
USB 経由でホスト PC と通信をしたり、
を可能にしたい。
OS を走らせるようなたいそうなことを考えているわけではなく、
あくまでベアメタルのマイクロコントローラ的な使い方を想定している。
以下の方法でOSを走らせるのはたぶんかなり大変だと思われる。
* Vivado での作業 [#cdb702d3]
** プロジェクトの作成 [#r75c892d]
&ref(new-project.png,,50%); [File]-[Project]-[New]
&ref(project-name.png,,50%); 適当に名前を付ける
&ref(project-type.png,,50%); RTL プロジェクトを選ぶ
&ref(project-add-source.png,,50%); Block Design をトップにするのでここでは何もしない
&ref(project-add-xdc.png,,50%); 制約ファイルを1つ作っておく
&ref(project-select-kintex.png,,50%); 対象とする FPGA を選択する
あ、本当は xc7k160tfbg484-1 を選んだのにキャプチャした図は違うのを選んでるときのものだった。。。
&ref(project-finish.png,,50%); 以上でプロジェクト作成できた
** ブロック図の作成 [#gde59039]
こちらが完成形:
&ref(block-diagram-final.png,,33%);
- 入力端子として
-- クロック(差動入力)
-- リセット(負論理)
-- スイッチ2つ
-- UART-RX (USB-Serial 変換器の TX 端子と繋ぐ)
- 出力端子として
-- LED 2つ
-- UART-TX (USB-Serial 変換器の RX 端子と繋ぐ)
を持っており、それらが適切に IP に繋がっている。
以下が手順:
&ref(create-block-design.png,,50%); Block Design を新規作成
&ref(block-design-name.png,,50%); プロジェクトに1つしか作らないなら名前は適当でも
&ref(add-microblaze.png,,50%); Add IP ボタンから MicroBlaze を追加する
&ref(add-uart.png,,50%); 同様にシリアル通信用の UART モジュール を追加
&ref(add-gpio.png,,50%); 同様に LED やスイッチの制御のための GPIO モジュール を追加
&ref(regenerate-layout.png,,50%); Regenerate Layout ボタンで配置を調整
上部の Run Block Automation を押し、MicroBlaze についていろいろ設定する
&ref(block-automation-microblaze.png,,50%);
OK すると以下が自動的に追加される。
- クロックジェネレータ (Clocking Wizard)
- リセットコントローラ (Processor System Reset)
- ローカルメモリ (local memory)
- AXI ハブ (AXI Interconnect)
- 割り込みコントローラ (AXI Interrupt Controller)
&ref(block-automation-result.png,,50%);
Clocking Wizard をダブルクリックして
&ref(adjust-clocking-wizard.png,,50%); 入力周波数を 200MHz に変更
&ref(adjust-clocking-wizard2.png,,50%); リセットを反転入力とする
GPIO をダブルクリックして
&ref(adjust-gpio.png,,50%); 下位2ピンを出力にし、割り込みを有効にする
&ref(add-slice.png,,50%); Slice を追加しダブルクリック
&ref(adjust-slice.png,,50%); From を 1 にする
&ref(add-concat.png,,50%); Concat を追加しダブルクリック
&ref(adjust-concat.png,,50%); 28bit, 2bit, 2bit のポートを用意する
&ref(add-const.png,,50%); Const を追加しダブルクリック
&ref(adjust-const.png,,50%); 幅を 28bit, 値をゼロに設定
GPIO モジュールの GPIO バスをクリックして開き、slice, concat, const と結ぶ。~
また、Slice の出力、Concat の2本の入力について、右クリックから Make External して外部端子を出す。
&ref(gpio-connection.png,,50%);
&ref(interrupt-connection.png,,50%); UART, GPIO からの割り込み線を INTC へ繋がる Concat へ接続
&ref(uart-make-external.png,,50%); UART の UART 端子を右クリックして Make External
&ref(clock-make-external.png,,50%); Clocking Wizard の入力端子を Make External
ext_reset_in にも繋ぐ
左上の Run Connection Automation をクリック
&ref(connection-automation.png,,50%);
これで UART と GPIO が AXI ハブに繋がる。
Regenerate Layout して完成。
&ref(block-diagram-final.png,,33%);
** アドレスを確認 [#ee3ee978]
Diagram のとなりのタブに Address Editor がある。
ここで、それぞれの IP のベースアドレスを確認できる。~
必要に応じて変更することもできる。
&ref(address-editor.png,,50%);
** ブロック図から HDL を生成する [#c14fab92]
上図の左下で Generate Block Design を押すと以下のダイアログが現れる。
&ref(generate-block-design.png,,50%); Global を選ぶ
design_1 上で右クリックして Create HDL Wrapper を選択。
&ref(create-hdl-wrapper.png,,50%);
扱いは Vivado に任せる。
&ref(create-hdl-wrapper2.png,,50%);
design_1_wrapper.v が自動生成され、以降、必要に応じて自動更新される。
&ref(generated-wrapper.png,,50%);
** Implement してみる [#oca1cdc7]
この時点で Implement が可能になっている。
&ref(implementation-success.png,,50%);
まだ xdc ファイルには何の制約も追加していないのに「タイミング制約が満たされている」というような表示があるのは、Clocking Wizard に設定した入力周波数 200MHz で全体に対してクロック周波数制約がかかっているため。
[Open Implemented Design]-[Report Timing Summary] すると、
&ref(report-timing-summary.png,,50%);
&ref(implementation-timing-result.png,,50%);
Setup, Hold, Pulse Width とも Slack (余裕) の値は正になっていて、タイミング制約を満たしていることを確認できる。そして Clock Summary で各クロックに正しくタイミング制約がかかっていることを確認できる。
&ref(clock-summary.png,,50%);
注意が必要なのは、[Open Synthesized Design] から [Report Timing Summary] を見ると、
&ref(synthesis-timing-result.png,,50%);
のように、Hold の Slack が負になっていて、タイミング制約を満たしていないように見えることだ。
Hold の Slack が負というのはあるゲートから次のゲートへ信号が「早く到達しすぎている」((厳密には後段のゲートへクロックよりも次のデータが早く到達してしまっている))ということで、よほどクロックラインのスキューが大きいような場合でない限り起きえない。Implement 前の情報ではゲート間の遅延を正しく見積もれず、そのために負になっているということ、なのかな?
ここで見た通り Synthesis で Hold に Negative Slack が出ても、
同じ回路で Implementation では問題がなくなる場合があるようなので、
Synthesis 時点の少々の Negative Slack で悩まず Implementation を試すべきだ。
** 制約を与える [#w8e9114b]
module design_1_wrapper のインタフェースを見ると、
LANG:verilog
input CLK_IN1_D_0_clk_n; // オンボードクロックからの差動負入力
input CLK_IN1_D_0_clk_p; // オンボードクロックからの差動正入力
output [1:0]Dout_0; // LED0, LED1 への出力
input [1:0]In1_0; // SW0, SW1 からの入力
input UART_0_rxd; // USB-Serial 変換器の TX からの入力
output UART_0_txd; // USB-Serial 変換器の RX への出力
input resetn_0; // オンボードのリセットスイッチからの負論理入力
となっている。
そこで、以下のように制約ファイルを与えた。
# 入出力ピン
set_property PACKAGE_PIN V4 [get_ports CLK_IN1_D_0_clk_p]
set_property IOSTANDARD LVDS [get_ports CLK_IN1_D_0_clk_p]
set_property PACKAGE_PIN W4 [get_ports CLK_IN1_D_0_clk_n]
set_property IOSTANDARD LVDS [get_ports CLK_IN1_D_0_clk_n]
set_property PACKAGE_PIN R19 [get_ports Dout_0[0]]
set_property IOSTANDARD LVCMOS33 [get_ports Dout_0[0]]
set_property PACKAGE_PIN R19 [get_ports Dout_0[1]]
set_property IOSTANDARD LVCMOS33 [get_ports Dout_0[1]]
set_property PACKAGE_PIN T20 [get_ports In_1[0]]
set_property IOSTANDARD LVCMOS33 [get_ports In_1[0]]
set_property PACKAGE_PIN A21 [get_ports In_1[1]]
set_property IOSTANDARD LVCMOS33 [get_ports In_1[1]]
set_property PACKAGE_PIN K17 [get_ports resetn_0]
set_property IOSTANDARD LVCMOS33 [get_ports resetn_0]
set_property PACKAGE_PIN AA19 [get_ports UART_0_txd]
set_property IOSTANDARD LVCMOS33 [get_ports UART_0_txd]
set_property SLEW SLOW [get_ports UART_0_txd]
set_property PACKAGE_PIN W22 [get_ports UART_0_rxd]
set_property IOSTANDARD LVCMOS33 [get_ports UART_0_rxd]
set_property SLEW SLOW [get_ports UART_0_rxd]
# 電源に固定されているため使ってはいけないピン
set_property PROHIBIT true [get_sites Y11]
set_property PROHIBIT true [get_sites Y12]
# コンフィギュレーションブロックの設定
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property CFGBVS VCCO [current_design]
## 以下は FPGA のプログラムを短時間で行えるようにするおまじない
# 周波数を 50MHz に設定
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]
# 圧縮を有効化
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
このうち「FPGA のプログラムを短時間で行えるようにするおまじない」はかなり重要で、
これを書いておくのとおかないのとでプログラム時間がもの凄く違う。
** Bit Stream を生成する [#m9a1dc63]
launch_runs impl_1 -to_step write_bitstream -jobs 2
[Sat Sep 1 20:36:10 2018] Launched synth_1...
Run output will be captured here: C:/Users/osamu/MicroBlazeHello/MicroBlazeHello.runs/synth_1/runme.log
[Sat Sep 1 20:36:10 2018] Launched impl_1...
Run output will be captured here: C:/Users/osamu/MicroBlazeHello/MicroBlazeHello.runs/impl_1/runme.log
close_design; open_run impl_1
INFO: [Netlist 29-17] Analyzing 305 Unisim elements for replacement
INFO: [Netlist 29-28] Unisim Transformation completed in 0 CPU seconds
INFO: [Project 1-479] Netlist was created with Vivado 2018.2
INFO: [Device 21-403] Loading part xc7k160tfbg484-1
INFO: [Project 1-570] Preparing netlist for logic optimization
INFO: [Timing 38-478] Restoring timing data from binary archive.
INFO: [Timing 38-479] Binary timing data restore complete.
INFO: [Project 1-856] Restoring constraints from binary archive.
INFO: [Project 1-853] Binary constraint restore complete.
Reading XDEF placement.
Reading placer database...
Reading XDEF routing.
Read XDEF File: Time (s): cpu = 00:00:00 ; elapsed = 00:00:00.417 . Memory (MB): peak = 2962.469 ; gain = 0.000
Restored from archive | CPU: 0.000000 secs | Memory: 0.000000 MB |
Finished XDEF File Restore: Time (s): cpu = 00:00:00 ; elapsed = 00:00:00.418 . Memory (MB): peak = 2962.469 ; gain = 0.000
Generating merged BMM file for the design top 'design_1_wrapper'...
INFO: [Memdata 28-144] Successfully populated the BRAM INIT strings from the following elf files: c:/Users/osamu/MicroBlazeHello/MicroBlazeHello.srcs/sources_1/bd/design_1/ip/design_1_microblaze_0_1/data/mb_bootloop_le.elf
INFO: [Project 1-111] Unisim Transformation Summary:
A total of 223 instances were transformed.
LUT6_2 => LUT6_2 (LUT5, LUT6): 127 instances
RAM16X1D => RAM32X1D (RAMD32, RAMD32): 32 instances
RAM32X1D => RAM32X1D (RAMD32, RAMD32): 64 instances
open_run: Time (s): cpu = 00:00:29 ; elapsed = 00:00:28 . Memory (MB): peak = 3021.410 ; gain = 673.984
open_hw
reset_run impl_1 -prev_step
launch_runs impl_1 -to_step write_bitstream -jobs 2
[Sat Sep 1 21:02:00 2018] Launched impl_1...
Run output will be captured here: C:/Users/osamu/MicroBlazeHello/MicroBlazeHello.runs/impl_1/runme.log
となってうまく行った。
ここまでで回路は完成だ。
INFO: [Memdata 28-144] Successfully populated the BRAM INIT strings from the following elf files: c:/Users/osamu/MicroBlazeHello/MicroBlazeHello.srcs/sources_1/bd/design_1/ip/design_1_microblaze_0_1/data/mb_bootloop_le.elf
の行から分かるとおり、microblaze_0_1 に結びつけられたローカルメモリには bootloop という「何もしないプログラム」が書き込まれている。
以下はここに入れるべきソフトウェアプログラムを開発する話になる。
** ハードウェアを SDK にエクスポート [#ua700724]
Xilinx SDK を使ってソフトを開発する場合、ハードウェアの情報を SDK に伝えるために、
[File]-[Export]-[Export Hardware] を使って情報をエクスポートする。
&ref(export-hardware.png,,50%);
&ref(include-bitstream.png,,50%); include bitstream にチェックを入れる
以下に見るように、MicroBlaze 用のソフトウェアは WebPack 版の Xilinx SDK では開発できないので、
実はこの作業は無意味であった。
EDK を持っていて、SDK でソフト開発ができる場合にはこの手順で正しいはず。
** SDK でエラーが出る [#d7d50135]
* SDK でエラーが出る [#cfd860ef]
SDK でプロジェクトを作成しようとすると、bsp 生成部分で "Couldn't figure out compiler's library directory" というエラーが出てしまう。
ERROR : (XSDB Server)ERROR: [Hsi 55-1545] Problem running tcl command ::sw_cpu_v2_7::generate : Couldn't figure out compiler's library directory
while executing "error "Couldn't figure out compiler's library directory" "" "hsi_error""
(procedure "::sw_cpu_v2_7::generate" line 139) invoked from within "::sw_cpu_v2_7::generate microblaze_0"
ERROR : (XSDB Server)si 55-1442] Error(s) while running TCL procedure generate()
ERROR : (XSDB Server)ERROR: [Hsi 55-1450] Error: run
ERROR : (XSDB Server)ning generate_bsp.
ERROR : Error generating bsp sources: Failed in generating sources
SDK を使って MicroBlaze 開発をするには EDK のライセンスが必要ということらしい。
* クロスコンパイラの準備 [#fee22d62]
そこで SDK を使わずにソフトウェアを開発する。
実は MicroBlaze 用のコードを出力する gcc を無償で利用することができるのだ。
ただし現状では、自分でビルドしなければならないみたい?
** Windows 上の Vagrant で Ubuntu を立ち上げる [#i2f75e69]
gcc のビルドには Linux 環境が必要なので、お手軽な環境として
Windows10 に VirtualBox を入れ、Vagrant から利用する。
ここではすでに VirtualBox と Vagrant は導入済みとして、
以下の手順で進める。
>ただし、ビルドする開発ツール自体はローカルフォルダ
(./work) にインストールすることになるため、必ずしもこれだけのために
仮想マシンが必要ではない。いくつかのパッケージを入れることをいとわなければ、
既存の Ubuntu 環境で作業しても問題ないはず。
https://qiita.com/watame/items/1c17aaf266f14abef13f を見ながら
LANG:console
$ cd \Users\osamu\Vagrant
$ mkdir microblaze-gcc
$ cd microblaze-gcc
$ vagrant init bento/ubuntu-16.04
$ vagrant up --provider virtualbox
$ vagrant ssh
これでコンソールが立ち上がる。
まずは日本語キーボードに変更し( https://blog.amedama.jp/entry/2017/03/10/210552 )、~
タイムゾーンを日本にする( https://qiita.com/koara-local/items/32b004c0bf80fd70777c )。
LANG:console
$ sudo dpkg-reconfigure keyboard-configuration
> Generic 105-key (Intel) PC
> Japanese
> Japanese
> The default for the keyboard layout
> No compose key
$ sudo timedatectl set-timezone Asia/Tokyo
** 共有フォルダの設定 [#u0a2c50b]
一旦 exit で抜けて、
LANG:console
$ vagrant halt
で仮想マシンも止める。
\Users\osamu\Vagrant\microblaze-gcc\Vagrantfile に
config.vm.synced_folder "./shared", "/home/vagrant/shared"
という行を追加した。
これはホストマシンの
\Users\osamu\Vagrant\microblaze-gcc\shared
の内容を仮想マシンの
/home/vagrant/shared
に接続するおまじない。
** 必要なパッケージを追加する [#o29ee0bd]
もう一度、
LANG:console
$ vagrant up --provider virtualbox
$ vagrant ssh
としてシェルを立ち上げ、
LANG:console
$ sudo apt-get -y install build-essential m4 g++ texinfo
** 開発用ツールチェインのビルド [#a90659f6]
https://qiita.com/watame/items/1c17aaf266f14abef13f を参考にしつつ、
以下の内容を \Users\osamu\Vagrant\microblaze-gcc\shared\build-gcc.sh
として保存した。
LANG:sh
export MB_WORK=~/work
export MB_LINUX_DEP=${MB_WORK}/mb-linux-dep
export MB_LINUX_PREFIX=${MB_WORK}/mb-elf-toolchain-linux
export MB_BUILD=x86_64-linux-gnu
export MB_TARGET=microblaze-elf
export MB_PREFIX=mb-
export PATH=${MB_LINUX_PREFIX}/bin:$PATH
# prepare --------------------------------------------------
mkdir -p ${MB_WORK}/build-linux
mkdir -p ${MB_WORK}/source
# download sources...
cd ${MB_WORK}/source
wget http://ftp.gnu.org/gnu/gmp/gmp-6.1.1.tar.xz
wget http://ftp.gnu.org/gnu/mpfr/mpfr-3.1.4.tar.xz
wget http://ftp.gnu.org/gnu/mpc/mpc-1.0.3.tar.gz
wget http://isl.gforge.inria.fr/isl-0.17.tar.xz
wget http://ftp.gnu.org/gnu/binutils/binutils-2.26.1.tar.bz2
wget http://ftp.gnu.org/gnu/gcc/gcc-5.4.0/gcc-5.4.0.tar.bz2
wget ftp://sources.redhat.com/pub/newlib/newlib-2.4.0.20160527.tar.gz
tar xzf gmp-6.1.1.tar.xz
tar xzf mpfr-3.1.4.tar.xz
tar xzf mpc-1.0.3.tar.gz
tar xzf isl-0.17.tar.xz
tar xzf binutils-2.26.1.tar.bz2
tar xzf gcc-5.4.0.tar.bz2
tar xzf newlib-2.4.0.20160527.tar.gz
# linux ----------------------------------------------------
# gmp
cd ${MB_WORK}/build-linux
mkdir build-gmp
cd build-gmp
../../source/gmp-6.1.1/configure --prefix=${MB_LINUX_DEP}
make && make install && make check
# mpfr
cd ${MB_WORK}/build-linux
mkdir build-mpfr
cd build-mpfr
../../source/mpfr-3.1.4/configure \
--enable-static --disable-shared \
--with-gmp=${MB_LINUX_DEP} \
--prefix=${MB_LINUX_DEP}
make && make install
# mpc
cd ${MB_WORK}/build-linux
mkdir build-mpc
cd build-mpc
../../source/mpc-1.0.3/configure \
--enable-static --disable-shared \
--with-gmp=${MB_LINUX_DEP} \
--with-mpfr=${MB_LINUX_DEP} \
--prefix=${MB_LINUX_DEP}
make && make install
# isl
cd ${MB_WORK}/build-linux
mkdir build-isl
cd build-isl
../../source/isl-0.17/configure \
--without-piplib \
--enable-static --disable-shared \
--with-gmp-prefix=${MB_LINUX_DEP} \
--prefix=${MB_LINUX_DEP}
make && make install
# binutils
cd ${MB_WORK}/build-linux
mkdir build-binutils
cd build-binutils
../../source/binutils-2.26.1/configure --target=${MB_TARGET} \
--prefix=${MB_LINUX_PREFIX} \
--program-prefix=${MB_PREFIX}
make && make install
# bootstrap gcc
cd ${MB_WORK}/build-linux
mkdir build-gcc1
cd build-gcc1
../../source/gcc-5.4.0/configure \
--target=${MB_TARGET} \
--program-prefix=${MB_PREFIX} \
--with-gnu-as --with-gnu-ld \
--enable-static --disable-shared \
--with-gmp=${MB_LINUX_DEP} \
--with-mpfr=${MB_LINUX_DEP} \
--with-mpc=${MB_LINUX_DEP} \
--with-isl=${MB_LINUX_DEP} \
--with-newlib \
--without-headers \
--enable-languages="c,c++" --enable-interwork --enable-multilib \
--disable-decimal-float --disable-libffi \
--disable-libgomp --disable-libmudflap --disable-libquadmath --disable-libssp --disable-libstdcxx-pch \
--disable-nls --disable-shared --disable-threads --disable-tls \
--prefix=${MB_LINUX_PREFIX} \
--with-system-zlib
make -j2 all-gcc
make install-gcc
# because newlib not support program-prefix, we need to create symbol link
cd ${MB_LINUX_PREFIX}/bin
ln -s mb-gcc mb-cc
ln -s mb-ar microblaze-elf-ar
ln -s mb-as microblaze-elf-as
ln -s mb-c++ microblaze-elf-c++
ln -s mb-gcc microblaze-elf-gcc
ln -s mb-gcc microblaze-elf-cc
ln -s mb-gcc-ar microblaze-elf-gcc-ar
ln -s mb-gcc-nm microblaze-elf-gcc-nm
ln -s mb-gcc-ranlib microblaze-elf-gcc-ranlib
ln -s mb-gcov microblaze-elf-gcov
ln -s mb-gcov-tool microblaze-elf-gcov-tool
ln -s mb-ld microblaze-elf-ld
ln -s mb-ld microblaze-elf-ld.bfd
ln -s mb-nm microblaze-elf-nm
ln -s mb-objcopy microblaze-elf-objcopy
ln -s mb-objdump microblaze-elf-objdump
ln -s mb-ranlib microblaze-elf-ranlib
ln -s mb-readelf microblaze-elf-readelf
ln -s mb-size microblaze-elf-size
ln -s mb-strings microblaze-elf-strings
ln -s mb-strip microblaze-elf-strip
# newlib
cd ${MB_WORK}/build-linux
mkdir build-newlib
cd build-newlib
../../source/newlib-2.4.0.20160527/configure \
--target=${MB_TARGET} \
--prefix=${MB_LINUX_PREFIX}
make && make install
# gcc
cd ${MB_WORK}/build-linux
mkdir build-gcc2
cd build-gcc2
../../source/gcc-5.4.0/configure \
--target=${MB_TARGET} \
--program-prefix=${MB_PREFIX} \
--with-gnu-as --with-gnu-ld \
--enable-static --disable-shared \
--with-gmp=${MB_LINUX_DEP} \
--with-mpfr=${MB_LINUX_DEP} \
--with-mpc=${MB_LINUX_DEP} \
--with-isl=${MB_LINUX_DEP} \
--with-newlib \
--enable-languages="c,c++" --enable-interwork --enable-multilib \
--disable-decimal-float --disable-libffi \
--disable-libgomp --disable-libmudflap --disable-libquadmath --disable-libssp --disable-libstdcxx-pch \
--disable-nls --disable-shared --disable-threads --disable-tls \
--prefix=${MB_LINUX_PREFIX} \
--with-system-zlib
make -j 2
make install
cd ${MB_LINUX_PREFIX}
リンク先のままだと make -j4 all-gcc で、
checking dynamic linker characteristics... configure: error: Link tests are not allowed after GCC_NO_EXECUTABLES.
Makefile:8349: recipe for target 'configure-zlib' failed
make: *** [configure-zlib] Error 1
make: *** Waiting for unfinished jobs....
というエラーが出たので、https://stackoverflow.com/questions/29481325/arm-gcc-build-error-under-fedora-21 に従って configure に --with-system-zlib を追加してある。
あとは、
LANG:console
$ cd
$ source shared/build-gcc.sh 2>1 | tee shared/build-gcc.log
とすれば、かな~り時間はかかるもののビルドに成功するはず。
LANG:console
$ cd
$ ls work/mb-elf-toolchain-linux/bin
mb-addr2line mb-gcc-ar mb-ranlib microblaze-elf-gcc-5.4.0 microblaze-elf-objdump
mb-ar mb-gcc-nm mb-readelf microblaze-elf-gcc-ar microblaze-elf-ranlib
mb-as mb-gcc-ranlib mb-size microblaze-elf-gcc-nm microblaze-elf-readelf
mb-c++ mb-gcov mb-strings microblaze-elf-gcc-ranlib microblaze-elf-size
mb-cc mb-gcov-tool mb-strip microblaze-elf-gcov microblaze-elf-strings
mb-c++filt mb-ld microblaze-elf-ar microblaze-elf-gcov-tool microblaze-elf-strip
mb-cpp mb-ld.bfd microblaze-elf-as microblaze-elf-ld
mb-elfedit mb-nm microblaze-elf-c++ microblaze-elf-ld.bfd
mb-g++ mb-objcopy microblaze-elf-cc microblaze-elf-nm
mb-gcc mb-objdump microblaze-elf-gcc microblaze-elf-objcopy
$ microblaze-elf-gcc --version
microblaze-elf-gcc (GCC) 5.4.0
Copyright (C) 2015 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.
** パスに追加 [#v74c676c]
LANG:console
$ cat >> ~/.bashrc
PATH=/home/vagrant/work/mb-elf-toolchain-linux/bin/:$PATH
^D
** 試しにコンパイルしてみる [#wc9a93b0]
LANG:console
$ cd shared
$ mkdir hello
$ cd hello
$ cat > hello.c
int main()
{
return 0;
}
$ mb-gcc -c hello.c
$ ls
hello.c hello.o
$ mb-gcc hello.c -o hello.elf
/home/vagrant/work/mb-elf-toolchain-linux/lib/gcc/microblaze-elf/5.4.0/../../../../microblaze-elf/bin/ld: cannot find -lxil
collect2: error: ld returned 1 exit status
コンパイルはできるけれど、リンクで libxil というライブラリが見つからないといって失敗する。
標準ライブラリなしでリンクするには -nostdlib を付けると良いらしいのだけれど、
LANG:console
$ mb-gcc hello.c -nostdlib -o hello.elf
/home/vagrant/work/mb-elf-toolchain-linux/lib/gcc/microblaze-elf/5.4.0/../../../../microblaze-elf/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000000050
今度は _start が見つからないと言われてしまう。
[[Wikipedia:フリースタンディング環境]] などで解説されているとおり、-nostdlib を付けた場合には始めから main ではなく _start をエントリポイントとすれば良いらしい。
LANG:console
$ cat > hello.c
void _start()
{
}
$ mb-gcc hello.c -nostdlib -o hello.elf
$ ls
hello.c hello.elf
めでたくコンパイルが通る。
** コンパイルオプション [#fa20e3ea]
MicroBlaze を AXI バスと共に使う場合には
https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_1/ug984-vivado-microblaze-ref.pdf#page=11
にあるように Little Endian になるので、コンパイル時にもそうなるようにオプションを付ける必要がある。
LANG:console
$ mb-gcc -mlittle-endian -O2 hello.c -nostdlib -o hello.elf
* UART ライブラリを作成 [#lf3f59f8]
address.h
LANG:c
#define UART_BASE 0x40600000
#define GPIO 0x40000000
#define INTC_BASE 0x41200000
uart.h
LANG:c
#ifndef UART_LIB_INCLUDED
#define UART_LIB_INCLUDED
extern void uart_init(int enable_interrupt);
extern int uart_status();
extern int uart_readable();
extern int uart_readc();
extern int uart_writable();
extern void uart_writec(char c);
extern void uart_puts(const char *str);
extern void uart_write_hex1(int n);
extern void uart_write_hex2(int n);
extern void uart_write_hex4(int n);
extern void uart_write_hex8(int n);
#endif
uart.c
LANG:c
#include "address.h"
#define UART_RX (UART_BASE+0)
#define UART_TX (UART_BASE+4)
#define UART_STATUS (UART_BASE+8)
#define UART_CTRL (UART_BASE+12)
//////////////////////////////////////////////////
static void reg_set(int addr, int value)
{
*(volatile int *)(addr) = value;
}
static int reg_get(int addr)
{
return *(volatile int *)addr;
}
//////////////////////////////////////////////////
void uart_init(int enable_interrupt)
{
reg_set(UART_CTRL, 3 + ((!!enable_interrupt) << 4));
}
int uart_status()
{
return reg_get(UART_STATUS);
}
int uart_readable()
{
return uart_status() & 1;
}
int uart_readc()
{
while ( !uart_readable() ) // Empty
;
return reg_get(UART_RX) & 0xff;
}
int uart_writable()
{
return 0 == ( uart_status() & 8 );
}
void uart_writec(char c)
{
while ( !uart_writable() ) // Full
;
reg_set(UART_TX, c & 0xff);
}
void uart_puts(const char *str)
{
while (*str) {
uart_writec(*str);
str++;
}
}
void uart_write_hex1(int n)
{
n = n & 0xf;
uart_writec('0' + n + (n >= 10 ? 'a'-'0'-10 : 0));
}
void uart_write_hex2(int n)
{
uart_write_hex1(n >> 4);
uart_write_hex1(n);
}
void uart_write_hex4(int n)
{
uart_write_hex2(n >> 8);
uart_write_hex2(n);
}
void uart_write_hex8(int n)
{
uart_write_hex4(n >> 8);
uart_write_hex4(n);
}
* hello.c [#neaedd80]
hello.c
LANG:c
#include "uart.h"
void _start()
{
uart_puts("Hello World!!\n");
while(1) {
char c = uart_readc();
uart_puts("detected key '");
uart_writec(c);
uart_puts("'\n");
}
}
* コンパイル [#a302f96e]
LANG:console
$ mb-gcc -mlittle-endian -O2 hello.c uart.c -nostdlib -o hello.elf
* elf ファイルを bit ファイルへ埋め込む [#p094f6a5]
updatemem と言うコマンドを使えばいいらしい。
LANG:tcl
exec updatemem -force \
-meminfo C:/Users/osamu/MicroBlazeHello/MicroBlazeHello.runs/impl_1/design_1_wrapper.mmi \
-bit C:/Users/osamu/MicroBlazeHello/MicroBlazeHello.runs/impl_1/design_1_wrapper.bit \
-data C:/Users/osamu/Vagrant/microblaze-gcc/data/hello/hello.elf \
-proc design_1_i/microblaze_0 \
-out C:/Users/osamu/MicroBlazeHello/MicroBlazeHello.runs/impl_1/download.bit
これで、design_1_wrapper.bit の中の design_1_i/microblaze_0 のメモリ内容を
hello.elf で置き換えたものを download.bit として保存できる。
* FPGA をプログラムする [#p818f079]
あとは以下のようにして download.bit を FPGA へダウンロードできる。
LANG:tcl
set_property PROBES.FILE {} [get_hw_devices xc7k160t_0]
set_property FULL_PROBES.FILE {} [get_hw_devices xc7k160t_0]
set_property PROGRAM.FILE {C:/Users/osamu/MicroBlazeHello/MicroBlazeHello.runs/impl_1/download.bit} [get_hw_devices xc7k160t_0]
program_hw_devices [get_hw_devices xc7k160t_0]
* ツールボタンに割り当てる [#p8d08f3a]
コンパイル → bit 置き換え → FPGAプログラム
を何度も繰り返すのはかなり面倒なので、「bit 置き換え → FPGAプログラム」をワンクリックで可能なツールボタンを作成する。
Vivado の [Tools]-[Custom Commands]-[Customize Commands...] に
上記のスクリプトを ; で区切りながら1行に繋げた手順を入れてボタンにしておく。
コンパイルしたらボタンを押すだけでプログラムができるようになる。
* フラッシュメモリに書き込むには [#wca2c2e3]
普通なら Generate Bitstream のオプションで同時に bin ファイルを作成するようにしておけば良いのだけれど、elf を書き込んだ bit をフラッシュメモリに焼くにはどうしたらいいものか???
http://www3.hdl.co.jp/spc/xcm/466-q20160229.html
の手順で mcs ファイルを作れば良いらしい。
LANG:tcl
write_cfgmem -format MCS -interface SPIx1 -size 64 \
-loadbit "up 0x0 C:/Users/osamu/MicroBlazeHello/MicroBlazeHello.runs/impl_1/download.bit" \
"C:/Users/osamu/MicroBlazeHello/MicroBlazeHello.runs/impl_1/download.mcs"
* スタートアップコードが足りないみたい??? [#o876ab36]
上記の手順で一見動いているように見えたのだけれど、動作が不安定だ。
実は上で不足していると怒られた libxil のソースコードは Xilinx SDK に付いているので、
C:\Xilinx\SDK\2018.2\data\embeddedsw\lib\bsp\standalone_v6_7
不足するヘッダーファイル等を補うことでこれをそのまま上記環境でコンパイルして使えるっぽい。
ただ、そうしたときに完動するコードが、上記のように完全にベアな状態で走らせたときにうまく動かないケースがあった。
ここに付いてきたコードをそのままコンパイルして使っていいものかどうか、ライセンス的にちょっと心配なので、必要そうなコードを吟味して、独自のスタートアップルーチンを作るのがいいのかもしれない???
* 質問・コメント [#x5586ece]
#article_kcaptcha
Counter: 17596 (from 2010/06/03),
today: 3,
yesterday: 0