From f83a8b35b3fe7621d8e38a831203d56bc992a961 Mon Sep 17 00:00:00 2001 From: Olof Kindgren Date: Tue, 21 Nov 2023 15:50:05 +0100 Subject: [PATCH] Fix flow API docs --- doc/conf.py | 91 ++++++++++++++++++++++++++++++++++++++++- doc/edam/api.rst | 17 +++++++- doc/edam/efinity.gv | 5 +++ doc/edam/f4pga.gv | 13 ++++++ doc/edam/generic.gv | 5 +++ doc/edam/gls.gv | 6 +++ doc/edam/icestorm.gv | 14 +++++++ doc/edam/lint.gv | 3 ++ doc/edam/sim.gv | 5 +++ doc/edam/vivado.gv | 12 ++++++ doc/edam/vpr.gv | 8 ++++ edalize/edatool.py | 4 +- edalize/flows/vivado.py | 4 +- 13 files changed, 181 insertions(+), 6 deletions(-) create mode 100644 doc/edam/efinity.gv create mode 100644 doc/edam/f4pga.gv create mode 100644 doc/edam/generic.gv create mode 100644 doc/edam/gls.gv create mode 100644 doc/edam/icestorm.gv create mode 100644 doc/edam/lint.gv create mode 100644 doc/edam/sim.gv create mode 100644 doc/edam/vivado.gv create mode 100644 doc/edam/vpr.gv diff --git a/doc/conf.py b/doc/conf.py index ab19c81d6..f04d9e592 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -44,6 +44,7 @@ # ones. extensions = [ "sphinx.ext.autodoc", + "sphinx.ext.graphviz", "sphinx.ext.viewcode", "sphinx.ext.napoleon", "sphinx_autodoc_typehints", @@ -211,5 +212,93 @@ from edalize.edatool import gen_tool_docs s = gen_tool_docs() -with open(os.path.join(os.path.abspath("."), "edam/tools.rst"), "w") as f: +with open(os.path.join(os.path.abspath("."), "edam/legacytools.rst"), "w") as f: f.write(s) + +from importlib import import_module +from pkgutil import iter_modules + +import edalize.flows + + +def make_rst_table(options): + s = "" + lines = [] + name_len = 10 + type_len = 4 + for name, item in options.items(): + _type = item["type"] + if item.get("list"): + _type = "List of " + _type + name_len = max(name_len, len(name)) + type_len = max(type_len, len(_type)) + lines.append((name, _type, item["desc"])) + + s += "=" * name_len + " " + "=" * type_len + " " + "=" * 11 + "\n" + s += "Field Name".ljust(name_len + 1) + "Type".ljust(type_len + 1) + "Description\n" + s += "=" * name_len + " " + "=" * type_len + " " + "=" * 11 + "\n" + for line in lines: + s += line[0].ljust(name_len + 1) + s += line[1].ljust(type_len + 1) + s += line[2] + s += "\n" + s += "=" * name_len + " " + "=" * type_len + " " + "=" * 11 + "\n" + return s + + +def iter_namespace(ns_pkg): + # Specifying the second argument (prefix) to iter_modules makes the + # returned name an absolute name instead of a relative one. This allows + # import_module to work without having to do additional modification to + # the name. + return iter_modules(ns_pkg.__path__, ns_pkg.__name__ + ".") + + +discovered_plugins = { + name: import_module(name) for finder, name, ispkg in iter_namespace(edalize.flows) +} + +s = "" +table = {} +for k, v in discovered_plugins.items(): + name = k.split(".")[-1] + if name == "edaflow": + continue + + table[name] = { + "type": f"`{name.capitalize()} flow`_", + "desc": name + "-specific options", + } + _class = getattr(v, name.capitalize()) + s += "\n{} flow\n{}\n\n".format(name.capitalize(), "~" * (len(name) + 5)) + s += _class.__doc__ + "\n\n" + s += f".. graphviz:: {name}.gv\n\n" + s += make_rst_table(_class.get_flow_options()) + +with open(os.path.join(os.path.abspath("."), "edam/flows.rst"), "w") as f: + f.write(s) # make_rst_table(table)+s) + +import edalize.tools + +discovered_plugins = { + name: import_module(name) for finder, name, ispkg in iter_namespace(edalize.tools) +} + +s = "" +table = {} +for k, v in discovered_plugins.items(): + name = k.split(".")[-1] + if name == "edatool": + continue + + table[name] = { + "type": f"`{name.capitalize()} tool`_", + "desc": name + "-specific options", + } + _class = getattr(v, name.capitalize()) + s += "\n{} tool\n{}\n\n".format(name.capitalize(), "~" * (len(name) + 5)) + s += (_class.__doc__ or _class.description) + "\n\n" + s += make_rst_table(_class.get_tool_options()) + +with open(os.path.join(os.path.abspath("."), "edam/tools.rst"), "w") as f: + f.write(s) # make_rst_table(table)+s) diff --git a/doc/edam/api.rst b/doc/edam/api.rst index b6be0ba79..d118d41f7 100644 --- a/doc/edam/api.rst +++ b/doc/edam/api.rst @@ -11,6 +11,7 @@ Field Name Type Description dependencies Dict of `Dependency`_ Direct dependencies of each core that is contained in the EDAM. files List of `File`_ Contains all the HDL source files, constraint files, vendor IP description files, memory initialization files etc. for the project. +flow_options `Flow Options`_ A dictionary of tool- and flow-specific options. Used by the Flow API hooks `Hook`_ A dictionary of extra commands to execute at various stages of the project build/run. name String **Required** Name of the project parameters Dict of `Parameter`_ Specifies build- and run-time parameters, such as plusargs, VHDL generics, Verilog defines etc. @@ -48,6 +49,7 @@ File A file has a name, which is the absolute path or the relative path to the working directory. It also has a type, which describes the intended usage of the file. Different EDA tools handle different subsets of files and are expected to ignore files that are not applicable to them, but might issue a warning. By specifying *user* as the file type, the backends will explicitly ignore the file. The valid file types are based on the IP-XACT 2014 standard, with some additional file types added. The file types not covered by IP-XACT are listed below + - QIP : Intel Quartus IP file - UCF : Xilinx ISE constraint file - verilogSource-2005 : Verilog 200 source @@ -66,6 +68,19 @@ include_path String When is_include_file is true, the director logical_name String Logical name (e.g. VHDL/SystemVerilog library) of the file =============== ===================== =========== +Flow options +------------ + +The flow API consists of two layers. The *flow* defines how different *tools* are interconnected to perform a task. The topology of the flows can be very different. A simulation flow might consist of a single simulation tool. An FPGA flow might be built up from a synthesis tool followed by a place & route tool and finally some tool to convert into a device-specific FPGA image (bitstream). A gate-level simulation flow could be created with a synthesis tool feeding its output into a simulator. + +This also means that configuring the flow consists of two types of options. The flow options listed for each flow below defines the topology. Depending on which tools that get pulled into the flow graph, additional tool-specific flow options becomes available as well. In addition, some tool-specific options might be hardcoded by the flow. If e.g. yosys is used in the Vivado flow, the architecture will always be set to *xilinx* and the output format will always be *edf* since that's what Vivado expects for its post-synthesis activities. Below is listed the flow options for each flow as well as the tool options for each tool. In order to programatically see what options are available for a specific flow configuration, first run ``get_flow_options()`` to get the available flow options. Assign values to any flow options of interest and then run ``get_tool_options(assigned_flow_options)`` with a dict containing the flow options and their values to see what tool options are available for this particular flow configuration. + +The global flow options and options for each tool both goes into the ``flow_options`` section in the EDAM description. + +.. include:: flows.rst + +.. include:: tools.rst + Hook ---- @@ -118,7 +133,7 @@ paramtype String **Required** Type of parameter. Valid valu Tool options ------------ -.. include:: tools.rst +.. include:: legacytools.rst VPI --- diff --git a/doc/edam/efinity.gv b/doc/edam/efinity.gv new file mode 100644 index 000000000..b03812805 --- /dev/null +++ b/doc/edam/efinity.gv @@ -0,0 +1,5 @@ +digraph G { +"$project.bit" [shape=box,style=filled] +frontends -> efinity; +efinity -> "$project.bit"; +} \ No newline at end of file diff --git a/doc/edam/f4pga.gv b/doc/edam/f4pga.gv new file mode 100644 index 000000000..c248fe3ed --- /dev/null +++ b/doc/edam/f4pga.gv @@ -0,0 +1,13 @@ +digraph G { +yosysblif [label="yosys\noutput_format=blif"] +nextpnr [label="nextpnr\narch=ice40"] +"$project.bit" [shape=box,style=filled] + +frontends -> yosysjson[label="pnr==nextpnr "]; +frontends -> yosyseblif[label="pnr==vpr "]; +yosysjson -> nextpnr; +yosyseblif -> vpr; +vpr -> genfasm; +genfasm -> xcfasm; +xcfasm -> "$project.bit"; +} \ No newline at end of file diff --git a/doc/edam/generic.gv b/doc/edam/generic.gv new file mode 100644 index 000000000..ac84e934f --- /dev/null +++ b/doc/edam/generic.gv @@ -0,0 +1,5 @@ +digraph G { +"?" [shape=box,style=filled] +frontends -> "$tool"; +"$tool" -> "?"; +} \ No newline at end of file diff --git a/doc/edam/gls.gv b/doc/edam/gls.gv new file mode 100644 index 000000000..3463bf3ea --- /dev/null +++ b/doc/edam/gls.gv @@ -0,0 +1,6 @@ +digraph G { +"model" [shape=box,style=filled,label="Simulation model"] +frontends -> "$synth"; +"$synth" -> "$sim"; +"$sim" -> "model"; +} \ No newline at end of file diff --git a/doc/edam/icestorm.gv b/doc/edam/icestorm.gv new file mode 100644 index 000000000..ed5dc97a1 --- /dev/null +++ b/doc/edam/icestorm.gv @@ -0,0 +1,14 @@ +digraph G { +"$project.bit" [shape=box,style=filled] +"$project.json" [shape=box,style=filled] +yosys [label="yosys\narch=ice40\noutput_format=json"] +nextpnr [label="nextpnr\narch=ice40"] + +frontends -> yosys; +yosys -> nextpnr; +yosys -> "$project.json" [label="pnr==none"]; +nextpnr -> icetime; +nextpnr -> icebox_stat; +nextpnr -> icepack; +icepack -> "$project.bit"; +} \ No newline at end of file diff --git a/doc/edam/lint.gv b/doc/edam/lint.gv new file mode 100644 index 000000000..5670e242c --- /dev/null +++ b/doc/edam/lint.gv @@ -0,0 +1,3 @@ +digraph G { +frontends -> "$tool"; +} \ No newline at end of file diff --git a/doc/edam/sim.gv b/doc/edam/sim.gv new file mode 100644 index 000000000..fb0fb81f6 --- /dev/null +++ b/doc/edam/sim.gv @@ -0,0 +1,5 @@ +digraph G { +"model" [shape=box,style=filled,label="Simulation model"] +frontends -> "$tool"; +"$tool" -> "model"; +} \ No newline at end of file diff --git a/doc/edam/vivado.gv b/doc/edam/vivado.gv new file mode 100644 index 000000000..44f47d1ad --- /dev/null +++ b/doc/edam/vivado.gv @@ -0,0 +1,12 @@ +digraph G { +yosys [label="yosys\narch=xilinx\noutput_format=edif"] +vpnr [label="vivado\nsynth=none"] +"$project.bit" [shape=box,style=filled] +"$project.v" [shape=box,style=filled] +frontends -> yosys[label="synth==yosys "]; +frontends -> "vivado"[label="synth!=yosys"]; +yosys -> "vpnr"; +vivado -> "$project.v"[label="pnr==none"]; +vivado -> "$project.bit"[label="pnr!=none"]; +"vpnr" -> "$project.bit"; +} \ No newline at end of file diff --git a/doc/edam/vpr.gv b/doc/edam/vpr.gv new file mode 100644 index 000000000..f57bb92da --- /dev/null +++ b/doc/edam/vpr.gv @@ -0,0 +1,8 @@ +digraph G { +yosysblif [label="yosys\noutput_format=blif"] +"$project.analysis" [shape=box,style=filled] + +frontends -> yosysblif; +yosysblif -> vpr; +vpr -> "$project.analysis"; +} \ No newline at end of file diff --git a/edalize/edatool.py b/edalize/edatool.py index e865a0c90..bfeb3abec 100644 --- a/edalize/edatool.py +++ b/edalize/edatool.py @@ -568,12 +568,12 @@ def gen_tool_docs(): table.append( { "name": name.lower(), - "type": "`" + name + "`_", + "type": "`" + name + " backend`_", "desc": name + "-specific options", } ) - s += "\n{}\n{}\n\n".format(name, "~" * len(name)) + s += "\n{} backend\n{}\n\n".format(name, "~" * (len(name) + 8)) s += _class_doc(backend.get_doc(0)) return ( diff --git a/edalize/flows/vivado.py b/edalize/flows/vivado.py index e0fbef78d..a020c578e 100644 --- a/edalize/flows/vivado.py +++ b/edalize/flows/vivado.py @@ -8,7 +8,7 @@ class Vivado(Edaflow): - """The Vivado backend executes Xilinx Vivado to build systems and program the FPGA""" + """The Vivado flow executes AMD Vivado to create a bitstream and optionally program a board. Yosys can be used for synthesis by setting the synth option accordingly""" argtypes = ["vlogdefine", "vlogparam"] @@ -19,7 +19,7 @@ class Vivado(Edaflow): FLOW_OPTIONS = { "frontends": { "type": "str", - "desc": "Tools to run before yosys (e.g. sv2v)", + "desc": "Tools to run before Vivado (e.g. sv2v)", "list": True, }, "pgm": {