blob: 700d02b78d8a930123766f8e1053f7f69deef852 [file] [log] [blame] [edit]
#!/usr/bin/env python3
import lxml.etree as ET
from enum import Enum
def clog2(x):
"""Ceiling log 2 of x.
>>> clog2(0), clog2(1), clog2(2), clog2(3), clog2(4)
(0, 0, 1, 2, 2)
>>> clog2(5), clog2(6), clog2(7), clog2(8), clog2(9)
(3, 3, 3, 3, 4)
>>> clog2(1 << 31)
31
>>> clog2(1 << 63)
63
>>> clog2(1 << 11)
11
"""
x -= 1
i = 0
while True:
if x <= 0:
break
x = x >> 1
i += 1
return i
def add_metadata(tag, mtype, msubtype):
meta_root = ET.SubElement(tag, 'metadata')
meta_type = ET.SubElement(meta_root, 'meta', {'name': 'type'})
meta_type.text = mtype
meta_subtype = ET.SubElement(meta_root, 'meta', {'name': 'subtype'})
meta_subtype.text = msubtype
return meta_root
class MuxType(Enum):
LOGIC = 'BEL_MX'
ROUTING = 'BEL_RX'
class MuxPinType(Enum):
INPUT = 'i'
SELECT = 's'
OUTPUT = 'o'
def verilog(self):
if self in (self.INPUT, self.SELECT):
return "input wire"
elif self == self.OUTPUT:
return "output wire"
else:
raise TypeError(
"Can't convert {} into verilog definition.".format(self)
)
def direction(self):
if self in (self.INPUT, self.SELECT):
return "input"
elif self == self.OUTPUT:
return "output"
else:
raise TypeError(
"Can't convert {} into verilog definition.".format(self)
)
def __str__(self):
return self.value
class ModulePort(object):
def __init__(self, pin_type, name, width, index, data_width=1):
self.name = name
self.pin_type = pin_type
self.width = width
self.index = index
self.data_width = data_width
def getDefinition(self):
if self.width == 1:
if self.data_width is not None and self.data_width > 1:
return '\t%s [%d:0] %s;\n' % (
self.pin_type.verilog(), self.data_width - 1, self.name
)
else:
return '\t%s %s;\n' % (self.pin_type.verilog(), self.name)
else:
return '\t%s %s %s;\n' % (
self.pin_type.verilog(), self.index, self.name
)
def pb_type_xml(mux_type, mux_name, pins, subckt=None, num_pb=1, comment=""):
"""Generate <pb_type> XML for a mux.
Parameters
----------
mux_type: MuxType
Type of mux to create.
mux_name: str
Name of the mux.
pins: [(MuxPinType, str, int, int),]
List of tuples which contain (pin type, pin name, port width, index)
subckt: str
Name of the blif_model for the mux. Only valid when mux_type ==
MuxType.LOGIC.
num_pb: int
Value for the num_pb value. Defaults to 1.
comment: str
Optional comment for the mux.
Returns
-------
xml.etree.ElementTree
pb_type.xml for requested mux
"""
assert isinstance(comment,
str), "{} {}".format(type(comment), repr(comment))
if mux_type not in (MuxType.LOGIC, MuxType.ROUTING):
assert False, "Unknown type {}".format(mux_type)
pb_type_xml = ET.Element(
'pb_type', {
'name': mux_name,
'num_pb': str(num_pb),
}
)
if mux_type == MuxType.LOGIC:
add_metadata(pb_type_xml, 'bel', 'mux')
else:
add_metadata(pb_type_xml, 'bel', 'routing')
if mux_type == MuxType.LOGIC:
model = ET.SubElement(pb_type_xml, "blif_model")
model.text = '.subckt {}'.format(subckt)
else:
assert not subckt, "Provided subckt={} for non-logic mux!".format(
subckt
)
if comment is not None:
pb_type_xml.append(ET.Comment(comment))
for port in pins:
# assert port.index < port.width, (
# "Pin index {} >= width {} for pin {} {}".format(
# port.index, port.width, port.name, port.pin_type
# )
# )
if mux_type == MuxType.ROUTING and port.pin_type == MuxPinType.SELECT:
continue
assert port.width == 1 or port.data_width == 1, (
'Only one of width(%d) or data_width(%d) may > 1 for pin %s' %
(port.width, port.data_width, port.name)
)
if port.width == 1 and port.data_width > 1:
num_pins = port.data_width
else:
num_pins = port.width
mux = ET.SubElement(
pb_type_xml,
port.pin_type.direction(),
{
'name': port.name,
'num_pins': str(num_pins)
},
)
if mux_type == MuxType.LOGIC:
for inport in pins:
if inport.pin_type not in (MuxPinType.INPUT, MuxPinType.SELECT):
continue
for outport in pins:
if outport.pin_type not in (MuxPinType.OUTPUT, ):
continue
if inport.name.startswith('I'):
delay_inport = inport.name[1]
else:
# if it is not IX it must be S
delay_inport = "S0"
# XXX: temporary workaroud
if mux_name == "F6MUX":
maxdel = "10e-12"
else:
maxdel = "{{iopath_{}_OUT}}".format(delay_inport)
ET.SubElement(
pb_type_xml,
'delay_constant',
{
'max': maxdel,
'in_port': "%s" % inport.name,
'out_port': "%s" % outport.name,
},
)
elif mux_type == MuxType.ROUTING:
interconnect = ET.SubElement(pb_type_xml, 'interconnect')
inputs = [
"{}.{}".format(mux_name, port.name)
for port in pins
if port.pin_type in (MuxPinType.INPUT, )
]
outputs = [
"{}.{}".format(mux_name, port.name)
for port in pins
if port.pin_type in (MuxPinType.OUTPUT, )
]
assert len(outputs) == 1
mux = ET.SubElement(
interconnect,
'mux',
{
'name': '%s' % mux_name,
'input': " ".join(inputs),
'output': outputs[0],
},
)
meta_root = add_metadata(mux, 'bel', 'routing')
meta_fasm_mux = ET.SubElement(meta_root, 'meta', {'key': 'fasm_mux'})
meta_fasm_mux.text = "\n".join(
[""] + ["{0} = {0}".format(i) for i in inputs] + [""]
)
return pb_type_xml
if __name__ == "__main__":
import doctest
failure_count, test_count = doctest.testmod()
assert test_count > 0
assert failure_count == 0, "Doctests failed!"