MicroBoardのSPI ROMから
MicroBlazeのプログラムを
読んで起動する話
イーツリーズ/わさらぼ
三好 健文
やること
1) MicroBlaze大きなプログラムを実行したい
← BlockRAMにのらない/外部メモリで実行
2) プログラムは自動的に実行を開始したい
← ROMからプログラムを読んで実行したい
3) MicroBoardにはQSPI FlashROMが載ってる
4) Xilinx AR#55026にSPIからのブートローダが
5) MicroBoardでも試してみよう
手順概要
1) MicroBlazeシステムを構築
2) QSPIをシステムに追加
3) トップのHDLを作成.#HOLDの処置を追加
4) UCFを記述
5) ローダーとアプリケーションプログラムを用意
6) ローダーをBlockRAMに埋め込む
7) アプリケーションプログラムを分割
8) MCSファイルを作る
MicroBlazeシステムを構築/概要
● ISEからプロジェクトを作る
● BSBで基本システムを作成
– 入力クロック66.666667MHz
– CPU動作周波数66MHz
– 使用デバイスを追加
● DDR3(後でLPDDRに設定するけど)
● LED(GPIO出力)
● DIPスイッチ(GPIO入力)
● UART(ボーレート115200に)
● 細かなパラメタ調整
MicroBlazeシステムを構築(1)
ISEプロジェクトを作成
コンテクストメニューからNew Sourceを選択
New Sourceとして追加するのは
Embedded Processor
名前はお好みで
XPS起動直後にBSB Wizardを使うか?
と聞かれるので”YES”を選択
MicroBlazeシステムを構築(2)
PLBじゃなくてAXIを使う
(デフォルトのままいじらない)
周波数は66.666667MHz
リセットはActive HIGH
●
CPUの動作周波数は66MHz
●
周辺デバイスに下記を追加
●
MCB_DDR3
●
LED(GPIO, 4bit)
●
DIPスイッチ(GPIO, 4bit)
●
UART(115200, Interruptあり)
MicroBlazeシステムを構築(3)
● 入出力ポートの設定
– LEDとDIPスイッチが8bitなので4bit([0:3])に修正
– クロック入力は差動じゃないので削除して新規作成
BSBで4bitと指定したのに,
[0:7]になっていたので[0:3]に修正
差動クロックは削除
新たにクロック入力ピンを生成
clock_generator_0_CLKIN_pinになった
MicroBlazeシステムを構築(4)
● MIGでメモリの設定
– DDR3をLPDDRにする
– メモリはMT46H32M16XXXX-5を選択
– ほかはデフォルトでOK
MCB_DDR3を
ダブルクリックしてMIGを起動
LPDDRを選択
MT46H32M16XXXX-5を選択
MicroBlazeシステムを構築(5)
● メモリ用のクロックを200MHzに設定する
clock_generator_0をダブルクリック
メモリの動作周波数が600MHzになっている
200MHzに設定する
MicroBlazeシステムを構築(6)
● ブロックRAMのサイズを32KBにする
microblaze_0_d_bram_ctrlと
microblaze_0_i_bram_ctrlの
それぞれの設定ダイアログを開いて
LMB BRAM High Addressを
0x00007fffに設定
設定の確認は”Addresses”タブで
QSPI ROMをシステムに追加/概要
● IP CatalogでAXI Quad SPI Interfaceを選択
● FIFO Depthを16,SCK Ratioを2に設定
● microblaze_0(作ったCPU)にぶら下げる
● 外部クロックをCLKOUT2に設定
● 必要なポートを外部ピンに設定する
● ここまで完了したらNetlistを作る
QSPI ROMをシステムに追加(1)
AXI Quad SPI Interface
IPコアを選択
名前をQSPI_FLASHに決めた(何でもいい)
microblaze_0に接続(デフォルト) モジュール(QSPI_FLASH)が追加できた
FIFO Depth=16,
SCK Ratio=2に設定
QSPI ROMをシステムに追加(2)
● SPIクロックのソースをCLKOUT2に設定
● IOピンを外部に引き出す
“Ports”タブでポートの設定をする
- EXT_SPI_CLKにclock_generator_0のCLKOUT2を接続
- SCK, SS, IO0, IO1, SPISELを外部ポートに指定
終わったら,確認がてら
Netlistを作成しておく
トップのHDLを作成/概要
● ISEに戻ってトップモジュールのHDLを生成
● SSELは常に'1'にする
● #HOLD用の信号を追加.常に'1'を出力
作成した
Embedded Processorを選択して
Create top HDL Sourceをダブルクリック
トップモジュール(のVHDLコード)が
プロジェクトに追加された
トップのHDLを作成(1)
● SSELは常に'1'にする
– 外部ポートのQSPI_FLASH_SPISEL_pinを削除
– port map は QSPI_FLASH_SPISEL_pin => '1',
● #HOLD用の信号を追加.常に'1'を出力
– QSPI_FLASH_HOLD : out std_logic を追加
– QSPI_FLASH_HOLD <= '1'; とか
後述のbootloaderプログラムではSPIモードでROMにアクセスします
#HOLD (D3)を'1'にしていないと,データが読めません!!
UCFの記述
● いつも通り.メモリは書かなくていいから楽
NET RS232_Uart_1_sout LOC = T7 | IOSTANDARD = LVCMOS33;
NET RS232_Uart_1_sin LOC = R7 | IOSTANDARD = LVCMOS33;
NET RESET LOC = V4 | IOSTANDARD = LVCMOS33 | TIG | PULLDOWN;
NET LEDS_TRI_O<0> LOC = P4 | IOSTANDARD = LVCMOS18;
NET LEDS_TRI_O<1> LOC = L6 | IOSTANDARD = LVCMOS18;
NET LEDS_TRI_O<2> LOC = F5 | IOSTANDARD = LVCMOS18;
NET LEDS_TRI_O<3> LOC = C2 | IOSTANDARD = LVCMOS18;
NET DIP_Switches_TRI_I<0> LOC = B3 | IOSTANDARD = LVCMOS33;
NET DIP_Switches_TRI_I<1> LOC = A3 | IOSTANDARD = LVCMOS33;
NET DIP_Switches_TRI_I<2> LOC = B4 | IOSTANDARD = LVCMOS33;
NET DIP_Switches_TRI_I<3> LOC = A4 | IOSTANDARD = LVCMOS33;
NET clock_generator_0_CLKIN_pin LOC = K15 | IOSTANDARD = LVCMOS33;
NET QSPI_FLASH_SCK_pin LOC = R15 | IOSTANDARD = LVCMOS33;
NET QSPI_FLASH_SS_pin LOC = V3 | IOSTANDARD = LVCMOS33;
NET QSPI_FLASH_IO0_pin LOC = T13 | IOSTANDARD = LVCMOS33;
NET QSPI_FLASH_IO1_pin LOC = R13 | IOSTANDARD = LVCMOS33;
NET QSPI_FLASH_HOLD LOC = V14 | IOSTANDARD = LVCMOS33;
NET "clock_generator_0_CLKIN_pin" TNM_NET = clock_generator_0_CLKIN_pin;
TIMESPEC TS_clock_generator_0_CLKIN_pin = PERIOD clock_generator_0_CLKIN_pin 66666 kHz;
### Set Vccaux for S6LX9 MicroBoard to 3.3V ###
CONFIG VCCAUX = "3.3" ;
ローダーとアプリケーションを用意
● Xilinx #AR55026からいただいてくる
● このローダーはアプリケーションプログラムの
サイズを埋め込む必要があるので注意
– REST_SECTION_BYTE_NUM
● DDRメモリの名前が違うので修正
– xparameters.hを参照
– XPAR_DDR3_SDRAM_S_AXI_BASEADDR を
XPAR_MCB_DDR3_S0_AXI_BASEADDRに変更
● ローダーは全セクションをBRAMに割り当てる
– lscript.ldでタブから選べばいい
ブートローダーの中身
● SPIメモリにアクセスするための初期化
● SPIメモリからプログラムを読んでDDRメモリ
に書く
● 書き終わったら,DDRメモリの先頭(プログラ
ム開始アドレス)にジャンプする
ブートローダーの中身(抜粋)
...
/*
* Read the rest_section data from flash.
*/
for(i=0; i<(REST_SECTION_BYTE_NUM/16)+1; i++)
{
Status = SpiFlashRead(&Spi, (REST_SECTION_START_ADDR+16*i), 16, COMMAND_RANDOM_READ);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
for(k=0; k<16; k++)
*destination_location++ = ReadBuffer[k+4];
}
/*
* Read the vector_section data from flash.
*/
for(i=0; i<(VECTOR_SECTION_BYTE_NUM/16)+1; i++)
{
Status = SpiFlashRead(&Spi, (VECTOR_SECTION_START_ADDR+16*i), 16, COMMAND_RANDOM_READ);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
for(k=0; k<16; k++)
*reset_location++ = ReadBuffer[k+4];
}
xil_printf("user application load succeed!rn");
boot_app = (int (*) (void)) XPAR_DDR3_SDRAM_S_AXI_BASEADDR;
boot_app();
...
ローダーをBlockRAMに埋め込む
● data2memを実行すればよい
● SDKで作ったelfファイルをプロジェクトに登
録してGenerate Programming FileでOK
elfをプロジェクトに登録
Generate Programming Fileを実行
なお,初回登録時は”?”状態になるがelfを変更して
も状態は変更ず生成済状態のままなので注意!!
内部ではdata2memが実行される
bitファイルは上書きではなく別に生成される.注意!!
アプリケーションを分割/概要
● アプリケーションプログラムの空間はでかい
– ベクタ関連のセクション(0x00000000-0x0000004f)
– プログラムデータ(DDRのアドレス)
● そのままだと大量の無駄な領域が必要
● 分割して個別にバイナリイメージ化する
アプリケーションを分割(1)
C:WORKimages>mb-objcopy -O binary -j .vectors.reset ^
-j .vectors.sw_exception -j .vectors.interrupt -j .vectors.hw_exception ^
user_application.elf vector_section.bin
● ISEなコマンドプロンプトシェルで作業
– ベクタセクションだけをとりだす
– ベクタセクション以外を取り出す
– ここで作成したrest_section.binのサイズを
bootloader.cのREST_SECTION_BYTE_NUMに設定
C:WORKimages> mb-objcopy -O binary -R .vectors.reset ^
-R .vectors.sw_exception -R .vectors.interrupt -R .vectors.hw_exception ^
user_application.elf rest_section.bin
アプリケーションを分割(2)
● 実行例
MCSファイルを作成/概要
● FPGAのbitファイルとアプリケーションを
MCSにまとめる
– FPGAのbitファイルは0番地から
– アプリケーションプログラムは0xb00000から
– ベクタ領域は0xc0000から
– 開始位置を変更したければbootloader.cを修正
● iMPACTでもコマンドラインでもOK
MCSファイルを作成(1)
C:WORKimages>promgen -spi ^
-w -p mcs -u 0 download.bit ^
-data_file up b00000 rest_section.bin^
-data_file up c00000 vector_section.bin
● 次のコマンドを実行すればよい
作ったらROMに書く
起動
● 動いた.
● 読み出しデータを表示してみたところ
まとめ
● AR#55026をMicroBlazeで試してみた
● 動いた,やったね!!
● 今更ISE?
– まあSpartan6使わなきゃなこともあるし
● 次は,
– 自己書き換え,かな
– SDKのサンプルの様にS形式を解釈する?

Microblaze loader