PyTCL allows control EDA tools directly from Python that use TCL.
- It executes Python method with provided positional arguments directly as TCL procedure
For example invocation of Python
<object>.<name>(*args)method is like calling TCL procedure<name> {*}${args} - Any Python value is converted to TCL value like for example Python
listto TCL list - Result from invoked TCL procedure is returned as
pytcl.TCLValuethat can handle any TCL value (that is represented always as string) to Pythonstr,int,bool,float,list,dict, ... - TCL error is returned as Python exception
pytcl.TCLError - High performance and very low (unnoticeable) overhead by using Unix domain sockets or Windows named pipes for communication between Python and TCL in streamable way (sockets/pipes are always open and ready)
- It allows to create and access TCL variables from Python side. Please see tests/test_tclsh.py for some examples
- It can work with any EDA tool. Please see tests/test_vivado.py how to use bare
PyTCLclass for that - It supports Linux, macOS and Windows
- No external dependencies
pip install pytcl-edaCreating new Vivado project:
#!/usr/bin/env python3
from pathlib import Path
from pytcl import Vivado
def main() -> None:
"""Create new Vivado project."""
hdl_dir: Path = Path.cwd() / "hdl"
project_dir: Path = Path.cwd() / "my-awesome-project"
with Vivado() as vivado:
# See Vivado Design Suite Tcl Command Reference Guide (UG835) for all available Vivado TCL procedures
# https://docs.amd.com/r/en-US/ug835-vivado-tcl-commands
vivado.create_project(project_dir.name, project_dir)
vivado.add_files(hdl_dir / "my_awesome_design.sv")
synthesis_runs = list(vivado.get_runs("synth_*"))
vivado.launch_runs(synthesis_runs)
# wait_on_runs was introduced in Vivado 2021.2. For backward compatibility we will use wait_on_run
# https://docs.amd.com/r/2021.2-English/ug835-vivado-tcl-commands/wait_on_runs
# Vivado >= 2021.2 can just use: vivado.wait_on_runs(synthesis_runs)
for run in synthesis_runs:
vivado.wait_on_run(run)
implementation_runs = list(vivado.get_runs("impl_*"))
vivado.launch_runs(implementation_runs)
for run in implementation_runs:
vivado.wait_on_run(run)
vivado.close_project()
if __name__ == "__main__":
main()To use any EDA tool where PyTCL doesn't provide neat helper classes like pytcl.Vivado
you can use the pytcl.PyTCL class directly:
#!/usr/bin/env python3
from pathlib import Path
from pytcl import PyTCL
def main() -> None:
"""Create new Vivado project."""
project_dir: Path = Path.cwd() / "my-awesome-project"
# PyTCL offers some string placeholders {} that you can use:
# {tcl} -> it will insert <pytcl>/execute.tcl
# {address} -> it will insert Unix socket, Windows named pipe or network address
cmd: list[str] = [
"vivado",
"-nojournal",
"-notrace",
"-nolog",
"-mode",
"batch",
"-source",
"{tcl}",
"-tclargs",
"{address}",
]
with PyTCL(*cmd) as vivado:
vivado.create_project(project_dir.name, project_dir)
# Do the same magic that you would normally do in TCL
vivado.close_project()
if __name__ == "__main__":
main()stateDiagram-v2
direction LR
PyTCL --> connection: send()
connection --> execute.py: string
state tool {
execute.py --> execute.tcl: stdin
execute.tcl --> execute.py: stdout
}
execute.py --> connection: NDJSON
connection --> PyTCL: recv()
PyTCLwill run tool withexecute.tcl <address>arguments in separate processexecute.tclinvoked by tool will invokeexecute.pyexecute.pywill start new connection listener on provided<address>PyTCLwill try connect to<address>as clientPyTCLwill transform any Python method call<object>.<name>(*args)to TCL expression<name> {*}${args}PyTCLwill send TCL expression as string toexecute.pyvia<address>execute.pywill print received TCL expression to standard outputstdoutexecute.tclwill capture received TCL expression fromexecute.pyusing standard inputstdinexecute.tclwill evaluate received TCL expressionexecute.tclwill print result of evaluated TCL expression back toexecute.pyusing standard outputstdoutin form of NDJSON{"result": "<tcl-result>", "status": <tcl-status>}execute.pywill capture above result using standard inputstdinand send it back toPyTCLPyTCLwill return received NDJSON message aspytcl.TCLValuePyTCLwill raise a Python exceptionpytcl.TCLErrorif received TCL status was non-zero
Create Python virtual environment:
python3 -m venv .venv
Activate created Python virtual environment:
. .venv/bin/activate
Upgrade pip:
pip install --upgrade pip
Install project in editable mode with pytest:
pip install --editable .[test]
Run tests:
pytest