Simple example on how to generate an Efinity project file to fully use the command line.
It it my understanding that Efinix Efinity 2024.x Python API does not yet support generating XML project files which are required to run a project from the command line. In the supplied simple example below I use a Python script (thanks ChatGPT) to generate the XML project file. The rtl files and constraints are read from a text file.
I use the GUI Interface Designer to generate the interface scripting file (*.isf). You can also use the Efinity Python API to generate an XML periphery file but I think using the GUI is easier as in most cases you only have to do it once. For the next project you simply modify the *.isf file. While you are in the Interface Designer GUI I would also create the SDC file especially if you are using a PLL.
The file for this example is called params.txt and it contains a list of your input files (RTL/SDC/ISF) and some constrains.
# Project info
project.name=led_test
project.description=Simple LED test
# Device info
device.family=Trion
device.device=T20Q100F3
device.timing_model=C4
# Design info
design.def_veri_version=verilog_2k
design.def_vhdl_version=vhdl_2008
design.unified_flow=false
design.top_module=top
design.top_vhdl_arch=rtl
design.design_file1.name=rtl/ledtest.vhd
design.design_file1.library=default
design.design_file2.name=rtl/top.sv
design.design_file2.library=default
# Constraint info
constraint.sdc_file=led_test.pt.sdc
constraint.isf_file=led_test_io.isf
# Synthesis params
synthesis.hdl-loop-limit=20000
# Place_and_route params
place_and_route.optimization_level=TIMING_1
# Bitstream_generation params
bitstream_generation.mode=passive
bitstream_generation.width=1
bitstream_generation.generate_hex=on
H:\GitHub\Efinix_cli>python generate_xml.py
XML file 'generated_project.xml' generated successfully.
H:\GitHub\Efinix_cli>efx_run.bat generated_project.xml --flow compile
Creating H:\GitHub\Efinix_cli\outflow
Running: efx_run_map.py led_test --family Trion --device T20Q100F3 --project_xml H:\GitHub\Efinix_cli\generated_project.xml --output_dir outflow --opt root=top --opt arch=rtl --opt veri_options=verilog_mode=verilog_2k,vhdl_mode=vhdl_2008
map : PASS
Running: efx_run_pt_unified.py led_test Trion T20Q100F3 --output_dir outflow --timing_model C4 --project_xml generated_project.xml
interface : PASS
Running: efx_run_pnr.py led_test --prj --family Trion --device T20Q100F3 --timing_model C4 --sim --output_dir outflow --opt sdc_file=ledtest.sdc --opt optimization_level=TIMING_1
pnr : PASS
Running: efx_run_pgm.py led_test --family Trion --device T20Q100F3 --output_dir outflow --opt mode=passive width=1
pgm : PASS
As of Efinity 2025.1 there is unfortunately no verbose output option for the command line option, this means that when you run efx_run.bat you have to check the various log file in the outflow directory at the end of the run. Luckily Efinix are kind enough to provide the full Python code for efx_run so you can make some changes until Efinix adds this feature.
To stream the warning and errors to both stdout an a log file modify <efinity_install_dir>\2025.1\scripts\efx_run.py
Around line 868 you will find the pre_run(args) function:
# some common preparation steps
def pre_run(args):
# print out stage
print('Running: ' + ' '.join(str(arg) for arg in sys.argv))
# redirect stdout+stderr to log file
sys.stdout = open(args.LOG_FILE, 'a')
sys.stderr = sys.stdout
# print out stage (this time to log)
print('Running: ' + ' '.join(str(arg) for arg in sys.argv))
sys.stdout.flush()
# save the offset to do error logging from here
args.LOG_OFFSET = sys.stdout.tell()
Replace it with the code below:
class TeeOutput: # HABT stream both to stdout/logfile
def __init__(self, log_file_path):
self.file = open(log_file_path, 'a', buffering=1)
self.stdout = sys.stdout
def write(self, message):
self.file.write(message)
self.file.flush()
if not message.startswith("INFO :"):
self.stdout.write(message)
self.stdout.flush()
def flush(self):
self.stdout.flush()
self.file.flush()
def close(self):
self.file.close()
sys.stdout = self.stdout # Restore original stdout
def fileno(self):
return self.file.fileno()
# some common preparation steps
def pre_run(args):
# print out stage
print('Running: ' + ' '.join(str(arg) for arg in sys.argv))
# redirect stdout+stderr to log file
# sys.stdout = open(args.LOG_FILE, 'a')
sys.stdout = TeeOutput(args.LOG_FILE) # HABT stream both to stdout/logfile
sys.stderr = sys.stdout
# print out stage (this time to log)
print('Running: ' + ' '.join(str(arg) for arg in sys.argv))
sys.stdout.flush()
# save the offset to do error logging from here
# args.LOG_OFFSET = sys.stdout.tell()
args.LOG_OFFSET = sys.stdout.file.tell() # HABT stream both to stdout/logfile
Note that it filters out the “INFO” lines for stdout but you add it back by removing the “if not message.startswith…” line.
You should now see all the warnings and errors whilst efx_run is running:
WARNING : Mapping into logic memory block 'U_CPU/U_BIU/U_FIFO/mem__D$2' (64 bits) (H:\HTL32IMC\RTL\syncfifo.vhd:48) because size is too small (<=64) [EFX-0657]
WARNING : Mapping into logic memory block 'U_CPU/U_BIU/U_FIFO/mem__D$b12' (64 bits) (H:\HTL32IMC\RTL\syncfifo.vhd:48) because size is too small (<=64) [EFX-0657]
WARNING : Mapping into logic memory block 'U_CPU/U_BIU/U_FIFO/mem__D$c1' (64 bits) (H:\HTL32IMC\RTL\syncfifo.vhd:48) because size is too small (<=64) [EFX-0657]
WARNING : H:\HTL32IMC\Testbench\rv32sys_struct.vhd(36): Input/inout port RX1 is unconnected and will be removed. [VDB-8003]
WARNING : Found 1 warnings in the post-synthesis netlist.
Stage completed: map
map : PASS
Running: efx_run_pt_unified.py rv32sys Trion T20Q100F3 --output_dir outflow --timing_model C4 --project_xml generated_project.xml
Running: efx_run_pt_unified.py rv32sys Trion T20Q100F3 --output_dir outflow --timing_model C4 --project_xml generated_project.xml
Running: H:/Vendors/Efinity/2025.1\python311\bin\python.exe H:\Vendors\Efinity\2025.1\scripts\efx_run_pt_unified.py rv32sys Trion T20Q100F3 --output_dir outflow --timing_model C4 --project_xml generated_project.xml
Stage completed: interface
interface : PASS
Rather than looking at the report files in the outflow directory you can simply display the relevant info at the end of the run (chatgpt generated Python):
H:\GitHub\Efinix_cli>python results.py outflow/led_test.place.rpt "Resource Summary (begin)" "Resource Summary (end)"
Inputs: 3 / 163 (1.84%)
Outputs: 3 / 347 (0.86%)
Clocks: 1 / 16 (6.25%)
Logic Elements: 26 / 19728 (0.13%)
LE: LUTs/Adders: 25 / 19728 (0.13%)
LE: Registers: 24 / 13920 (0.17%)
Memory Blocks: 0 / 204 (0.00%)
Multipliers: 0 / 36 (0.00%)
H:\GitHub\Efinix_cli>python results.py outflow/led_test.timing.rpt "Frequency Summary (begin)" "Frequency Summary (end)"
User target constrained clocks
Clock Name Period (ns) Frequency (MHz) Waveform Targets
PLL_OUT 1.000 1000.000 {0.000 0.500} {PLL_OUT}
Maximum possible analyzed clocks frequency
Clock Name Period (ns) Frequency (MHz) Edge
PLL_OUT 2.503 399.521 (R-R)
Geomean max period: 2.503
If you want to add/modify any of the parameters in params.txt simply load the generated xml project in the GUI, this will add all(?) parameters to the xml project file. Open the xml file in an editor and extract any parameters you want to use and add them to the parameter file. For example if you want to increase the P&R effort look for:
<efx:param name="placer_effort_level" value="5" value_type="e_option"/>
and update your params.txt with:
place_and_route.placer_effort_level=5
Now put all commands in batch file together with your download utility....