以下の記事の部分的な和訳・要約の個人用メモです。外付けDDRメモリを使用してアプリケーションを実行するまでの手順を解説します。
環境
- Hardware
- Arty A7 100T
- PCとつなぐ用ケーブル
- Software
- Vivado 2023.2
- Vitis Unified IDE 2023.2
- GTKTerm
手順
-
プロジェクト作成
-
Do not specify sources at this time
にチェック - boardファイルを選択。一応
Refresh
してから選択するのが吉。
-
-
ハードウェア設計
Create Block Design
-
Board
タブからDDR SDRAM
を右クリック、Auto Connect
を選択 -
clk_ref_i
ピンを削除し、MIG
の出力ポートui_addn_clk_0
をそこに接続 -
sys_clk_i
はxdc
ファイルで登録しておく -
Run Connection Automation
(リセットピンの追加) -
Clocking Wizard
を追加,clk_in1
とMIG
のui_clk
を接続reset
とMIG
のui_clk_sync_rst
を接続 -
MicroBlaze
を追加,Run Block Automation
,Clock Connection
にClocking Wizard
のclk_out1
を指定,Local Memory
を32KB
に変更 Run Connection Automation
-
Board
タブからUSB UART
を追加 (AXI Timer
とかもここで追加する) Run Connection Automation
Validate Design
Create HDL Wrapper
Generate Bitstream
Export Hardware...
-
Launch Vitis IDE
-
ソフトウェア設計
- workspaceの指定
- platformの指定
- アプリケーションはexampleから適当に
Hello World
を選択 - ビルド
- 実行
おまけ
DDRとBRAMそれぞれに100回ずつREADとWRITEを実行しました。
BRAMとDDRメモリセルでのアクセス速度比較
#define __MICROBLAZE__
#include <unistd.h>
#include <sys/_intsup.h>
#include <xstatus.h>
#include "xparameters.h"
#include "platform.h"
#include "xil_printf.h"
#include "xtmrctr.h"
#define DDR_BASE 0x80000000
#define BRAM_BASE 0x50
XTmrCtr TimerCounterInst;
int init(){
int Status;
Status = XTmrCtr_Initialize(&TimerCounterInst, XPAR_AXI_TIMER_0_BASEADDR);
if (Status != XST_SUCCESS) {
xil_printf("Timer Initialize Error\n\r");
return XST_FAILURE;
}
XTmrCtr_SetOptions(&TimerCounterInst, 0, XTC_AUTO_RELOAD_OPTION);
XTmrCtr_Start(&TimerCounterInst, 0);
return XST_SUCCESS;
}
int main()
{
init_platform();
int res = init();
if(res != XST_SUCCESS)return 0;
u32 tStart, tEnd;
double fval;
int whole, thousandths;
int repeatNum = 10000;
int tmp;
tStart = XTmrCtr_GetValue(&TimerCounterInst, 0);
for(int i=0; i<repeatNum; i++){
*(int *)DDR_BASE = 9; // DDR WRITE
}
tEnd = XTmrCtr_GetValue(&TimerCounterInst, 0);
xil_printf("End - Start = %u\n\r", (unsigned int)(tEnd - tStart));
fval= (tEnd - tStart) / 100000000.0 * 1000; // ms (周波数100000000.0Hzで除することでsに変換し、1000倍してmsに変換)
whole = fval; // 整数
thousandths = (fval - whole) * 1000; // 小数点以下3桁
xil_printf("Time = %d.%03d ms\n\r", whole, thousandths);
tStart = XTmrCtr_GetValue(&TimerCounterInst, 0);
for(int i=0; i<repeatNum; i++){
tmp = *(int *)DDR_BASE; // DDR READ
}
tEnd = XTmrCtr_GetValue(&TimerCounterInst, 0);
xil_printf("End - Start = %u\n\r", (unsigned int)(tEnd - tStart));
fval= (tEnd - tStart) / 100000000.0 * 1000; // ms (周波数100000000.0Hzで除することでsに変換し、1000倍してmsに変換)
whole = fval; // 整数
thousandths = (fval - whole) * 1000; // 小数点以下3桁
xil_printf("Time = %d.%03d ms\n\r", whole, thousandths);
tStart = XTmrCtr_GetValue(&TimerCounterInst, 0);
for(int i=0; i<repeatNum; i++){
*(int *)BRAM_BASE = 1; // BRAM WRITE
}
tEnd = XTmrCtr_GetValue(&TimerCounterInst, 0);
xil_printf("End - Start = %u\n\r", (unsigned int)(tEnd - tStart));
fval= (tEnd - tStart) / 100000000.0 * 1000; // ms (周波数100000000.0Hzで除することでsに変換し、1000倍してmsに変換)
whole = fval; // 整数
thousandths = (fval - whole) * 1000; // 小数点以下3桁
xil_printf("Time = %d.%03d ms\n\r", whole, thousandths);
tStart = XTmrCtr_GetValue(&TimerCounterInst, 0);
for(int i=0; i<repeatNum; i++){
tmp = *(int *)BRAM_BASE; // BRAM READ
}
tEnd = XTmrCtr_GetValue(&TimerCounterInst, 0);
xil_printf("End - Start = %u\n\r", (unsigned int)(tEnd - tStart));
fval= (tEnd - tStart) / 100000000.0 * 1000; // ms (周波数100000000.0Hzで除することでsに変換し、1000倍してmsに変換)
whole = fval; // 整数
thousandths = (fval - whole) * 1000; // 小数点以下3桁
xil_printf("Time = %d.%03d ms\n\r", whole, thousandths);
cleanup_platform();
return 0;
}
End - Start = 7952440 // DDR WRITE
Time = 79.524 ms
End - Start = 7952436 // DDR READ
Time = 79.524 ms
End - Start = 7289934 // BRAM WRITE
Time = 72.899 ms
End - Start = 7289937 // BRAM READ
Time = 72.899 ms
経過したクロック数に多少の誤差はあれどDDRとBRAM間でそこまでの差は見られませんでした。
参考