litex/migen/fhdl/edif.py

218 lines
6.2 KiB
Python

from collections import OrderedDict
from migen.fhdl.std import *
from migen.fhdl.namer import build_namespace
from migen.fhdl.tools import list_special_ios
from migen.fhdl.structure import _Fragment
from collections import namedtuple
_Port = namedtuple("_Port", "name direction")
_Cell = namedtuple("_Cell", "name ports")
_Property = namedtuple("_Property", "name value")
_Instance = namedtuple("_Instance", "name cell properties")
_NetBranch = namedtuple("_NetBranch", "portname instancename")
def _write_cells(cells):
r = ""
for cell in cells:
r += """
(cell {0.name}
(cellType GENERIC)
(view view_1
(viewType NETLIST)
(interface""".format(cell)
for port in cell.ports:
r += """
(port {0.name} (direction {0.direction}))""".format(port)
r += """
)
)
)"""
return r
def _write_io(ios):
r = ""
for s in ios:
r += """
(port {0.name} (direction {0.direction}))""".format(s)
return r
def _write_instantiations(instances, cell_library):
instantiations = ""
for instance in instances:
instantiations += """
(instance {0.name}
(viewRef view_1 (cellRef {0.cell} (libraryRef {1})))""".format(instance, cell_library)
for prop in instance.properties:
instantiations += """
(property {0} (string "{1}"))""".format(prop.name, prop.value)
instantiations += """
)"""
return instantiations
def _write_connections(connections):
r = ""
for netname, branches in connections.items():
r += """
(net {0}
(joined""".format(netname)
for branch in branches:
r += """
(portRef {0}{1})""".format(branch.portname, "" if branch.instancename == "" else " (instanceRef {})".format(branch.instancename))
r += """
)
)"""
return r
def _write_edif(cells, ios, instances, connections, cell_library, design_name, part, vendor):
r = """(edif {0}
(edifVersion 2 0 0)
(edifLevel 0)
(keywordMap (keywordLevel 0))
(external {1}
(edifLevel 0)
(technology (numberDefinition))""".format(design_name, cell_library)
r += _write_cells(cells)
r += """
)
(library {0}_lib
(edifLevel 0)
(technology (numberDefinition))
(cell {0}
(cellType GENERIC)
(view view_1
(viewType NETLIST)
(interface""".format(design_name)
r += _write_io(ios)
r += """
(designator "{0}")
)
(contents""".format(part)
r += _write_instantiations(instances, cell_library)
r += _write_connections(connections)
r += """
)
)
)
)
(design {0}
(cellRef {0} (libraryRef {0}_lib))
(property PART (string "{1}") (owner "{2}"))
)
)""".format(design_name, part, vendor)
return r
def _generate_cells(f):
cell_dict = OrderedDict()
for special in f.specials:
if isinstance(special, Instance):
port_list = []
for port in special.items:
if isinstance(port, Instance.Input):
port_list.append(_Port(port.name, "INPUT"))
elif isinstance(port, Instance.Output):
port_list.append(_Port(port.name, "OUTPUT"))
elif isinstance(port, Instance.InOut):
port_list.append(_Port(port.name, "INOUT"))
elif isinstance(port, Instance.Parameter):
pass
else:
raise NotImplementedError("Unsupported instance item")
if special.of in cell_dict:
if set(port_list) != set(cell_dict[special.of]):
raise ValueError("All instances must have the same ports for EDIF conversion")
else:
cell_dict[special.of] = port_list
else:
raise ValueError("Edif conversion can only handle synthesized fragments")
return [_Cell(k, v) for k, v in cell_dict.items()]
def _generate_instances(f,ns):
instances = []
for special in f.specials:
if isinstance(special, Instance):
props = []
for prop in special.items:
if isinstance(prop, Instance.Input):
pass
elif isinstance(prop, Instance.Output):
pass
elif isinstance(prop, Instance.InOut):
pass
elif isinstance(prop, Instance.Parameter):
props.append(_Property(name=prop.name, value=prop.value))
else:
raise NotImplementedError("Unsupported instance item")
instances.append(_Instance(name=ns.get_name(special), cell=special.of, properties=props))
else:
raise ValueError("Edif conversion can only handle synthesized fragments")
return instances
def _generate_ios(f, ios, ns):
outs = list_special_ios(f, False, True, False)
inouts = list_special_ios(f, False, False, True)
r = []
for io in ios:
direction = "OUTPUT" if io in outs else "INOUT" if io in inouts else "INPUT"
r.append(_Port(name=ns.get_name(io), direction=direction))
return r
def _generate_connections(f, ios, ns):
r = OrderedDict()
for special in f.specials:
if isinstance(special, Instance):
instname = ns.get_name(special)
for port in special.items:
if isinstance(port, Instance._IO):
s = ns.get_name(port.expr)
if s not in r:
r[s] = []
r[s].append(_NetBranch(portname=port.name, instancename=instname))
elif isinstance(port, Instance.Parameter):
pass
else:
raise NotImplementedError("Unsupported instance item")
else:
raise ValueError("Edif conversion can only handle synthesized fragments")
for s in ios:
io = ns.get_name(s)
if io not in r:
r[io] = []
r[io].append(_NetBranch(portname=io, instancename=""))
return r
class EDIFConvert:
def __init__(self, f, ios, cell_library, vendor, device, name="top"):
self.cell_library
self.vendor = vendor
self.device = device
self.name = name
if not isinstance(f, _Fragment):
f = f.get_fragment()
if f.comb != [] or f.sync != {}:
raise ValueError("Edif conversion can only handle synthesized fragments")
if ios is None:
ios = set()
cells = _generate_cells(f)
ns = build_namespace(list_special_ios(f, True, True, True))
instances = _generate_instances(f, ns)
inouts = _generate_ios(f, ios, ns)
connections = _generate_connections(f, ios, ns)
self.f = f
self.ios = ios
self.cells = cells
self.ns = ns
self.instances = instances
self.inouts = inouts
self.connections = connections
def __str__(self):
return _write_edif(self.cells, self.inouts, self.instances, self.connections,
self.cell_library, self.name, self.device, self.vendor)
def convert(f, ios, cell_library, vendor, device, name="top", return_ns=False):
return EDIFConvert(f, ios, cell_library, vendor, device, name, return_ns)