動作環境
- Windows 10 Pro (v21H2)
- Vivado v2019.1
- FPGA基板: CORA Z7 Zynq-7000評価ボード(Z7-07S)
概要
PYNQ を使って Python で手軽に FPGA を活用 (5)
https://www.acri.c.titech.ac.jp/wordpress/archives/36
こちらで紹介されているものはPYNQで動作するように作られている。PYNQ動作だと特定のFPGA基板でしか動かないため、XSDK実装をしてみた (XSDKの実装勉強も兼ねて)。
Block Design
記事に従って作成した。

Address Editor

XSDK実装
記事のPYNQ用実装を参考にXSDK実装を作成した。
system.mssから作成可能なxbram_example.c
とxgpio_example.c
も参考にした。
helloworld.c
# include <stdio.h>
# include "platform.h"
# include "xil_printf.h"
# include "xbram.h"
# include "xgpio.h"
XBram Bram; // Bramドライバのインスタンス
# define BRAM_DEVICE_0_ID (XPAR_AXI_BRAM_CTRL_0_DEVICE_ID)
# define BRAM_DEVICE_1_ID (XPAR_AXI_BRAM_CTRL_1_DEVICE_ID)
# define GPIO_DEVICE_ID (XPAR_GPIO_0_DEVICE_ID)
/*
参考 :
1. xbram_example.c (system.mssのexampleから生成)
2. xgpio_example.c (system.mssのexampleから生成)
*/
# define NUM_LOOP (5) // Read/Write Valueのループ
int main()
{
init_platform();
XBram_Config *BramConfigPtr0;
XBram_Config *BramConfigPtr1;
XBram BramInst0; // インスタンス用
XBram BramInst1; // インスタンス用
XGpio_Config *GpioConfigPtr;
XGpio GpioInst; // インスタンス用
u32 data;
int Status;
printf("Hello 1145\r\n");
// 1. Init ====================================
BramConfigPtr0 = XBram_LookupConfig(BRAM_DEVICE_0_ID);
if (BramConfigPtr0 == (XBram_Config *)NULL) {
printf("BRAM0 Config error\r\n");
return XST_FAILURE;
}
Status = XBram_CfgInitialize(&BramInst0, BramConfigPtr0, BramConfigPtr0->CtrlBaseAddress);
if (Status != XST_SUCCESS) {
printf("BRAM0 CfgInit error\r\n");
return XST_FAILURE;
}
BramConfigPtr1 = XBram_LookupConfig(BRAM_DEVICE_1_ID);
if (BramConfigPtr1 == (XBram_Config *)NULL) {
printf("BRAM1 Config error\r\n");
return XST_FAILURE;
}
Status = XBram_CfgInitialize(&BramInst1, BramConfigPtr1, BramConfigPtr1->CtrlBaseAddress);
if (Status != XST_SUCCESS) {
printf("BRAM1 CfgInit error\r\n");
return XST_FAILURE;
}
printf("BRAM0,1 Init Pass\r\n");
// 2. Read and Write BRAM ==========================
for(int idx=0; idx < NUM_LOOP; idx++) {
data = XBram_ReadReg(BramConfigPtr0->MemBaseAddress, 4*idx);
printf("bram0 %d:%d\n", idx, (unsigned int)data);
}
for(int idx=0; idx < NUM_LOOP; idx++) {
u32 wdata = idx + 20;
XBram_WriteReg(BramConfigPtr0->MemBaseAddress, 4*idx, wdata);
//printf("bram0 %d:%d\n", idx, data);
}
for(int idx=0; idx < NUM_LOOP; idx++) {
data = XBram_ReadReg(BramConfigPtr0->MemBaseAddress, 4*idx);
printf("bram0 %d:%d\n", idx, (unsigned int)data);
}
printf("<= not yet copied =>\r\n");
for(int idx=0; idx < NUM_LOOP; idx++) {
data = XBram_ReadReg(BramConfigPtr1->MemBaseAddress, 4*idx);
printf("bram1 %d:%d\n", idx, (unsigned int)data);
}
// 3. GPIOによるCtrl制御 ==========================
GpioConfigPtr = XGpio_LookupConfig(GPIO_DEVICE_ID);
if (GpioConfigPtr == (XGpio_Config *)NULL) {
printf("GPIO Config error\r\n");
return XST_FAILURE;
}
Status = XGpio_CfgInitialize(&GpioInst, GpioConfigPtr, XPAR_AXI_GPIO_0_BASEADDR);
if (Status != XST_SUCCESS) {
printf("GPIO CfgInit error\r\n");
return XST_FAILURE;
}
printf("GPIO Init Pass\r\n");
XGpio_WriteReg(XPAR_AXI_GPIO_0_BASEADDR, 4, 0); // AXI GPIO経由でCTRLに書き込む準備
XGpio_WriteReg(XPAR_AXI_GPIO_0_BASEADDR, 0, 1); // AXI GPIO経由でCTRLに書き込む
XGpio_WriteReg(XPAR_AXI_GPIO_0_BASEADDR, 4, 0xFFFFFFFF); // AXI GPIO経由でステータスを読み込む準備
for(int idx=0; idx < NUM_LOOP; idx++) {
data = XGpio_ReadReg(XPAR_AXI_GPIO_0_BASEADDR, 0);
}
printf("<= copied =>\r\n");
for(int idx=0; idx < NUM_LOOP; idx++) {
data = XBram_ReadReg(BramConfigPtr1->MemBaseAddress, 4*idx);
printf("bram1 %d:%d\n", idx, (unsigned int)data);
}
// 4. Cleanup ==========================
cleanup_platform();
return 0;
}
動作確認

Bram0に書き込んだ値がBram1に書き込まれることを確認できた。
この動作は「Program FPGA」をした直後だけ動作する。
helloworld
.cにて書き込みする値を変更して二回目の実装をした場合は値は変わらない 。
(bram_copy.v
との関係もあるのだろう。現在はそれは重要でないため詳細は追わない。)
関連
- PYNQ を使って Python で手軽に FPGA を活用 (5) @ ACRi
- GPIOをソフトウェアから制御する @ 特殊電子回路株式会社
- https://github.com/Xilinx/embeddedsw/blob/master/lib/bsp/standalone/src/common/xil_io.h
- ZYBOで遊ぶ01:簡易タイマーIPの自作(3) @ https://thuruthurutoru.hatenablog.com/entry/2015/11/01/021638
情報感謝です。
その他
前準備
この記事は以下の実装をためそうとしている前段階として実施したもの。