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),
+ ]
+ }
+}