Skip to content

Commit

Permalink
Add support for official gowin tool
Browse files Browse the repository at this point in the history
  • Loading branch information
flaminggoat authored Nov 4, 2024
1 parent 9696c99 commit dc65687
Show file tree
Hide file tree
Showing 7 changed files with 277 additions and 2 deletions.
25 changes: 25 additions & 0 deletions edalize/flows/gowin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright edalize contributors
# Licensed under the 2-Clause BSD License, see LICENSE for details.
# SPDX-License-Identifier: BSD-2-Clause

from edalize.flows.generic import Generic


class Gowin(Generic):
"""Official Gowin FPGA toolchain"""

argtypes = []

@classmethod
def get_flow_options(cls):
return {k: v for k, v in cls.FLOW_OPTIONS.items() if k != "tool"}

@classmethod
def get_tool_options(cls, flow_options):
flow = flow_options.get("frontends", []).copy() + ["gowin"]

return cls.get_filtered_tool_options(flow, cls.FLOW_DEFINED_TOOL_OPTIONS)

def configure_flow(self, flow_options):
self.flow_options["tool"] = "gowin"
return super().configure_flow(flow_options)
150 changes: 150 additions & 0 deletions edalize/tools/gowin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Copyright edalize contributors
# Licensed under the 2-Clause BSD License, see LICENSE for details.
# SPDX-License-Identifier: BSD-2-Clause

import os.path

from edalize.tools.edatool import Edatool
from edalize.utils import EdaCommands
from functools import partial


class Gowin(Edatool):

description = "Official development tool for Gowin FPGAs"

TOOL_OPTIONS = {
"part": {
"type": "str",
"desc": "FPGA part number (e.g. GW2AR-LV18QN88C8/I7)",
},
"part_version": {
"type": "str",
"desc": "Part version. e.g 'C'",
},
"synth": {
"type": "str",
"desc": "Synthesis tool. Allowed values are gowin (default) or none.",
},
"pnr": {
"type": "str",
"desc": "P&R tool. Allowed values are gowin (default) and none (to just run synthesis)",
},
"gowin_options": {
"type": "str",
"desc": "Additional options for Gowin. See Gowin Software User Guide SUG-100 > set_option",
"list": True,
},
}

def src_file_filter(self, f):
def _append_library(f):
s = ""
if f.get("logical_name"):
s += (
"\nset_file_prop -lib " + f["logical_name"] + ' "' + f["name"] + '"'
)
return s

def _handle_src(t, f):
s = "add_file -type " + t
s += ' "' + f["name"] + '"'
s += _append_library(f)
return s

def _handle_tcl(f):
return "source " + f["name"]

file_mapping = {
"verilogSource": partial(_handle_src, "verilog"),
"systemVerilogSource": partial(_handle_src, "verilog"),
"vhdlSource": partial(_handle_src, "VHDL_FILE"),
"CST": partial(_handle_src, "cst"),
"SDC": partial(_handle_src, "sdc"),
"tclSource": partial(_handle_tcl),
}

_file_type = f.get("file_type")
if _file_type in file_mapping:
return file_mapping[_file_type](f)
elif _file_type == "user":
return ""

return ""

def setup(self, edam):
super().setup(edam)

file_table = []
unused_files = []
depfiles = []

has_vhdl2008 = "vhdlSource-2008" in [x["file_type"] for x in self.files]
has_systemVerilog = "systemVerilogSource" in [
x["file_type"] for x in self.files
]

escaped_name = self.name.replace(".", "_")

if not self.tool_options.get("synth"):
self.tool_options["synth"] = "gowin"

if not self.tool_options.get("pnr"):
self.tool_options["pnr"] = "gowin"

if not self.tool_options.get("part"):
raise RuntimeError("FPGA part number must be specified")

if self.generic:
raise RuntimeError("Gowin does not support top level generics")

if self.vlogparam:
raise RuntimeError("Gowin does not support top level verilog parameters")

if self.vlogdefine:
raise RuntimeError("Gowin does not support top level verilog defines")

commands = EdaCommands()

for f in self.files:
cmd = self.src_file_filter(f)

if cmd:
depfiles.append(f["name"])
file_table.append(cmd)
else:
unused_files.append(f)

self.edam = edam.copy()
self.edam["files"] = unused_files

fs_file = os.path.join("pnr", escaped_name + ".fs")

self.edam["files"].append(
{
"name": fs_file,
}
)

