概要
先日、AliExpressでKintex-7 Base CというFPGAボードを購入しました。
My new gear... pic.twitter.com/V63Z9qo7Kj
— Y.M.D オフライン (@YMD_Glasses) February 11, 2025
このボードに搭載されているFPGAはKintex-7 325Tであり、Vivadoで使用するには有料ライセンスが必要となります。 しかし、オープンソースのツールチェーンであるopenXC7がこのFPGAに対応しているため、それを使って安く済ませようと思います。 本記事では、openXC7のインストールからKintexボードでのLチカまでを行います。
本編
openXC7のインストーラのリポジトリを開くと、「こっちはsnapベースなのでUbuntu向けで、他のディストリビューションはnixを使ってね」という旨が書かれています。 snap版とnix版の主な違いとして、yosysにGHDLのプラグインが入っている点があるようです。 ただ、これはVHDLを使う人のための機能のようで、Verilogメインの筆者にとってはひとまず不要そうです。 また、筆者はUbuntu (WSL2) を使うため、こちらのインストーラを使います。
$ wget -qO - https://raw.githubusercontent.com/openXC7/toolchain-installer/main/toolchain-installer.sh | bash
しばらく待つと、yosysとopenxc7 (nextpnr-xilinx, bbasm, fasm2frames, xc7frames2bit, bit2fasm) がインストールされました。
続いて、openxc7の使い方を理解するために、デモ用のプロジェクトを動かしてみます。 リポジトリをクローンするのですが、HTTPSだとうまくいかなかったため、SSHで行いました。
$ # git clone https://github.com/openXC7/demo-projects.git $ git clone git@github.com:openXC7/demo-projects.git $ cd demo-projects
とりあえずArty用のプロジェクトをmake
したところ、pypy3が入っていないと怒られました。
$ cd blinky-digilent-arty $ make ... pypy3 /snap/openxc7/current/opt/nextpnr-xilinx/python/bbaexport.py --device xc7a35tcsg324-1 --bba xc7a35tcsg324.bba make: pypy3: No such file or directory make: *** [../openXC7.mk:39: ../chipdb//xc7a35tcsg324.bin] Error 127
pypy3をインストールし、再度make
したところ、bitstreamの生成ができました。
blinky.bit
がそのbitstreamと思われます。
$ sudo apt install -y pypy3 $ make $ ll total 17020 drwxr-xr-x 2 yamada yamada 4096 Feb 15 22:22 ./ drwxr-xr-x 24 yamada yamada 4096 Feb 15 22:16 ../ -rw-r--r-- 1 yamada yamada 125 Feb 15 22:16 Makefile -rw-r--r-- 1 yamada yamada 2192116 Feb 15 22:22 blinky.bit -rw-r--r-- 1 yamada yamada 27068 Feb 15 22:22 blinky.fasm -rw-r--r-- 1 yamada yamada 5580828 Feb 15 22:22 blinky.frames -rw-r--r-- 1 yamada yamada 9598042 Feb 15 22:18 blinky.json -rw-r--r-- 1 yamada yamada 243 Feb 15 22:16 blinky.v -rw-r--r-- 1 yamada yamada 176 Feb 15 22:16 blinky.xdc
ここで、デモのMakefileを参考にして作成した、openXC7の処理の流れを示します。
始めに、yosysで入力Verilogファイルの論理合成を行い、ネットリストをJSON形式で出力します。
${PROJECT}.json: ${TOP_VERILOG} ${ADDITIONAL_SOURCES} yosys -p "synth_xilinx -flatten -abc9 ${SYNTH_OPTS} -arch xc7 -top ${TOP_MODULE}; write_json ${PROJECT}.json" $< ${ADDITIONAL_SOURCES}
続いて、nextpnr-xilinxを用いて、あらかじめ用意しておいたパーツのデータベースファイルと制約ファイルとともに配置と配線を行います。
${PROJECT}.fasm: ${PROJECT}.json ${CHIPDB}/${DBPART}.bin ${XDC} nextpnr-xilinx --chipdb ${CHIPDB}/${DBPART}.bin --xdc ${XDC} --json ${PROJECT}.json --fasm $@ ${PNR_ARGS} ${PNR_DEBUG}
このデータベースファイルは以下のルールによって生成されます。
${CHIPDB}/${DBPART}.bin: ${PYPY3} ${NEXTPNR_XILINX_PYTHON_DIR}/bbaexport.py --device ${PART} --bba ${DBPART}.bba bbasm -l ${DBPART}.bba ${CHIPDB}/${DBPART}.bin rm -f ${DBPART}.bba
その後、おそらくファイルフォーマットの変換などを行って、bitstreamを生成するようです。
${PROJECT}.frames: ${PROJECT}.fasm fasm2frames --part ${PART} --db-root ${PRJXRAY_DB_DIR}/${FAMILY} $< > $@ ${PROJECT}.bit: ${PROJECT}.frames xc7frames2bit --part_file ${PRJXRAY_DB_DIR}/${FAMILY}/${PART}/part.yaml --part_name ${PART} --frm_file $< --output_file $@
これをもとに、購入したFPGAボードでLチカを行ってみます。 以下に、Lチカ (8bitアップカウンタ) のVerilogコードを示します。
module blink ( input wire clk, // 50 MHz input wire rst_n, output wire [7:0] led ); localparam CNT_MAX = 50000000 / 4; reg [31:0] r_cnt; reg [7:0] r_led; always @(posedge clk) begin if (!rst_n) begin r_cnt <= 0; r_led <= 0; end else begin r_cnt <= (r_cnt == CNT_MAX-1) ? 0 : r_cnt + 1; r_led <= (r_cnt == CNT_MAX-1) ? r_led + 1 : r_led; end end assign led = r_led; endmodule
このコードは、ボードから供給される50MHzのクロックによってカウンタを駆動します。
8bitのLEDに表示される値は、1秒に4回インクリメントされます。
このファイルをblink.v
という名前で保存しました。
また、制約ファイルとしてblink.xdc
というファイルを作成しました (内容は販売者から提供されたものを利用)。
以下のコマンドで論理合成を行い、ネットリストをblink.json
に保存します。
$ yosys -p "synth_xilinx -flatten -abc9 -arch xc7 -top blink; write_json blink.json" blink.v
続いて、データベースファイルの作成を行います。 ただし、openXC7は、購入したFPGAボードの搭載するXC7K325TFFG676のスピードグレードが-1のものしか対応しておらず、このままではエラーとなります。
$ pypy3 /snap/openxc7/current/opt/nextpnr-xilinx/python/bbaexport.py --device xc7k325tffg676-2 --bba xc7k325tffg676.bba Traceback (most recent call last): File "/snap/openxc7/current/opt/nextpnr-xilinx/python/bbaexport.py", line 353, in <module> main() File "/snap/openxc7/current/opt/nextpnr-xilinx/python/bbaexport.py", line 34, in main d = import_device(args.device, xraydb_root, metadata_root) File "/snap/openxc7/current/opt/nextpnr-xilinx/python/xilinx_device.py", line 498, in import_device with open(prjxray_root + "/" + name + "/package_pins.csv") as ppf: FileNotFoundError: [Errno 2] No such file or directory: '/snap/openxc7/x1/opt/nextpnr-xilinx/python/../external/prjxray-db/kintex7/xc7k325tffg676-2/package_pins.csv'
そこで、スピードグレードを-1としてデータベースファイルを生成します。
データベースファイルはxc7k325tffg676.bin
という名前で保存されます。
$ pypy3 /snap/openxc7/current/opt/nextpnr-xilinx/python/bbaexport.py --device xc7k325tffg676-1 --bba xc7k325tffg676.bba $ bbasm -l xc7k325tffg676.bba xc7k325tffg676.bin
配置、配線、そしてbitstreamの生成を行います。
ここでもやはりスピードグレードに-1を指定します。
これで、blink.bit
という名前でbitstreamが出来上がります。
$ nextpnr-xilinx --chipdb xc7k325tffg676.bin --xdc blink.xdc --json blink.json --fasm blink.fasm $ fasm2frames --part xc7k325tffg676-1 --db-root /snap/openxc7/current/opt/nextpnr-xilinx/external/prjxray-db/kintex7/ blink.fasm > blink.frames $ xc7frames2bit --part_file /snap/openxc7/current/opt/nextpnr-xilinx/external/prjxray-db/kintex7/xc7k325tffg676-1/part.yaml --part_name xc7k325tffg676-1 --frm_file blink.frames --output_file blink.bit $ ll total 1829212 drwxr-xr-x 2 yamada yamada 4096 Feb 16 00:18 ./ drwxr-x--- 34 yamada yamada 4096 Feb 15 23:53 ../ -rw-r--r-- 1 yamada yamada 11443716 Feb 16 00:18 blink.bit -rw-r--r-- 1 yamada yamada 58022 Feb 16 00:09 blink.fasm -rw-r--r-- 1 yamada yamada 31229748 Feb 16 00:15 blink.frames -rw-r--r-- 1 yamada yamada 9628798 Feb 15 23:21 blink.json -rw-r--r-- 1 yamada yamada 403 Feb 15 23:18 blink.v -rw-r--r-- 1 yamada yamada 1467 Feb 15 23:18 blink.xdc -rw-r--r-- 1 yamada yamada 1360660175 Feb 16 00:03 xc7k325tffg676.bba -rw-r--r-- 1 yamada yamada 460057016 Feb 16 00:06 xc7k325tffg676.bin
作成したbitstreamでFPGAをコンフィギュレーションします。 MakefileにはopenFPGAloaderを使った手法が記されていますが、筆者の手元にはVivado Lab Editionがあるため、それを用いてコンフィギュレーションします。 その結果、無事にLチカ (アップカウンタ) が動作しました。
アップカウンタ動いたー pic.twitter.com/lCdk5YPxoz
— Y.M.D オフライン (@YMD_Glasses) February 15, 2025
というわけで、openXC7を用いて無事にKintex-7のFPGAボードを動かすことができました。 今後、このボードを用いて自作プロセッサの開発などに取り組もうと思います。
ライセンス
openXC7のデモリポジトリのライセンスを示します。
BSD 3-Clause License Copyright (c) 2022, Hans Baier All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.