BLIF Exporter
The BLIF Exporter is an binary that serializes a Synth dialect circuit contained inside hw.module operations into a BLIF file. It serves as the inverse of the BLIF Importer, allowing Dynamatic’s IR to be exported back to a standard BLIF representation for use with external synthesis tools.
Code Structure
The binary export-blif can be called as follows:
./bin/export-blif <input-mlir-file> <output-blif-file>
where input-mlir-file is the file that contains the Synth circuit to be exported and output-blif-file is the file containing the exported BLIF.
The core functionality is the following:
- It iterates over all
hw.HWModuleOpoperations in the module and callsexportBlifCircuiton each of them to generate a BLIF module.
The core function exportBlifCircuit executes the following steps:
- It writes the
.model,.inputs, and.outputslines, and collects all port names into theinputPortsandoutputPortsvectors using thegenerateBlifHeaderfunction. - It iterates over the ops inside the module body and emit the corresponding BLIF statements using the
generateBlifCircuitFromSynthfunction. - Writes the
.endterminator to close the BLIF model.
Support Functions
In this subsection of the doc, we highlight the key support functions.
Generate BLIF Header
The core function that writes the header section of the BLIF file for a given hw.HWModuleOp is generateBlifHeader. It:
- Writes the
.modelline using thehw.modulename. - Iterates over the module’s port list and writes all input ports on the
.inputsline. It populates the vectorinputPortswhich contains the same list. - Iterates over the module’s port list and writes all output ports on the
.outputsline. It populates the vectoroutputPortswhich contains the same list.
Generate BLIF Functionality
The core function that translates the Synth operations inside an hw.HWModuleOp into BLIF statements is generateBlifCircuitFromSynth. It iterates over all ops in the module body and handles three operation types:
-
synth.latch: the function emits a.latchstatement with the format.latch <input> <output> [type control] [init]. The input and output operand names are resolved viagetValueName. Optional fields are emitted only when present: if a control signal exists, the latch type (defaulting to"re"if unset) and control signal name are written; if an init value is set, it is appended. -
synth.aig.and_inv: the function emits a.namesstatement listing both input operand names and the output result name, followed by a truth-table row. Each input position in the row is"0"if that input is inverted and"1"otherwise. -
hw.constant: the function emits a single-node.namesstatement (.names <output>) followed by either1or0on the next line, corresponding to the constant’s value. Only 1-bit constants are supported. -
hw.output: after all ops are processed, the function checks whether any output port is directly connected to an input port (i.e., a pass-through with no Synth op in between). For each such case, a two-node.nameswire statement is emitted (1 1), connecting the input port name to the output port name. At the end, the function asserts that every output port has been accounted for.
Any other operation type is reported as unsupported via an error message.
Value Naming in BLIF
Value names in the BLIF output are resolved by the internal getValueName lambda, which applies the following priority:
- If the value is a block argument (input port), return its name from
inputPortsusing the argument index. - If the value is used as an operand of
hw.output(output port), return its name fromoutputPortsusing the operand index offset by the number of input ports. - Otherwise, print the value using MLIR’s
AsmState(e.g.,%4), strip the leading%, and prependnto produce a valid BLIF node name (e.g.,n4).
This function ensure uniqueness and consistency of names inside a BLIF module.