🏩

MicroBlazeを用いたハードウェア構築

2023/03/28に公開

MicroBlazeを用いたハードウェア構築

はじめに

前回に続き、「FPGAプログラミング大全 第2版」をやる
https://amzn.to/40isQyG

HDL経験:Verilog入門書を一日読んだだけ 基本の文法のみ
本投稿では本書6-1~「ソフトマクロCPUシステム」を実施したメモを書きます

環境

FPGA : Xilinx Zybo Z7-20
OS : WSL2 Ubuntu20.04
開発環境 : Vivado ML edition 2022.1 Linux版

やりたいこと

  • Zynqで構築したハードウェア同等の回路をソフトマクロCPU MicroBlazeを使って実装する
  • UART通信はZynq PS側で埋まっているため、直接PL側と通信できない。そのためMicroBlazeのDebug Moduleを経由してUART通信を行う

Microblazeとは

  • Xilinxが提供しているソフトマクロCPU
  • 対応バス
    • LMB :BRAM接続用
    • AXI :ARM系バス
    • ACE :AXI拡張
  • MicroBlaze Processor Reference

https://docs.xilinx.com/v/u/2018.2-English/ug984-vivado-microblaze-ref

実装

ハードウェア構築

Vivadoでハードウェアを構築していく

  • Create project -> Create Block Design
  • MicroBlaze IPを追加
    • Microcontroller
    • LocalMemory設定
    • Debug+UART
    • 割り込みコントローラは不要
  • Run Connection Automation実行

    ペリフェラルが生成される(local memory, clock,reset等)
  • MicroBlazeのInput Clockを100->125MHzに変更
  • CLK端子はシングルエンドなのでDifferential -> SingleEndに変更
  • Reset: Active Highで使用。Sys ResetとClock Resetを接続
  • GPIO IPを追加 ALL Output[2:0] 1Ch構成で使用する
  • 制約ファイルに合わせてI/Oの信号名を変更
  • 最後にエラーが出るのでZynq PSを配置しておく
  • Validate design -> Create HDL Wrapper -> Generate Bitstream

最終的なブロックデザイン

Bitstreamを行ったところエラー

要はI/Oが割り当てられず、それによりDRCエラーを吐いている。
-> 制約ファイルの追加を忘れていたのが原因🥺
制約ファイルを追加してGenerate Bitstream
無事に完了したのでExport Hardware

MicroBlaze アドレスマップ
GPIO/BRAM/MDMのレジスタアドレスが確認できる

VitisからMicroBlazeを制御

  • Vitis起動
  • Hardware構築で生成したxsaファイルを使用してPlatform projectを作成
  • Applicationでhello worldを選択
  • Build project
  • Debug As -> Launch Hardware

    実行完了 
    MicroBlazeはSerialportではなくUARTを使うのでConsole上で確認する

LED点灯プログラムを動かす

次にApplication Projectを再作成してMicroblazeからGPIOを制御し、LEDを点灯させる
LED_test.cをimport Source -> Build project
コードはここから参照してます
https://www.shuwasystem.co.jp/support/7980html/6326.html

/*xparameters.h
/* Canonical definitions for peripheral AXI_GPIO_0 */
#define XPAR_GPIO_0_BASEADDR 0x40000000
#define XPAR_GPIO_0_HIGHADDR 0x4000FFFF
#define XPAR_GPIO_0_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID
#define XPAR_GPIO_0_INTERRUPT_PRESENT 0
#define XPAR_GPIO_0_IS_DUAL 0

/*led_test.c */
#include "xparameters.h"
#include "xil_printf.h"

#define LED      *((volatile unsigned int*) (XPAR_GPIO_0_BASEADDR + 0x00))
#define LED_ctrl *((volatile unsigned int*) (XPAR_GPIO_0_BASEADDR + 0x04))

int main()
{
    int i, j;

    LED_ctrl = 0x0; 
    xil_printf("Hello FPGA World!\r\n");
    while(1) {
        for ( i=0; i<5; i++ ) {
            xil_printf("i=%d\r\n", i);
            switch ( i ) {
                case  0: LED = 0x4; break;
                case  1: LED = 0x2; break;
                case  2: LED = 0x1; break;
                case  3: LED = 0x7; break;
                case  4: LED = 0x0; break;
                default: LED = 0x0;
            }
            for ( j=0; j<40000000; j++);
        }
    }

    return 0;
}

VivadoでGenerate Bitstreamを行うとxparameters.hにHardware側のGPIOレジスタが生成されるので、それを制御プログラム側でポインタとして指定している

xparameters.hを見るとXPAR_GPIO_0_BASEADDRは16bitのレジスタ空間が用意されている(0x40000000~0x4000FFFF)

動作としてはwhile文で3bitのGPIO=3つのRGB LEDライトを(100)->(010)->(001)->(111)->(000)の順でj<40000000のループ毎に実施している

今後やること

MicroBlaze + 自作IPで動作させる(そのうち本記事に追加する

感想

  • AXI busめちゃ便利
  • これでZynq(PS)が無くても一応制御できるようになった

おわり

Discussion