self.template_vars = {
"name": escaped_name,
"file_table": file_table,
"tool_options": self.tool_options,
"toplevel": self.toplevel,
"has_vhdl2008": has_vhdl2008,
"has_systemVerilog": has_systemVerilog,
}

commands.add(
["gw_sh", "edalize_gowin_template.tcl"],
[fs_file],
depfiles,
)

commands.set_default_target(fs_file)
self.commands = commands

def write_config_files(self):
self.render_template(
"gowin-project.tcl.j2", "edalize_gowin_template.tcl", self.template_vars
)
18 changes: 18 additions & 0 deletions edalize/tools/templates/gowin/gowin-project.tcl.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
set_device {{ tool_options.part }} {{ "--device_version " + tool_options.part_version if tool_options.part_version else "" }}


{% for src_file in file_table %}
{{ src_file }}
{% endfor %}

set_option -top_module {{ toplevel }}
{{ "set_option -vhdl_std vhd2008" if has_vhdl2008 else "" }}
{{ "set_option -verilog_std sysv2017" if has_systemVerilog else "" }}

{% for option in tool_options.gowin_options %}
set_option {{ option }}
{% endfor %}


{{ "run syn" if tool_options.synth == "gowin" else "" }}
{{ "run pnr" if tool_options.pnr == "gowin" else "" }}
11 changes: 9 additions & 2 deletions tests/edalize_tool_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,25 @@ def _tool_fixture(
toplevel="top_module",
ref_subdir="",
config_files=[],
paramtypes=["plusarg", "vlogdefine", "vlogparam"],
has_makefile=True,
):

tf = ToolFixture(tool_name, ref_subdir)

edam = get_edam(
tool_name, tool_options=tool_options, files=files, toplevel=toplevel
tool_name,
tool_options=tool_options,
files=files,
toplevel=toplevel,
paramtypes=paramtypes,
)

tf.tool.work_root = tmp_path
tf.tool.setup(edam)
tf.tool.commands.write(tmp_path / "Makefile")
tf.compare_makefile()
if has_makefile:
tf.compare_makefile()

return tf

Expand Down
30 changes: 30 additions & 0 deletions tests/test_tool_gowin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from .edalize_tool_common import tool_fixture


def test_tool_gowin(tool_fixture):

tool_options = {
"part": "dummy_part",
"gowin_options": ["some", "gowin", "options"],
}

tf = tool_fixture(
"gowin", tool_options=tool_options, paramtypes=[], has_makefile=False
)

tf.tool.configure()
tf.compare_config_files(["edalize_gowin_template.tcl"])


def test_tool_gowin_minimal(tool_fixture):
tool_options = {"part": "dummy_part"}
tf = tool_fixture(
"gowin",
tool_options=tool_options,
ref_subdir="minimal",
paramtypes=[],
has_makefile=False,
)

tf.tool.configure()
tf.compare_config_files(["edalize_gowin_template.tcl"])
24 changes: 24 additions & 0 deletions tests/tools/gowin/edalize_gowin_template.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
set_device dummy_part


add_file -type sdc "sdc_file"
add_file -type verilog "sv_file.sv"
source tcl_file.tcl
add_file -type verilog "vlog_file.v"
add_file -type verilog "vlog_incfile"
add_file -type VHDL_FILE "vhdl_file.vhd"
add_file -type VHDL_FILE "vhdl_lfile"
set_file_prop -lib libx "vhdl_lfile"
add_file -type verilog "another_sv_file.sv"

set_option -top_module top_module
set_option -vhdl_std vhd2008
set_option -verilog_std sysv2017

set_option some
set_option gowin
set_option options


run syn
run pnr
21 changes: 21 additions & 0 deletions tests/tools/gowin/minimal/edalize_gowin_template.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
set_device dummy_part


add_file -type sdc "sdc_file"
add_file -type verilog "sv_file.sv"
source tcl_file.tcl
add_file -type verilog "vlog_file.v"
add_file -type verilog "vlog_incfile"
add_file -type VHDL_FILE "vhdl_file.vhd"
add_file -type VHDL_FILE "vhdl_lfile"
set_file_prop -lib libx "vhdl_lfile"
add_file -type verilog "another_sv_file.sv"

set_option -top_module top_module
set_option -vhdl_std vhd2008
set_option -verilog_std sysv2017



run syn
run pnr

0 comments on commit dc65687

Please sign in to comment.