CPUの合成
これまでの章では、RV64IのCPUを作成してパイプライン化しました。 今までは動作確認とテストはシミュレータで行っていましたが、 本章では実機(FPGA)でCPUを動かします。

FPGAとは何か?
集積回路を製造するには手間と時間とお金が必要です。 FPGAを使うと、少しの手間と少しの時間、安価に集積回路の実現をお試しできます。
FPGA(Field Programmable Gate Array)は、 任意の論理回路を実現できる集積回路のことです。 ハードウェア記述言語で設計した論理回路をFPGA上に設定することで、 実際に集積回路を製造しなくても実機で論理回路を再現できます。
「任意の論理回路を実現できる集積回路」は、 主にプロダクトターム方式、またはルックアップ・テーブル方式で構成されています。 本書ではルックアップ・テーブル(Lookup Table, LUT)方式のFPGAを利用します。
表8.1: 真理値表の例
| X | Y | A |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
図2では、記憶素子のデータをYによって選択し、さらにXによって選択することで2入力1出力の真理値表の論理回路を実現しています。 入力がN個で出力がM個のLUTのことをN入力M出力LUTと呼びます。
ルックアップ・テーブル方式のFPGAは、多数のLUT、入出力装置、これらを相互接続するための配線によって構成されています。 また、乗算回路やメモリなどの部品はFPGAよりも専用の回路で実現した方が良い[1]ので、 メモリや乗算回路の部品が内蔵されていることがあります。
本書では2つのFPGA(Tang Nano 9K、PYNQ-Z1)を使用して実機でCPUを動作させます。 2024年11月12日時点ではどちらも秋月電子通商で入手できて、 Tang Nano 9Kは3000円くらい、 PYNQ-Z1は50000円くらいで入手できます。
LEDの制御
大抵のFPGAボードにはLEDがついています。 本章では2つのテストプログラム(LEDを点灯させる、LEDを点滅させる)によって、CPUの動作確認を行います。
LEDはトップモジュールのポートを経由して制御します(図4)。 ポートとLEDの接続方法は合成系によって異なるため、それらの接続方法は後で考えます。 CPUからLEDを制御するには、メモリ経由で制御する、CSRによって制御するなどの方法が考えられます。 本書ではLEDを制御するためのCSRを実装して、CSRをトップモジュールのポートに接続することでLEDを制御します。

