-
Notifications
You must be signed in to change notification settings - Fork 193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add VTR backend #271
base: main
Are you sure you want to change the base?
Add VTR backend #271
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
# Copyright edalize contributors | ||
# Licensed under the 2-Clause BSD License, see LICENSE for details. | ||
# SPDX-License-Identifier: BSD-2-Clause | ||
|
||
import shutil | ||
from edalize.edatool import Edatool | ||
import logging | ||
import pathlib | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
""" VTR Backend | ||
|
||
To run this you will need to provide at minimum: | ||
- Single Verilog design source (multiple source files not yet supported) | ||
|
||
If VTR is not on your PATH (vtr/vtr_flow/scripts) then you can provide: | ||
- vtr_pth (path to compiled VTR source tree) | ||
|
||
""" | ||
|
||
|
||
class Vtr(Edatool): | ||
@classmethod | ||
def get_doc(cls, api_ver): | ||
if api_ver == 0: | ||
return { | ||
"description": "The VTR backend runs the VTR open-source FPGA CAD tool, consisting of synthesis, tech mapping, packing, placement and routintg.", | ||
"members": [ | ||
{ | ||
"name": "vtr_path", | ||
"type": "String", | ||
"desc": "The path to the VTR tool installation", | ||
}, | ||
{ | ||
"name": "route_chan_width", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace this with a vtr_options list instead so that we don't need to update the backend if there are more options we want to support eventually There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK will do. |
||
"type": "Integer", | ||
"desc": "Routing channel width. If not provided, a minimum channel width will be determined, and then a relaxation factor will be added.", | ||
}, | ||
], | ||
} | ||
|
||
def configure_main(self): | ||
commands = self.EdaCommands() | ||
work_root = pathlib.Path(self.work_root) | ||
|
||
|
||
############ Find VTR Tool ############# | ||
vtr_path = None | ||
run_vtr_flow_py_path = "run_vtr_flow.py" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we want to replace the |
||
|
||
# Check for vtr_path tool_option | ||
if "vtr_path" in self.tool_options: | ||
vtr_path = pathlib.Path(self.tool_options["vtr_path"]) | ||
|
||
# Make sure vtr_path points to a directory with a run_vtr_flow.py | ||
# script in the correct location | ||
run_vtr_flow_py_path = vtr_path / "vtr_flow" / "scripts" / "run_vtr_flow.py" | ||
if not run_vtr_flow_py_path.is_file(): | ||
logger.warning("vtr_path invalid (" + str(run_vtr_flow_py_path) + " does not exist)") | ||
|
||
############ Parse all files ############# | ||
|
||
# Default files | ||
verilog_path = None | ||
if vtr_path: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this file default? I don't know much about vtr internals but it looks to me like it's a specific chip. I would prefer to require the user to specify a valid chip themselves. This ties into a bigger question about these XML files. Depending on how Edalize is used, it's not certain that the user can know the path to these files. Most users of EDA tools are expecting to just tell the EDA tool which chip they are targeting and let the tools handle the rest. After speaking to @kgugala about how these xml files work in symbiflow, I did a quick hack (https://gist.github.com/olofk/0f3911e7fa1028cc4c445bb2039ba06e) that makes it possible to programmatically get the official arch description files for a certain chip. I understand though that there is a need for certain types of users to override this file, but in this case I propose adding that as a tool option instead that these users can set by themselves. Generatlly, things that go in the files section of the EDAM format are those that are design-specific, not specific to a tool installation path There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is a common "basic" FPGA architecture in VTR. I don't have to provide a default. I was just providing a default with the belief that it should work with minimum number of settings provided (for example the Xilinx backend works without providing a part # -- but perhaps that is a feature of Xilinx, and not a intended feature of Edalize).
I see the concern here, but I'm not sure it completely applies to VTR. While Symbiflow (which uses VTR) targets real parts, the current version of VTR is more about targeting hypothetical architectures. These don't describe actual parts, but rather an architecture family. For example, the default behavior of VTR is to automatically size a chip based on the input design, so the user is often not dealing with actual "parts". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You do have a point about the Xilinx backend. I use that feature occasionally myself when I just want to do a quick synthesis test and don't really care exactly which chip I'm targeting. My only remaining worry is if vtr itself would settle upon a default which would differ from what we do in Edalize. I tend to be quite careful about adding defaults for that reason. But then again, I'm not (yet) a VTR user myself, so I'll leave the decision of setting this as the default arch to you. The remaining issue then is how the user would get this arch description. Is it always shipped with vtr or does the user need to find it themselves? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See question above re arch files. I'm fine requiring the user to provide an architecture file; you make a good point about VTR not having a default architecture yet. |
||
arch_path = vtr_path / "vtr_flow" / "arch" / "timing" / "k6_N10_mem32K_40nm.xml" | ||
else: | ||
arch_path = pathlib.Path("k6_N10_mem32K_40nm.xml") | ||
|
||
# Check all input file types | ||
for f in self.files: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does VTR only support verilog netlists, or is e.g. blif intended to be supported as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. blif is an intermediate format in the VTR flow, and it's possible to provide a blif and skip the front-end of the VTR flow. I was planning to add that in the future, but I could do that now if it's important. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's fine. Better to add more features later as you had planned. Was just making sure I wasn't missing anything |
||
if f["file_type"].startswith("verilogSource"): | ||
if verilog_path: | ||
logger.warning("Ignoring extra Verilog file", f) | ||
else: | ||
verilog_path = pathlib.Path(f["name"]) | ||
elif f["file_type"] == "vtr_arch": | ||
arch_path = pathlib.Path(f["name"]) | ||
else: | ||
logger.warning("Unsupported file " + str(f)) | ||
|
||
# Validate verilog file exists | ||
if verilog_path is None: | ||
logger.error("Missing required Verilog source file") | ||
return | ||
elif not verilog_path.is_file(): | ||
logger.warning("Verilog source file " + str(verilog_path) + " does not exist") | ||
|
||
# Validate arch file exists | ||
if not arch_path.is_file(): | ||
logger.warning("Architecture XML file " + str(arch_path) + " does not exist.") | ||
|
||
############ Build Makefile ############# | ||
|
||
# Build Makefile for running run_vtr_flow.py | ||
route_file_path = pathlib.Path("temp") / (self.name + ".route") | ||
|
||
# Default vtr_flow runner | ||
cmd = [ | ||
str(run_vtr_flow_py_path), | ||
str(verilog_path), | ||
str(arch_path), | ||
] | ||
if "route_chan_width" in self.tool_options: | ||
cmd += ["--route_chan_width", str(self.tool_options["route_chan_width"])] | ||
commands.add(cmd, [str(route_file_path)], ()) | ||
|
||
commands.set_default_target(str(route_file_path)) | ||
commands.write(str(work_root / "Makefile")) | ||
|
||
def build_main(self): | ||
logger.info("Building") | ||
|
||
self._run_tool("make", quiet=True) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#!/usr/bin/env python3 | ||
import sys | ||
|
||
with open('run_vtr_flow.py.cmd', 'a') as f: | ||
f.write(' '.join(sys.argv[1:]) + '\n') |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import pytest | ||
import sys | ||
|
||
from edalize_common import make_edalize_test | ||
|
||
|
||
def test_vtr(make_edalize_test): | ||
tf = make_edalize_test('vtr') | ||
|
||
tf.backend.configure() | ||
tf.compare_files(['Makefile']) | ||
|
||
tf.backend.build() | ||
tf.compare_files(['run_vtr_flow.py.cmd']) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#Auto generated by Edalize | ||
|
||
all: temp/test_vtr_0.route | ||
|
||
temp/test_vtr_0.route: | ||
$(EDALIZE_LAUNCHER) run_vtr_flow.py vlog_file.v k6_N10_mem32K_40nm.xml |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
vlog_file.v k6_N10_mem32K_40nm.xml |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is better handled through the EDALIZE_LAUNCHER mechanism. Yes, it's a bit more tedious for the users but I also think it's more flexible and in line with the other tools
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I'll take a look at EDALIZE_LAUNCHER
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize I didn't give much context here and I also haven't properly documented this feature. The idea is that all calls to EDA tools is prefixed by
$EDALIZE_LAUNCHER
. Normally this variable is unset and the tool will just be called normally.By setting EDALIZE_LAUNCHER we can run a command where the rest of the command-line becomes arguments to this command. A neat use case is setting EDALIZE_LAUNCHER to this script. By doing that we will seamlessly launch containerized versions of the supported tools. In your case, I think you could set EDALIZE_LAUNCHER to
PATH=/path/to/vtr:$PATH
so that the the path to where your tools is located will get added to the PATH variable priior to launching.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I tried out this suggestion and it seemed to work well. I had to set it like so (with quotes and $$):
export EDALIZE_LAUNCHER='PATH=/path/to/vtr:$$PATH'
The only issue is related to your question below:
The normal use case is to use an xml architecture file provided by VTR. These are typically located within <vtr_installation>/vtr_flow/arch. If I forgo the "vtr_path" tool_option and use the EDALIZE_LAUNCHER mechanism, then users are forced to provide the full hard-coded path to the architecture file in the VTR installation.
Alternatively with "vtr_path", users could provide the arch file as a path relative to the installation directory. Thoughts?
I like the EDALIZE_LAUNCHER mechanism, and I don't mind requiring full paths for arch files, just wondering if you have a better solution in mind.