FPGAを用いて開発していく上でIPコアを作る必要が出てくる場合があります.
その一例としてGPIOを持ちMicroBlazeからAXIトランザクションにより
制御できるIPコアを作ってみます.
IPコアを動かすための土台を作る
まずはMicroBlaze環境を作ります.
ソフトウェアは Vivado 2020.1 です.
Vivadoを起動し左上のFile->Project->Newでプロジェクトを作ります.
Project nameはmyip_test
Project locationは/home/dev/Project
Create project subdirectoryにチェックを入れておきます.
特に何も指定せずDefault Partまで進めます.
BoardsタブからexStickGEを指定しFinishをクリック.
左のFlow NavigatorからCreate Block Designでブロックデザインを作成します.
Boardタブから定義済みのインターフェイスが表示されます.
Clock Sources->System Differential Clockをダブルクリック
接続先IPの指定が出てくるのでCLK_IN1_Dが選択されたままOK
生成されたIPをダブルクリックして設定を変更します.
Output Clocksタブで以下のように変更します.
MIGを動かすためにAdd IPからClocking Wizardをもう一個追加します.
以下の設定に変更します.
次にMIGを追加します.
External Memory->DDR3 SDRAMをダブルクリック
そのままOKで作成します.
次はMicroBlazeです.
Add IPからMicroBlazeを追加,上部のRun Block Automatinをクリック
余裕があるのでローカルメモリを128KB,キャッシュを64KBにしておきます.
デバッグ用にシリアル通信モジュールも追加します.
Add IPからAXI UartliteとAXI Interrupt Controllerを追加します.
AXI UartliteはIPの設定でBaud Rateを115200にしておきます.
最後の追加はリセットです.
Reset->System Resetをダブルクリック
設定は以下の図のようにします.
上部のRun Connection Automationをクリックし
axi_uartlite_0,axi_intc_0,mig_7series_0にチェックを入れてOK.
自動で生成されたUART入出力ピンはuart_rtlからUARTに名前を変更しておきます.
最後に配線を調整します.
MIGから生えているsys_clk_iとclk_ref_iを削除します.
clk_wiz_0のCLK200MからMIGのclk_ref_iへ
clk_wiz_1のCLK310MからMIGのsys_clk_iへ
axi_uartlite_0のinterruptからaxi_intc_0のintr[0:0]へ
axi_intc_0のinterruptからmicroblaze_0のinterruptへ
保存してPROJECT MANAGERへ
Sourcesから先程生成したdesign_1を右クリックしCreate HDL Wrapperをクリック.
そのままOKして生成します.
次にAdd Sourcesから制約ファイルを作成します.
Add or create constraintsを選択しNext,Create FileからFile nameはconstで作成します.
Finishで作成されたら開いて以下のシリアル通信ポートの定義を指定します.
#UART set_property PACKAGE_PIN R18 [get_ports UART_rxd] set_property PACKAGE_PIN T18 [get_ports UART_txd] set_property IOSTANDARD LVCMOS33 [get_ports UART_rxd] set_property IOSTANDARD LVCMOS33 [get_ports UART_txd]
保存して一度bitファイルが生成されるか試します.
左下のGenerate Bitstreamで生成します.
問題なく生成されると思います.
自作IPを作る
自作IPの仕様は以下の通りです.
- AXI-Liteインタフェース
- 2ビットの入力(アドレス0)
- 3ビットの出力(アドレス4)
イチから作ると大変なのでVivadoのテンプレート機能を使い作成します.
4バイトのレジスタが複数個ありアドレス指定で読み書きしてくれるものです.
VivadoのメニューバーからTools->Create and Package New IPをクリック
Create Peripheral, Package IP or Package a Block Designまで進め,
Create a new AXI4 peripheralを選択しNext.
Peripheral DetailsでIPの名称や説明について設定しNext.
Add InterfacesはそのままNext.
最後はEdit IPを選択してFinishをクリックします.
そうすると新しいウィンドウで先ほど作成したmyipのプロジェクトが開きます.
入出力ポートを増やすのでSourcesからmyip_v1_0.vを開きます.
上の方にコメントでUsers to add ports hereとあるのでそこに入出力ポートの記述を追加します.
// Users to add ports here input wire [1:0] port_in, output wire [2:0] port_out, // User ports ends
次に既に作成されているAXIスレーブのインスタンスにも増やします.
myip_v1_0_S00_AXI # ( .C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH), .C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH) ) myip_v1_0_S00_AXI_inst ( .port_in(port_in), .port_out(port_out), .S_AXI_ACLK(s00_axi_aclk), .S_AXI_ARESETN(s00_axi_aresetn), .S_AXI_AWADDR(s00_axi_awaddr),
AXIスレーブのモジュールに入出力ポートを増やし実際に入出力するためのコードを追加します.
myip_v1_0_S00_AXI.vを開き先程と同様にポートを追加します.
// Users to add ports here input wire [1:0] port_in, output wire [2:0] port_out, // User ports ends
次に出力ポートの設定をします.
出力は読み書き用に準備されているレジスタの内容を直接出力するだけなので簡単です.
ファイル末尾の方にAdd user logic hereがあるのでそこに追加します.
// Add user logic here assign port_out = slv_reg1[2:0]; // User logic ends
入力ポートの設定をします.
こっちは少し面倒で,出力用レジスタに割り込む形で入力ポートの値を出力します.
assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid; always @(*) begin // Address decoding for reading registers case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) 2'h0 : reg_data_out <= {{C_S_AXI_DATA_WIDTH - 2{1'b0}},port_in}; 2'h1 : reg_data_out <= slv_reg1; 2'h2 : reg_data_out <= slv_reg2; 2'h3 : reg_data_out <= slv_reg3; default : reg_data_out <= 0; endcase end
ソースコードの改変は以上です.
Package IPでIPをアップデートします.
すべてのMerge ~の部分をクリックして適用します.
すべて緑のチェックになったら最後にRe-Package IPで完了です.
アップデートが終わるとプロジェクトを閉じますかと聞かれるので不要であれば閉じてください.
自作IPを追加しよう
自作したIPを先程作成しておいたプロジェクトへ追加しましょう.
Block Designを開いてAdd IPからmyipを追加しましょう.
コメント