Coverage for apio / scons / plugin_gowin.py: 100%
48 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-08 02:47 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-08 02:47 +0000
1# -*- coding: utf-8 -*-
2# -- This file is part of the Apio project
3# -- (C) 2016-2018 FPGAwars
4# -- Author Jesús Arroyo
5# -- License GPLv2
6# -- Derived from:
7# ---- Platformio project
8# ---- (C) 2014-2016 Ivan Kravets <me@ikravets.com>
9# ---- License Apache v2
11"""Apio scons plugin for the gowin architecture."""
13# pylint: disable=duplicate-code
15from pathlib import Path
16from SCons.Script import Builder
17from SCons.Builder import BuilderBase
18from apio.common.common_util import SRC_SUFFIXES
19from apio.scons.apio_env import ApioEnv
20from apio.scons.plugin_base import PluginBase, ArchPluginInfo
21from apio.scons.plugin_util import (
22 verilator_lint_action,
23 has_testbench_name,
24 announce_testbench_action,
25 source_files_issue_scanner_action,
26 iverilog_action,
27 basename,
28 make_verilator_config_builder,
29 get_define_flags,
30)
33class PluginGowin(PluginBase):
34 """Apio scons plugin for the ice40 architecture."""
36 def __init__(self, apio_env: ApioEnv):
37 # -- Call parent constructor.
38 super().__init__(apio_env)
40 # -- Cache values.
41 yosys_path = Path(apio_env.params.environment.yosys_path)
42 self.yosys_lib_dir = yosys_path / "gowin"
43 self.sim_lib_files = [yosys_path / "gowin" / "cells_sim.v"]
44 self.lint_lib_files = self.sim_lib_files
46 def plugin_info(self) -> ArchPluginInfo:
47 """Return plugin specific parameters."""
48 return ArchPluginInfo(
49 constrains_file_ext=".cst",
50 bin_file_suffix=".fs",
51 clk_name_index=0,
52 )
54 # @overrides
55 def synth_builder(self) -> BuilderBase:
56 """Creates and returns the synth builder."""
58 # -- Keep short references.
59 apio_env = self.apio_env
60 params = apio_env.params
62 # -- The yosys synth builder.
63 return Builder(
64 action=(
65 'yosys -p "synth_gowin -top {0} {1} -json $TARGET" '
66 "{2} -DSYNTHESIZE {3} $SOURCES"
67 ).format(
68 params.apio_env_params.top_module,
69 " ".join(params.apio_env_params.yosys_synth_extra_options),
70 "" if params.verbosity.all or params.verbosity.synth else "-q",
71 get_define_flags(apio_env),
72 ),
73 suffix=".json",
74 src_suffix=SRC_SUFFIXES,
75 source_scanner=self.verilog_src_scanner,
76 )
78 # @overrides
79 def pnr_builder(self) -> BuilderBase:
80 """Creates and returns the pnr builder."""
82 # -- Keep short references.
83 apio_env = self.apio_env
84 params = apio_env.params
86 # -- We use an emmiter to add to the builder a second output file.
87 def emitter(target, source, env):
88 _ = env # Unused
89 target.append(apio_env.target + ".pnr")
90 return target, source
92 # -- Create the builder.
93 return Builder(
94 action=(
95 "nextpnr-himbaechel --device {0} --json $SOURCE "
96 "--write $TARGET --report {1} --vopt family={2} "
97 "--vopt cst={3} {4} {5}"
98 ).format(
99 params.fpga_info.part_num,
100 apio_env.target + ".pnr",
101 params.fpga_info.gowin.family,
102 self.constrain_file(),
103 "" if params.verbosity.all or params.verbosity.pnr else "-q",
104 " ".join(params.apio_env_params.nextpnr_extra_options),
105 ),
106 suffix=".pnr.json",
107 src_suffix=".json",
108 emitter=emitter,
109 )
111 # @overrides
112 def bitstream_builder(self) -> BuilderBase:
113 """Creates and returns the bitstream builder."""
115 return Builder(
116 action="gowin_pack -d {0} -o $TARGET $SOURCE".format(
117 self.apio_env.params.fpga_info.gowin.family
118 ),
119 suffix=".fs",
120 src_suffix=".pnr.json",
121 )
123 # @overrides
124 def testbench_compile_builder(self) -> BuilderBase:
125 """Creates and returns the testbench compile builder."""
127 # -- Keep short references.
128 apio_env = self.apio_env
129 params = apio_env.params
131 # -- Sanity checks
132 assert apio_env.targeting_one_of("sim", "test")
133 assert params.target.HasField("sim") or params.target.HasField("test")
135 # -- We use a generator because we need a different action
136 # -- string for sim and test.
137 def action_generator(target, source, env, for_signature):
138 _ = (source, env, for_signature) # Unused
139 # Extract testbench name from target file name.
140 testbench_file = str(target[0])
141 assert has_testbench_name(testbench_file), testbench_file
142 testbench_name = basename(testbench_file)
144 # Construct the actions list.
145 action = [
146 # -- Print a testbench title.
147 announce_testbench_action(),
148 # -- Scan source files for issues.
149 source_files_issue_scanner_action(),
150 # -- Perform the actual test or sim compilation.
151 iverilog_action(
152 apio_env,
153 verbose=params.verbosity.all,
154 vcd_output_name=testbench_name,
155 is_interactive=apio_env.targeting_one_of("sim"),
156 lib_dirs=[self.yosys_lib_dir],
157 lib_files=self.sim_lib_files,
158 ),
159 ]
160 return action
162 # -- The testbench compiler builder.
163 return Builder(
164 # -- Dynamic action string generator.
165 generator=action_generator,
166 suffix=".out",
167 src_suffix=SRC_SUFFIXES,
168 source_scanner=self.verilog_src_scanner,
169 )
171 # @overrides
172 def lint_config_builder(self) -> BuilderBase:
173 """Creates and returns the lint config builder."""
175 # -- Sanity checks
176 assert self.apio_env.targeting_one_of("lint")
178 # -- Make the builder.
179 return make_verilator_config_builder(
180 self.yosys_lib_dir,
181 rules_to_supress=[
182 "SPECIFYIGN",
183 ],
184 )
186 # @overrides
187 def lint_builder(self) -> BuilderBase:
188 """Creates and returns the lint builder."""
190 return Builder(
191 action=verilator_lint_action(
192 self.apio_env,
193 lib_dirs=[self.yosys_lib_dir],
194 lib_files=self.lint_lib_files,
195 ),
196 src_suffix=SRC_SUFFIXES,
197 source_scanner=self.verilog_src_scanner,
198 )