|  | #!/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!" |