CSRにLED制御用レジスタを実装する
RISC-VのCSRのアドレス空間には、読み込みと書き込みができるCSRを自由に定義できる場所(0x800から0x8FF)が用意されています[2]。 これの先頭アドレス0x800をLEDの制御用レジスタのアドレスとして実装を進めます。
まず、CsrAddr型にLED制御用レジスタのアドレスを追加します(リスト1)。
▼リスト8.1: LEDの制御用レジスタのアドレスを追加する (csrunit.veryl) 差分をみる
enum CsrAddr: logic<12> {
MTVEC = 12'h305,
MEPC = 12'h341,
MCAUSE = 12'h342,
LED = 12'h800,
}
書き込みマスクはすべて書き込み可にします(リスト2)。
▼リスト8.2: LEDの制御用レジスタの書き込みマスク (csrunit.veryl) 差分をみる
const LED_WMASK : UIntX = 'hffff_ffff_ffff_ffff;
LEDの制御用レジスタをcsrunitモジュールのポートに定義します。CSRの幅はUIntXです(リスト3)。
▼リスト8.3: LEDの制御用レジスタを定義する (csrunit.veryl) 差分をみる
module csrunit (
...
rdata : output UIntX ,
raise_trap : output logic ,
trap_vector: output Addr ,
led : output UIntX ,
) {
rdataとwmaskにLEDの制御用レジスタの値を割り当てます(リスト4)。
▼リスト8.4: rdataとwmaskに値を割り当てる (csrunit.veryl) 差分をみる
// read
rdata = case csr_addr {
CsrAddr::MTVEC : mtvec,
CsrAddr::MEPC : mepc,
CsrAddr::MCAUSE: mcause,
CsrAddr::LED : led,
default : 'x,
};
// write
wmask = case csr_addr {
CsrAddr::MTVEC : MTVEC_WMASK,
CsrAddr::MEPC : MEPC_WMASK,
CsrAddr::MCAUSE: MCAUSE_WMASK,
CsrAddr::LED : LED_WMASK,
default : 0,
};
リセット時にLEDの制御用レジスタの値を0に設定します(リスト5)。
▼リスト8.5: リセット値の設定 (csrunit.veryl) 差分をみる
if_reset {
mtvec = 0;
mepc = 0;
mcause = 0;
led = 0;
} else {
LEDの制御用レジスタへの書き込み処理を実装します(リスト6)。
▼リスト8.6: LEDの制御用レジスタへの書き込み (csrunit.veryl) 差分をみる
case csr_addr {
CsrAddr::MTVEC : mtvec = wdata;
CsrAddr::MEPC : mepc = wdata;
CsrAddr::MCAUSE: mcause = wdata;
CsrAddr::LED : led = wdata;
default : {}
}
トップモジュールにLEDを制御するポートを実装する
LEDはトップモジュールのポートを経由して制御します(図4)。 そのため、トップモジュールにLEDを制御するポートを作成して、csrunitのLEDの制御用レジスタの値を接続します (リスト7、リスト8、リスト9、リスト10)。 LEDの個数はFPGAによって異なるため、とりあえずXLEN(=64)ビットのポートを定義します。
▼リスト8.7: coreモジュールにポートを追加する (core.veryl) 差分をみる
module core (
clk : input clock ,
rst : input reset ,
i_membus: modport membus_if::<ILEN, XLEN>::master ,
d_membus: modport membus_if::<MEM_DATA_WIDTH, XLEN>::master,
led : output UIntX ,
▼リスト8.8: csrunitモジュールのledポートと接続する (core.veryl) 差分をみる
inst csru: csrunit (
clk ,
rst ,
valid : mems_valid ,
pc : mems_pc ,
ctrl : mems_ctrl ,
rd_addr : mems_rd_addr ,
csr_addr: mems_inst_bits[31:20],
rs1 : if mems_ctrl.funct3[2] == 1 && mems_ctrl.funct3[1:0] != 0 ?
{1'b0 repeat XLEN - $bits(memq_rdata.rs1_addr), memq_rdata.rs1_addr} // rs1を0で拡張する
:
memq_rdata.rs1_data
,
rdata : csru_rdata ,
raise_trap : csru_raise_trap ,
trap_vector: csru_trap_vector,
led ,
);
▼リスト8.9: topモジュールにポートを追加する (top.veryl) 差分をみる
module top #(
param MEMORY_FILEPATH_IS_ENV: bit = 1 ,
param MEMORY_FILEPATH : string = "MEMORY_FILE_PATH",
) (
#[ifdef(TEST_MODE)]
test_success: output bit,
clk: input clock,
rst: input reset,
led: output UIntX,
) {
▼リスト8.10: coreモジュールのledポートと接続する (top.veryl) 差分をみる
inst c: core (
clk ,
rst ,
i_membus ,
d_membus ,
led ,
);
CSRの読み書きによってLED制御用のポートを制御できるようになりました。
テストを作成する
LEDを点灯させるプログラム
LEDを点灯させるプログラムを作成します(リスト11、リスト12)。 CSRRWI命令で0x800に12('b01100)を書き込みます。
▼リスト8.11: LEDを点灯させるプログラム (test/led.asm) 差分をみる
80065073 // 0: csrrwi x0, 0x800, 12
00000067 // 4: jal x0, 0
▼リスト8.12: LEDを点灯させるプログラム (test/led.hex) 差分をみる
0000006780065073
LEDを点滅させるプログラム
LEDを点滅させるプログラムを作成します(リスト13、リスト14)。 これはちょっと複雑です。
▼リスト8.13: LEDを点滅させるプログラム (test/led_counter.asm) 差分をみる
000f40b7 // 0: lui x1, 244
24008093 // 4: addi x1, x1, 576
00000113 // 8: addi x2, x0, 0
00110113 // c: addi x2, x2, 1
fe209ee3 // 10: bne x1, x2, -4
800031f3 // 14: csrrc x3, 0x800, x0
00118193 // 18: addi x3, x3, 1
80019073 // 1c: csrrw x0, 0x800, x3
00000067 // 20: jalr x0, 0(x0)
00000067 // 24: jalr x0, 0(x0)
▼リスト8.14: LEDを点滅させるプログラム (test/led_counter.hex) 差分をみる
24008093000f40b7
0011011300000113
800031f3fe209ee3
8001907300118193
0000006700000067
リスト13は次のように動作します。
- x1に1000000(
(244 << 12) + 576)を代入する - x2に0を代入
- x2がx1と一致するまでx2に1を足し続ける
- LEDのCSRをx3に読み取り、1を足した値を書き込む
- 1 ~ 4を繰り返す
これにより、LEDの制御用レジスタは一定の時間ごとに0→1→2と値が変わっていきます。
FPGAへの合成① (Tang Nano 9K)
Tang Nano 9KをターゲットにCPUを合成します。 使用するEDAのバージョンは次の通りです。
- GOWIN FPGA Designer V1.9.10.03
- Gowin Programmer Version 1.9.9
合成用のモジュールを作成する
Tang Nano 9KにはLEDが6個実装されています(図5)。 そのため、LEDの制御には6ビット必要です。 それに対して、topモジュールのledポートは64ビットであるため、ビット幅が一致しません。
Tang Nano 9Kのためだけにtopモジュールのledポートのビット幅を変更すると柔軟性がなくなってしまうため、 topモジュールの上位に合成用のモジュールを作成して調整します。
src/top_tang.verylを作成し、次のように記述します(リスト15)。 top_tangモジュールのledポートは6ビットとして定義して、topモジュールのledポートの下位6ビットを接続しています。
▼リスト8.15: Tang Nano 9K用の最上位モジュール (top_tang.veryl) 差分をみる
import eei::*;
module top_tang (
clk: input clock ,
rst: input reset ,
led: output logic<6>,
) {
// CSRの下位ビットをLEDに接続する
var led_top: UIntX;
always_comb {
led = led_top[5:0];
}
inst t: top #(
MEMORY_FILEPATH_IS_ENV: 0 ,
MEMORY_FILEPATH : "",
) (
#[ifdef(TEST_MODE)]
test_success: _,
clk ,
rst ,
led: led_top,
);
}
プロジェクトを作成する
新規プロジェクトを作成します。 GOWIN FPGA Designerを開いて、Quick StartのNew Project...を選択します。 選択したら表示されるウィンドウでは、FPGA Design Projectを選択してOKを押してください(図6)。
プロジェクト名と場所を指定します。 プロジェクト名はtangnano9k、場所は好きな場所に指定してください(図7)。
ターゲットのFPGAを選択します。 GW1NR-LV9QN88PC6/I5を選択して、Nextを押してください(図8)。
プロジェクトが作成されました(図9)。

設定を変更する
プロジェクトのデフォルト設定ではSystemVerilogを利用できないため、設定を変更します。
ProjectのConfigurationから、設定画面を開きます(図10)。
SynthesizeのVerilog LanguageをSystem Verilog 2017に設定します。 同じ画面でトップモジュール(Top Module/Entity)を設定できるため、core_top_tangを指定します(図11)。

設計ファイルを追加する
Verylのソースファイルをビルドして、 生成されるファイルリスト(core.f)を利用して、 生成されたSystemVerilogソースファイルをプロジェクトに追加します。
Gowin FPGA Programmerでファイルを追加するには、 ウィンドウ下部のConsole画面でadd_fileを実行します。 しかし、add_fileはファイルリストの読み込みに対応していないので、 ファイルリストを読み込んでadd_fileを実行するスクリプトを作成します(リスト16)。
▼リスト8.16: add_files.tcl 差分をみる
set file_list [open "ファイルリストのパス" r]
while {[gets $file_list line] != -1} {
# skip blank or comment line
if {[string trim $line] eq "" || [string index $line 0] eq "#"} {
continue
}
# add file to project
add_file $line
}
close $file_list
ウィンドウの下部にあるConsole画面で、次のコマンドを実行します(リスト17、図12)。 VerylをWSLで実行してGOWIN FPGA DesignerをWindowsで開いている場合、ファイルリスト内のパスをWindowsから参照できるパスに変更する必要があります。
▼リスト8.17: Tclスクリプトを実行する
source add_files.tclのパス
ソースファイルを追加できました(図13)。

制約ファイルを作成する
物理制約
top_tangモジュールのclk、rst、ledポートを、 それぞれTang Nano 9Kの水晶発振器、ボタン、LEDに接続します。 接続の設定には物理制約ファイルを作成します。
新しくファイルを作成するので、プロジェクトを左クリックしてNew Fileを選択します(図14)。
物理制約ファイルを選択します(図15)。
名前はtangnano9k.cstにします(図16)。
物理制約ファイルには、次のように記述します(リスト18)。
▼リスト8.18: 物理制約ファイル (tangnano9k.cst) 差分をみる
// Clock and Reset
IO_LOC "clk" 52;
IO_PORT "clk" IO_TYPE=LVCMOS33 PULL_MODE=UP;
IO_LOC "rst" 4;
IO_PORT "rst" PULL_MODE=UP;
// LED
IO_LOC "led[5]" 16;
IO_LOC "led[4]" 15;
IO_LOC "led[3]" 14;
IO_LOC "led[2]" 13;
IO_LOC "led[1]" 11;
IO_LOC "led[0]" 10;
IO_PORT "led[5]" PULL_MODE=UP DRIVE=8;
IO_PORT "led[4]" PULL_MODE=UP DRIVE=8;
IO_PORT "led[3]" PULL_MODE=UP DRIVE=8;
IO_PORT "led[2]" PULL_MODE=UP DRIVE=8;
IO_PORT "led[1]" PULL_MODE=UP DRIVE=8;
IO_PORT "led[0]" PULL_MODE=UP DRIVE=8;
IO_LOCで接続する場所の名前を指定します。
場所の名前はTang Nano 9Kのデータシートで確認できます。 例えば図17と図18から、 LEDは10、11、13、14、15、16に割り当てられていることが分かります。 また、LEDが負論理(1で消灯、0で点灯)であることが分かります。 水晶発信器とボタンについても、データシートを見て確認してください。


タイミング制約
FPGAが何MHzで動くかをタイミング制約ファイルに記述します。
物理制約ファイルと同じようにAdd Fileを選択して、 タイミング制約ファイルを作成します(図19)。
名前はtiming.sdcにします(図20)。
タイミング制約ファイルには、次のように記述します(リスト19)。
▼リスト8.19: タイミング制約ファイル (timing.sdc) 差分をみる
create_clock -name clk -period 37.037 -waveform {0 18.518} [get_ports {clk}]
Tang Nano 9Kの水晶発振器は27MHzで振動します。 そのため、create_clockでclkポートの周期を37.037ナノ秒(27MHz)に設定しています。
テスト
LEDの点灯を確認する
まず、LEDの点灯を確認します。
インポートされたtop_tang.svのtopモジュールをインスタンス化している場所で、 MEMORY_FILEPATHパラメータの値をtest/led.hexのパスに設定します(リスト20)。
▼リスト8.20: 読み込むファイルを設定する (top_tang.sv)
core_top #(
.MEMORY_FILEPATH_IS_ENV (0 ),
.MEMORY_FILEPATH ("test/led.hexへのパス")
) t (
ProcessタブのSynthesizeをクリックし、合成します(図21)。
そうすると、合成に失敗して図22のようなエラーが表示されます。
これは、Tang Nano 9Kに搭載されているメモリ用の部品の数が足りないために発生しているエラーです。 この問題を回避するために、eeiパッケージのMEM_ADDR_WIDTHの値を10に変更します[3]。 メモリの幅を変更したら、Verylファイルをビルドしなおして、もう一度合成します。
合成に成功したら、Place & Routeを押して、論理回路の配置配線情報を生成します(図23)。 それが終了したら、Tang Nano 9KをPCに接続して、Gowin Programmerを開いて設計をFPGAに書き込みます(図24)。
Tang Nano 9Kの中央2つ以外のLEDが点灯していることを確認できます。 図5の左下のボタンを押すと全てのLEDが点灯します。

LEDの点滅を確認する
MEMORY_FILEPATHパラメータの値をtest/led_counter.hexのパスに設定します(リスト21)。
▼リスト8.21: 読み込むファイルを変更する (top_tang.sv)
core_top #(
.MEMORY_FILEPATH_IS_ENV (0 ),
.MEMORY_FILEPATH ("test/led_counter.hexへのパス")
) t (
合成、配置配線しなおして、設計をFPGAに書き込むとLEDが点滅します[4]。 図5の左下のボタンを押すと状態がリセットされます。
FPGAへの合成② (PYNQ-Z1)
PYNQ-Z1をターゲットにCPUを合成します。 使用するEDAのバージョンは次の通りです。
- Vivado v2023.2
初めてPYNQ-Z1を使う人は、PYNQのドキュメントやACRiの記事を参考に起動方法を確認して、Vivadoにボードファイルを追加してください。
合成用のモジュールを作成する
PYNQ-Z1にはLEDが6個実装されています(図26)。 本章ではボタンの上の横並びの4つのLED(図26右下)を使用します。
「8.3.1 合成用のモジュールを作成する」とおなじように、 ledポートのビット幅を一致させるためにPYNQ-Z1の合成のためのトップモジュールを作成します。
src/top_pynq_z1.verylを作成し、次のように記述します(リスト22)。 top_pynq_z1モジュールのledポートは4ビットとして定義して、topモジュールのledポートの下位4ビットを接続しています。
▼リスト8.22: PYNQ-Z1用の最上位モジュール (top_pynq_z1.veryl) 差分をみる
import eei::*;
module top_pynq_z1 #(
param MEMORY_FILEPATH: string = "",
) (
clk: input clock ,
rst: input reset ,
led: output logic<4>,
) {
// CSRの下位ビットをLEDに接続する
var led_top: UIntX;
always_comb {
led = led_top[3:0];
}
inst t: top #(
MEMORY_FILEPATH_IS_ENV: 0 ,
MEMORY_FILEPATH : MEMORY_FILEPATH,
) (
#[ifdef(TEST_MODE)]
test_success: _,
clk ,
rst ,
led: led_top,
);
}
プロジェクトを作成する
Vivadoを開いて、プロジェクトを作成します。 Quick StartのCreate Projectを押すと、図27が出るのでNextを押します。
プロジェクト名とフォルダを入力します(図28)。 好きな名前と場所を入力したらNextを押します。
プロジェクトの形式を設定します(図29)。 RTL Projectを選択して、Do not specify sources at this timeにチェックを入れてNextを押します。
ターゲットのFPGAボードを選択します(図30)。 今回はPYNQ-Z1がターゲットなので、Boardsタブに移動してPYNQ-Z1を選択します。 PYNQ-Z1が表示されない場合、ボードファイルをVivadoに追加してください。
概要を確認して、Nextを押します(図31)。
プロジェクトが作成されました(図32)。

設計ファイルを追加する
Verylのソースファイルをビルドして、 生成されるファイルリスト(core.f)を利用して、 生成されたSystemVerilogソースファイルをプロジェクトに追加します。
Vivadoでファイルを追加するには、 ウィンドウ下部のTcl Console画面でadd_fileを実行します。 しかし、add_fileはファイルリストの読み込みに対応していないので、 ファイルリストを読み込んでadd_fileを実行するスクリプトを作成します(リスト23)。
▼リスト8.23: add_files.tcl 差分をみる
set file_list [open "ファイルリストのパス" r]
while {[gets $file_list line] != -1} {
# skip blank or comment line
if {[string trim $line] eq "" || [string index $line 0] eq "#"} {
continue
}
# add file to project
add_files -force -norecurse $line
}
close $file_list
ウィンドウの下部にあるTcl Console画面で、次のコマンドを実行します(リスト24、図33)。 VerylをWSLで実行してVivadoをWindowsで開いている場合、ファイルリスト内のパスをWindowsから参照できるパスに変更する必要があります。
▼リスト8.24: Tclスクリプトを実行する
source add_files.tclのパス
ソースファイルが追加されました(図34)。

Verilogのトップモジュールを作成する
VerylファイルはSystemVerilogファイルに変換されますが、 VivadoではトップモジュールにSystemVerilogファイルを使用できません。 この問題を回避するために、Verilogでtop_pynq_z1モジュールをインスタンス化するモジュールを記述します(リスト25)。
▼リスト8.25: PYNQ-Z1用の最上位モジュール (core_top_v.v) 差分をみる
module core_top_v #(
parameter MEMORY_FILEPATH = ""
) (
input wire clk,
input wire rst,
output wire [3:0] led
);
core_top_pynq_z1 #(
.MEMORY_FILEPATH(MEMORY_FILEPATH)
) t (
.clk(clk),
.rst(rst),
.led(led)
);
endmodule
core_top_v.vをadd_filesでプロジェクトに追加します(リスト26)。
▼リスト8.26: Tcl Consoleで実行する
add_files -norecurse core_top_v.vのパス
ブロック図を作成する
Vivadoではモジュール間の接続をブロック図によって行えます。 設計したモジュールをブロック図に追加して、クロックやリセット、LEDの接続を行います。
ブロック図の作成とトップモジュールの設定
画面左のFlow NavigatorでCreate Block Designを押してブロック図を作成します(図35)。
名前は適当なものに設定します(図36)。
Sourcesタブに作成されたブロック図が追加されるので、右クリックしてCreate HDL Wrapper...を押します(図37)。
そのままOKを押します(図38)。
ブロック図がVerilogモジュールになるので、 Set as Topを押して、これをトップモジュールにします(図39)。
ブロック図がトップモジュールに設定されました(図40)。

