python-3.xsubprocesstcllattice-diamond

Lattice Diamond command line tool doesn't know 'synthesis' command


I have a (free) Lattice Diamond 3.7 installation on Windows 7 and I would like to run synthesis jobs from command line. I generated a *.prj file containing all relevant command line options, like part, toplevel and all source files.

Then I started pnmainc.exe from my PowerShell and executed: synthesis -f arith_prng.prj

-a "ECP5UM"
-top arith_prng
-logfile D:\git\PoC\temp\lattice\arith_prng.lse.log
-lib poc
-vhd D:/git/PoC/tb/common/my_project.vhdl
-vhd D:/git/PoC/tb/common/my_config_KC705.vhdl
-vhd D:/git/PoC/src/common/utils.vhdl
-vhd D:/git/PoC/src/common/config.vhdl
-vhd D:/git/PoC/src/common/math.vhdl
-vhd D:/git/PoC/src/common/strings.vhdl
-vhd D:/git/PoC/src/common/vectors.vhdl
-vhd D:/git/PoC/src/common/physical.vhdl
-vhd D:/git/PoC/src/common/components.vhdl
-vhd D:/git/PoC/src/arith/arith.pkg.vhdl
-vhd D:/git/PoC/src/arith/arith_prng.vhdl

The synthesis process started and finished. Next I tried to achieve the same behavior with a wrapping Python script, controlling STDIN and STDOUT of a subprocess.

I can execute some commands, but synthesis is reported as unknown command. It's not listed in help. I assume, that's because synthesis.exe is an external program.

For example, if I send help, then all help topics are displayed.

What can I do to run Tcl commands for Diamond from Python?

That's my Python code for experimenting on a Tcl-Shell wrapper.

from subprocess      import Popen    as Subprocess_Popen
from subprocess      import PIPE      as Subprocess_Pipe
from subprocess      import STDOUT    as Subprocess_StdOut

class Executable:
  _POC_BOUNDARY = "====== POC BOUNDARY ======"

  def __init__(self, executablePath):
    self._process =    None
    self._executablePath =    executablePath

  @property
  def Path(self):
    return self._executablePath

  def StartProcess(self, parameterList):
    parameterList.insert(0, str(self._executablePath))
    self._process = Subprocess_Popen(parameterList, stdin=Subprocess_Pipe, stdout=Subprocess_Pipe, stderr=Subprocess_StdOut, universal_newlines=True, bufsize=16, shell=True)

  def Send(self, line):
    print("  sending command: {0}".format(line))
    self._process.stdin.write(line + "\n")
    self._process.stdin.flush()

  def SendBoundary(self):
    print("  sending boundary")
    self.Send("puts \"{0}\"\n".format(self._POC_BOUNDARY))

  def GetReader(self):
    for line in iter(self._process.stdout.readline, ""):
      yield line[:-1]

tclShell = Executable(r"D:\Lattice\diamond\3.7_x64\bin\nt64\pnmainc.exe")
print("starting process: {0!s}".format(tclShell.Path))
tclShell.StartProcess([])
reader = tclShell.GetReader()
iterator = iter(reader)

# send boundary and wait until pnmainc.exe is ready
tclShell.SendBoundary()
for line in iterator:
  print(line)
  if (line == tclShell._POC_BOUNDARY):
    break
print("pnmainc.exe is ready...")

tclShell.Send("help")
tclShell.SendBoundary()
for line in iterator:
  print(line)
  if (line == tclShell._POC_BOUNDARY):
    break
print("pnmainc.exe is ready...")

tclShell.Send("synthesis -f arith_prng.prj")
tclShell.SendBoundary()
for line in iterator:
  print(line)
  if (line == tclShell._POC_BOUNDARY):
    break
print("pnmainc.exe is ready...")

print("exit program")
tclShell.Send("exit")
print("reading output")
for line in iterator:
  print(line)

print("done")

Solution

  • To run a synthesis, there is no need for TCL scripting with pnmainc. You can directly run the synthesizer binary as follows.

    Windows

    The synthesises.exe must be run from a command shell with all necessary Lattice environment variables. The environment is setup by an executable called pnwrap.exe in the bin/nt64 directory. In your example, this executable must be called as follows from a shell:

    D:\Lattice\diamond\3.7_x64\bin\nt64\pnwrap.exe -exec D:\Lattice\diamond\3.7_x64\ispfpga\bin\nt64\synthesis.exe -f arith_prng.prj
    

    The -exec parameter specifies the executable to run in the Lattice environment. All following arguments are passed to synthesis.exe.

    From within Python, you can run the synthesizer with (using your Executable class):

    exe = Executable(r"D:\Lattice\diamond\3.7_x64\bin\nt64\pnwrap.exe")
    parameterList = ['-exec', r"D:\Lattice\diamond\3.7_x64\ispfpga\bin\nt64\synthesis.exe", '-f', 'arith_prng']
    exe.StartProcess(parameterList)
    

    Unfortunately, pnwrap.exe opens a new command shell window to setup the environment. Thus, the output cannot be redirected via a pipe. But, the log will also be found in the log-file specified in the .prj file.

    Linux

    At first, you will have to load the Lattice Diamond environment to setup all necessary environment variables. With Bash syntax, this will be:

    bindir=/opt/lattice/diamond/3.7_x64/bin/lin64
    source $bindir/diamond_env
    

    Then, you can directly execute synthesis from the ispfpga/bin/lin64 directory with a command line as in your example:

    synthesis -f arith_prng.prj
    

    The synthesis executable will be found in $PATH.

    From within Python, you can run the synthesizer with (using your Executable class):

    exe = Executable('/opt/lattice/diamond/3.7_x64/ispfpga/bin/lin64/synthesis')
    parameterList = ['-f', 'arith_prng']
    exe.StartProcess(parameterList)