fpga: Create fpga_image build template Change-Id: I85f157838060d8c0187bb66596afdc894d2a4bbb Reviewed-on: https://pigweed-review.googlesource.com/c/gonk/+/185471 Reviewed-by: Armando Montanez <amontanez@google.com> Commit-Queue: Anthony DiGirolamo <tonymd@google.com>
diff --git a/BUILD.gn b/BUILD.gn index ea9870c..8a504ba 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -26,6 +26,10 @@ ":gonk_python.lint", ":gonk_python.tests", ":python.install", + + # TODO(tonymd): Enable the verilog build by default when the following tools + # are available in CIPD: yosys, nextpnr-ice40, icetime, icepack + # ":fpga", ] } @@ -40,6 +44,10 @@ ] } +group("fpga") { + deps = [ "//fpga" ] +} + # Python Targets _gonk_python_packages = [ "//tools" ]
diff --git a/README.md b/README.md index 8bf1a10..477707d 100644 --- a/README.md +++ b/README.md
@@ -40,6 +40,24 @@ The build commands are defined in: `//tools/gonk_tools/build_project.py`. +## Verilog: + +The Verilog build requires the following to be installed on Linux: + +```sh +sudo apt install fpga-icestorm nextpnr-ice40 yosys +``` + +Run this to compile the Gonk Verilog: + +```sh +pw build +ninja -C out/gn fpga +``` + +The bitstream files will be written with the `.bin` extenson under +`./out/gn/obj/fpga/*/*.bin`. + ## Gonk `spi_flash_test` Example ### Flash with `dfu-util`
diff --git a/fpga/BUILD.gn b/fpga/BUILD.gn new file mode 100644 index 0000000..6958491 --- /dev/null +++ b/fpga/BUILD.gn
@@ -0,0 +1,20 @@ +# Copyright 2023 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +import("//build_overrides/pigweed.gni") + +import("//fpga/fpga_image.gni") + +group("fpga") { +}
diff --git a/fpga/fpga_image.gni b/fpga/fpga_image.gni new file mode 100644 index 0000000..6cbf00d --- /dev/null +++ b/fpga/fpga_image.gni
@@ -0,0 +1,141 @@ +# Copyright 2023 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +import("//build_overrides/pigweed.gni") + +import("$dir_pw_build/exec.gni") + +# Builds an FPGA image using the icestorm toolchain. +# +# Requires the following tools: +# yosys, nextpnr-ice40, icepack, icetime +# +# Example: +# +# fpga_image("toplevel") { +# sources = [ +# "gonk/csa_ctl_top.v", +# "gonk/pll.v", +# "gonk/rst_sync.v", +# "gonk/sig_sync.v", +# "gonk/spi_m_core.v", +# "gonk/spi_m_core_ctl.v", +# "gonk/spi_s_core.v", +# "gonk/top.v", +# ] +# +# pcf = "gonk/top.pcf" +# } +# +template("fpga_image") { + assert(defined(invoker.sources), "fpga_image requires 'sources'") + assert(defined(invoker.pcf), "fpga_image requires a 'pcf'") + + # Image basename set to target_name by default but can be overriden. + _image_name = "$target_name" + if (defined(invoker.image_name)) { + _image_name = invoker.image_name + } + + _verilog_files = invoker.sources + _pcf_file = invoker.pcf + + _json_file = "$target_out_dir/$target_name/${_image_name}.json" + _asc_file = "$target_out_dir/$target_name/${_image_name}.asc" + _bin_file = "$target_out_dir/$target_name/${_image_name}.bin" + _timing_report_text = + "$target_out_dir/$target_name/${_image_name}_timing_report.txt" + _timing_report_json = + "$target_out_dir/$target_name/${_image_name}_timing_report.json" + + # By default, build the bin file and timing report. + group("$target_name") { + public_deps = [ + ":${target_name}._bin", + ":${target_name}._time", + ] + } + + pw_exec("${target_name}._json") { + inputs = _verilog_files + outputs = [ _json_file ] + + program = "yosys" + args = [ + "-q", + "-p", + "synth_ice40 -json " + rebase_path(_json_file, root_build_dir), + ] + args += rebase_path(_verilog_files, root_build_dir) + } + + pw_exec("${target_name}._asc") { + inputs = [ _json_file ] + outputs = [ _asc_file ] + + deps = [ ":${invoker.target_name}._json" ] + + program = "nextpnr-ice40" + args = [ + "--freq", + "75", + "--hx8k", + "--package", + "tq144:4k", + "--json", + rebase_path(_json_file, root_build_dir), + "--pcf", + rebase_path(_pcf_file, root_build_dir), + "--asc", + rebase_path(_asc_file, root_build_dir), + "--opt-timing", + "--placer", + "heap", + ] + } + + pw_exec("${target_name}._bin") { + inputs = [ _asc_file ] + outputs = [ _bin_file ] + + deps = [ ":${invoker.target_name}._asc" ] + + program = "icepack" + args = [ + rebase_path(_asc_file, root_build_dir), + rebase_path(_bin_file, root_build_dir), + ] + } + + pw_exec("${target_name}._time") { + inputs = [ _asc_file ] + outputs = [ + _timing_report_text, + _timing_report_json, + ] + + deps = [ ":${invoker.target_name}._asc" ] + + program = "icetime" + args = [ + "-r", + rebase_path(_timing_report_text, root_build_dir), + "-j", + rebase_path(_timing_report_json, root_build_dir), + "-tmd", + "hx8k", + rebase_path(_asc_file, root_build_dir), + ] + } +}