ブロック図の設計
Diagram画面でブロック図を組み立てます。
まず、core_top_vモジュールを追加します。 適当な場所で右クリックして、Add Module...を押します(図41)。
core_top_vを選択して、OKを押します(図42)。
core_top_vが追加されるので、 ledポートをクリックしてMake Externalを押します(xilinx/bd/8)。
led_0ポートが追加されました(図44)。 これがブロック図のoutputポートになります。
led_0を選択して、左側のExternal Port PropertiesのNameをledに変更します。
次に、+ボタンを押して ZYNQ7 Processing System、 Processor System Reset、 Clocking Wizardを追加します(図46、図47)。

上にDesigner Assistance Availableと出るので、Run Block Automationを押します(図48)。
図49のようになっていることを確認して、OKを押します。
図50のようにポートを接続します。 接続元から接続先にドラッグすることでポートを接続できます。 また、proc_sys_reset_0のext_reset_inをMake Externalしてrstを作成してください。
ZYNQ7 Processing Systemのoutputポートには、100MHzのクロック信号FCLK_CLK0が定義されています。 これをそのままcore_top_vに供給しても良いですが、 現状のコードではcore_top_vが100MHzで動くように合成できません。 そのため、Clocking Wizardで50MHzに変換したクロックをcore_top_vに供給します。
clk_wiz_0をダブルクリックして、入力を50MHzに変換するように設定します。 clk_out1のRequestedを50に変更してください。 また、Enable Optional ~のresetとlockedのチェックを外します(図51)。
clk_wiz_0が少しコンパクトになりました(図52)。

