|
| 1 | +# Blif Importer |
| 2 | + |
| 3 | + |
| 4 | +The BLIF Importer is a binary that reads a BLIF file and generates a corresponding Synth dialect circuit inside an `hw.module`. It serves as a standalone entry point for importing externally synthesized logic directly into Dynamatic's IR. |
| 5 | + |
| 6 | +This code interprets each BLIF model as an AIG-style circuit composed of 1-bit registers and AND-with-inverter gates, and re-expresses it directly in the Synth dialect while preserving the instance’s interface. |
| 7 | + |
| 8 | +--- |
| 9 | + |
| 10 | +## Code Structure |
| 11 | + |
| 12 | +The binary `import-blif` can be called as follows: |
| 13 | +```bash |
| 14 | +./bin/export-blif <output-mlir-file> <intput-blif-file> |
| 15 | +``` |
| 16 | + |
| 17 | +where `output-mlir-file` is the file that will contain the Synth circuit to be imported and `input-blif-file` is the file containing imported BLIF. |
| 18 | + |
| 19 | +The code core function is `importBlifCircuit(moduleOp, loc, blifFilePath)` which imports the blif specified in `blifFilePath` in the module operation `moduleOp`. |
| 20 | + |
| 21 | +This function executes the following steps: |
| 22 | + |
| 23 | +1. Extract the module name, input and output port names of the module from the BLIF file using the `getBlifModuleHeader` function. |
| 24 | +2. Create an hw module operation `hw.HWModuleOp` with input and output ports corresponding to the one of the model described in the BLIF file using the `createHWModuleShell`. |
| 25 | +3. Create all synth operations inside the `hw.HWModuleOp` using the function `populateHWModuleShell`. Then, attach all the outputs of the synth circuit to the terminator of the `hw.HWModuleOp`. |
| 26 | + |
| 27 | +--- |
| 28 | + |
| 29 | +## Support Functions |
| 30 | + |
| 31 | +In this subsection of the doc, we highlight the key support functions. |
| 32 | + |
| 33 | + |
| 34 | +### Generate Synth Operations |
| 35 | + |
| 36 | +The core function to generate synth operations is `populateHWModuleShell`. It parses the BLIF body line by line and emits the corresponding Synth operations. It maintains two maps throughout: |
| 37 | + |
| 38 | +- `nodeValuesMap` which maps a BLIF node name to its Synth Value. Pre-populated with all input port signals before parsing begins. |
| 39 | +- `tmpValuesMap` which maps a BLIF node name to a temporary `hw.constant 0` placeholder, created when a node's output is referenced before defining the node. Placeholders are replaced and erased once the real value is available. |
| 40 | + |
| 41 | +**IMPORTANT**: `tmpValuesMap` may contain a large number of temporary `hw` constants which should be cleaned up during synth graph construction. For BLIF generated by tools such as [ABC](https://github.com/berkeley-abc/abc), these temporaries arise primarily from latches since since latches appear at the start of the BLIF file and their inputs are not yet defined at generation time. As a result, performance impact scales mainly with latch count. |
| 42 | + |
| 43 | +It handles two types of units defined in the BLIF: |
| 44 | + |
| 45 | +1. `.latch` from which it parses input node, output node, and oprtional fields (`latchType`, `controlName`, `initVal`). The optional fields follow the BLIF syntax `[type control] [init]` and are decoded based on the number of tokens. A `synth.latch` of type `i1` is created and registered via `updateOutputSynthSignalMapping` in order to record its output value. |
| 46 | +2. `.names` from which it parses the input and output node names and the truth-table function. Depending on the number of node names, the behaviour is different: |
| 47 | + - 1 node name: it is a constant and an `hw.constant` is generated |
| 48 | + - 2 node names: it is a wire or an inverter and it is handled by `createSynthWire` |
| 49 | + - 3+ node names: it is a logic gate and it is handled by `createSynthLogicGate` |
| 50 | + |
| 51 | +After parsing, all the outputs of the synth circuit are appended in the `synthOutputs` variable. |
| 52 | + |
| 53 | + |
| 54 | +### Retrieve the Value of the Input of a BLIF Node |
| 55 | + |
| 56 | +The function that retrieves the input of a synth node is `getInputMappingSynthSignal`. It resolves a BLIF node name to a Synth Value applying the following steps: |
| 57 | + |
| 58 | +1. Return the value from `nodeValuesMap` if already defined. |
| 59 | +2. Return the existing placeholder from `tmpValuesMap` if one exists. |
| 60 | +3. Create a new `hw.constant 0` placeholder, store it in `tmpValuesMap`, and return it. |
| 61 | + |
| 62 | +### Save the Value of the Output of a BLIF Node |
| 63 | + |
| 64 | +The function that saves the MLIR Value corresponding to the output of a BLIF node is `updateOutputSynthSignalMapping`. It registers a newly created Synth value as the definitive signal for a given node name. If a temporary placeholder exists in `tmpValuesMap` for that name, all its uses are replaced with the new value, its defining `hw.constant` op is erased, and it is removed from `tmpValuesMap`. The new value is then recorded in `nodeValuesMap`. |
| 65 | + |
| 66 | +### Create a Wire |
| 67 | + |
| 68 | +The function that creates a wire in the Synth circuit is `createSynthWire`. It handles two-node `.names` blocks. Compares the input and output bits of the truth-table function string (format: "X Y"): |
| 69 | + |
| 70 | +- If equal, the output node is aliased directly to the input value via `updateOutputSynthSignalMapping` and no new op is created. |
| 71 | +- If different, a `synth.aig.and_inv` is created with the input inverted and `ANDed` with a constant 1, effectively modelling a NOT gate. |
| 72 | + |
| 73 | +### Create a Logic Gate |
| 74 | + |
| 75 | +The function that creates a logic gate in the Synth circuit is `createSynthLogicGate`. It handles multi-input `.names` blocks. Currently asserts that exactly 2 inputs are present, reflecting that the code operates on already-binarized AIG-form BLIF. The truth-table function string (format: "XY Z") determines the inversion flags for each input. A `synth.aig.and_inv` is created with the appropriate inversion flags. If the output bit is `0`, a second `synth.aig.and_inv` ANDing with constant 1 and inverting the first input is appended to negate the result. |
| 76 | + |
| 77 | + |
0 commit comments