blob: c6c96d5eb7371a031c3422d3b1c35199f8070779 [file] [log] [blame] [edit]
#!/usr/bin/env python3
"""
Utilities for cleaning circuit netlists
"""
import logging
# =============================================================================
def absorb_buffer_luts(netlist, outputs=False):
"""
Performs downstream absorbtion of buffer LUTs. All buffer LUTs are absorbed
except for those that drive top-level output ports not to change output
net names.
Returns a net map that defines the final net remapping after some nets
got absorbed downstream.
"""
INP_PORT = "lut_in[0]"
OUT_PORT = "lut_out"
def is_buffer_lut(cell):
"""
Returns True when a cell is a buffer LUT to be absorbed.
"""
# A pass-through LUT
if cell.type == "$lut" and cell.init == [0, 1]:
# Get input and output nets
assert INP_PORT in cell.ports, cell
net_inp = cell.ports[INP_PORT]
assert OUT_PORT in cell.ports, cell
net_out = cell.ports[OUT_PORT]
# Must not be driving any top-level outputs unless explicitly
# allowed
if (net_inp in netlist.inputs
or net_out in netlist.outputs) and not outputs:
return False
return True
return False
# Identify LUT buffers
buffers = {
key: cell
for key, cell in netlist.cells.items()
if is_buffer_lut(cell)
}
# Merge them downstream
net_map = {}
for cell in buffers.values():
# Get input and output nets
assert INP_PORT in cell.ports, cell
net_inp = cell.ports[INP_PORT]
assert OUT_PORT in cell.ports, cell
net_out = cell.ports[OUT_PORT]
# Cannot be a buffer connecting an input to an output directly
if net_out in netlist.outputs and net_inp in netlist.inputs:
continue
# This cell drives a top-level output directly. Change input nets and
# leave the output one
if net_out in netlist.outputs:
# Replace the output net in all cells with the input one
for c in netlist.cells.values():
for port, net in c.ports.items():
if net == net_inp:
c.ports[port] = net_out
# Update net map
for net in net_map:
if net_map[net] == net_inp:
net_map[net] = net_out
net_map[net_inp] = net_out
# A regular buffer
else:
# Replace the output net in all cells with the input one
for c in netlist.cells.values():
for port, net in c.ports.items():
if net == net_out:
c.ports[port] = net_inp
# Update net map
for net in net_map:
if net_map[net] == net_out:
net_map[net] = net_inp
net_map[net_out] = net_inp
# Remove the cell
del netlist.cells[cell.name]
logging.debug(" Absorbed {} buffer LUTs".format(len(buffers)))
return net_map
def sweep_dangling_cells(netlist):
# TODO:
pass