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
list
to TCL list - Result from invoked TCL procedure is returned as
pytcl.TCLValue
that 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
PyTCL
class for that - It supports Linux, macOS and Windows
- No external dependencies
pip install pytcl-eda
Creating 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()
PyTCL
will run tool withexecute.tcl <address>
arguments in separate processexecute.tcl
invoked by tool will invokeexecute.py
execute.py
will start new connection listener on provided<address>
PyTCL
will try connect to<address>
as clientPyTCL
will transform any Python method call<object>.<name>(*args)
to TCL expression<name> {*}${args}
PyTCL
will send TCL expression as string toexecute.py
via<address>
execute.py
will print received TCL expression to standard outputstdout
execute.tcl
will capture received TCL expression fromexecute.py
using standard inputstdin
execute.tcl
will evaluate received TCL expressionexecute.tcl
will print result of evaluated TCL expression back toexecute.py
using standard outputstdout
in form of NDJSON{"result": "<tcl-result>", "status": <tcl-status>}
execute.py
will capture above result using standard inputstdin
and send it back toPyTCL
PyTCL
will return received NDJSON message aspytcl.TCLValue
PyTCL
will raise a Python exceptionpytcl.TCLError
if 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