制約ファイルを作成する
ブロック図のrst、ledを、それぞれPYNQ-Z1のボタン(BTN0)、LED(LD0、LD1、LD2、LD3)に接続します。 接続の設定には物理制約ファイルを作成します。
pynq.xdcを作成し、次のように記述します(リスト27)。
▼リスト8.27: 物理制約ファイル (pynq.xdc) 差分をみる
# reset (BTN0)
set_property -dict { PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [ get_ports rst ]
# led (LD0 - LD4)
set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [ get_ports led[0] ];
set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [ get_ports led[1] ];
set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [ get_ports led[2] ];
set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [ get_ports led[3] ];
リスト27では、 rstにD19を割り当てて、 led[0]、led[1]、led[2]、led[3]にR14、P14、N16、M14を割り当てます(図53)。 ボタンは押されていないときに1、押されているときに0になります。 LEDは1のときに点灯して、0のときに消灯します。

テスト
LEDの点灯を確認する
ブロック図のcore_top_v_0をダブルクリックすることで、 core_top_vモジュールのMEMORY_FILEPATHパラメータを変更します。 パラメータにはテストのHEXファイルのパスを設定します(図54)。 LEDの点灯のテストのためにtest/led.hexのパスを入力します。
PROGRAM AND DEBUGのGenerate Bitstreamを押して合成と配置配線を実行します(図55)。
合成が完了したらOpen Hardware Managerを押して、 開かれたHARDWARE MANAGERのOpen TargetのAuto Connectを押してPYNQ-Z1と接続します(図56)。

Program deviceを押すと、PYNQ-Z1に設計が書き込まれます。
LEDが点灯しているのを確認できます(図58)。 BTN0を押すとLEDが消灯します。

LEDの点滅を確認する
core_top_vモジュールのMEMORY_FILEPATHパラメータの値をtest/ledcounter.hexのパスに変更して、 再度Generate Bitstreamを実行します。
Hardware Managerを開いてProgram deviceを押すとLEDが点滅します[5]。 BTN0を押すと状態がリセットされます。