Coverage for apio/scons/plugin_gowin.py: 100%
47 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-06 10:20 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-06 10:20 +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.yosys_lib_file = yosys_path / "gowin" / "cells_sim.v"
45 def plugin_info(self) -> ArchPluginInfo:
46 """Return plugin specific parameters."""
47 return ArchPluginInfo(
48 constrains_file_ext=".cst",
49 bin_file_suffix=".fs",
50 clk_name_index=0,
51 )
53 # @overrides
54 def synth_builder(self) -> BuilderBase:
55 """Creates and returns the synth builder."""
57 # -- Keep short references.
58 apio_env = self.apio_env
59 params = apio_env.params
61 # -- The yosys synth builder.
62 return Builder(
63 action=(
64 'yosys -p "synth_gowin -top {0} {1} -json $TARGET" {2} {3} '
65 "$SOURCES"
66 ).format(
67 params.apio_env_params.top_module,
68 " ".join(params.apio_env_params.yosys_synth_extra_options),
69 "" if params.verbosity.all or params.verbosity.synth else "-q",
70 get_define_flags(apio_env),
71 ),
72 suffix=".json",
73 src_suffix=SRC_SUFFIXES,
74 source_scanner=self.verilog_src_scanner,
75 )
77 # @overrides
78 def pnr_builder(self) -> BuilderBase:
79 """Creates and returns the pnr builder."""
81 # -- Keep short references.
82 apio_env = self.apio_env
83 params = apio_env.params
85 # -- We use an emmiter to add to the builder a second output file.
86 def emitter(target, source, env):
87 _ = env # Unused
88 target.append(apio_env.target + ".pnr")
89 return target, source
91 # -- Create the builder.
92 return Builder(
93 action=(
94 "nextpnr-himbaechel --device {0} --json $SOURCE "
95 "--write $TARGET --report {1} --vopt family={2} "
96 "--vopt cst={3} {4} {5}"
97 ).format(
98 params.fpga_info.part_num,
99 apio_env.target + ".pnr",
100 params.fpga_info.gowin.family,
101 self.constrain_file(),
102 "" if params.verbosity.all or params.verbosity.pnr else "-q",
103 " ".join(params.apio_env_params.nextpnr_extra_options),
104 ),
105 suffix=".pnr.json",
106 src_suffix=".json",
107 emitter=emitter,
108 )
110 # @overrides
111 def bitstream_builder(self) -> BuilderBase:
112 """Creates and returns the bitstream builder."""
114 return Builder(
115 action="gowin_pack -d {0} -o $TARGET $SOURCE".format(
116 self.apio_env.params.fpga_info.gowin.family
117 ),
118 suffix=".fs",
119 src_suffix=".pnr.json",
120 )
122 # @overrides
123 def testbench_compile_builder(self) -> BuilderBase:
124 """Creates and returns the testbench compile builder."""
126 # -- Keep short references.
127 apio_env = self.apio_env
128 params = apio_env.params
130 # -- Sanity checks
131 assert apio_env.targeting("sim", "test")
132 assert params.target.HasField("sim") or params.target.HasField("test")
134 # -- We use a generator because we need a different action
135 # -- string for sim and test.
136 def action_generator(source, target, env, for_signature):
137 _ = (source, env, for_signature) # Unused
138 # Extract testbench name from target file name.
139 testbench_file = str(target[0])
140 assert has_testbench_name(testbench_file), testbench_file
141 testbench_name = basename(testbench_file)
143 # Construct the actions list.
144 action = [
145 # -- Print a testbench title.
146 announce_testbench_action(),
147 # -- Scan source files for issues.
148 source_files_issue_scanner_action(),
149 # -- Perform the actual test or sim compilation.
150 iverilog_action(
151 apio_env,
152 verbose=params.verbosity.all,
153 vcd_output_name=testbench_name,
154 is_interactive=apio_env.targeting("sim"),
155 lib_dirs=[self.yosys_lib_dir],
156 lib_files=[self.yosys_lib_file],
157 ),
158 ]
159 return action
161 # -- The testbench compiler builder.
162 return Builder(
163 # -- Dynamic action string generator.
164 generator=action_generator,
165 suffix=".out",
166 src_suffix=SRC_SUFFIXES,
167 source_scanner=self.verilog_src_scanner,
168 )
170 # @overrides
171 def lint_config_builder(self) -> BuilderBase:
172 """Creates and returns the lint config builder."""
174 # -- Sanity checks
175 assert self.apio_env.targeting("lint")
177 # -- Make the builder.
178 return make_verilator_config_builder(self.yosys_lib_dir)
180 # @overrides
181 def lint_builder(self) -> BuilderBase:
182 """Creates and returns the lint builder."""
184 return Builder(
185 action=verilator_lint_action(
186 self.apio_env,
187 lib_dirs=[self.yosys_lib_dir],
188 lib_files=[self.yosys_lib_file],
189 ),
190 src_suffix=SRC_SUFFIXES,
191 source_scanner=self.verilog_src_scanner,
192 )