blob: fd8cee029740f98c5848b5fa4ecc5a601d341270 [file] [log] [blame]
# 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"
_yosys_log = "$target_out_dir/$target_name/yosys-log.txt"
_nextpnr_log = "$target_out_dir/$target_name/nextpnr-log.txt"
_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,
_yosys_log,
]
program = "yosys"
args = [
"-l",
rebase_path(_yosys_log, root_build_dir),
"-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,
_nextpnr_log,
]
deps = [ ":${invoker.target_name}._json" ]
program = "nextpnr-ice40"
args = [
"-l",
rebase_path(_nextpnr_log, root_build_dir),
"--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),
]
}
}