Example #1
0
    def py_execute(self, args, design):
        ys.log_header(design, "Coalescing $_NOT_ gates with $sop outputs\n")
        for module in design.selected_whole_modules_warn():
            # Find all the $_NOT_ cells that are fed by $sop cells, but where the
            # $sop only feeds that $_NOT_ cell, remove the $_NOT_ cell, and add an
            # inversion attribute to the $sop cell.
            cell_inputs = {}  # input wire name -> Set[Cell]
            not_inputs = {}  # input wire name -> Cell
            sop_outputs = {}  # output wire name -> Cell
            for cell in [cell for cell in module.selected_cells()]:
                inputs = get_cell_port(cell, ID_PORT_A).to_sigbit_vector()
                for s in inputs:
                    if not s.is_wire():
                        continue  # It's probably a const
                    name = f"{s.wire.name.str()}[{s.offset}]"
                    if name not in cell_inputs:
                        cell_inputs[name] = set()
                    cell_inputs[name].update([cell])

                if cell.type.str() == "$_NOT_":
                    name = f"{inputs[0].wire.name.str()}[{s.offset}]"
                    not_inputs[name] = cell

                if cell.type.str() == "$sop":
                    output = get_cell_port(cell,
                                           ID_PORT_Y).to_sigbit_vector()[0]
                    name = f"{output.wire.name.str()}[{output.offset}]"
                    sop_outputs[name] = cell

            inversions = []  # List[Tuple[$sop Cell, $_NOT_ Cell]]
            for wire_name, cell in not_inputs.items():
                if len(cell_inputs[wire_name]) == 1:
                    if wire_name in sop_outputs:
                        sop = sop_outputs[wire_name]
                        inversions.append((sop, cell))

            cells_to_remove = []
            for sop, not_cell in inversions:
                sop.set_bool_attribute(ID_ATTR_INV_OUTPUT, True)
                # Replace the output wire in the $sop with the output wire from the $_NOT_.
                sop.setPort(ID_PORT_Y, get_cell_port(not_cell, ID_PORT_Y))
                cells_to_remove.append(not_cell)

            for cell in cells_to_remove:
                module.remove(cell)

            ys.log(
                f"Coalesced {len(cells_to_remove)} $_NOT_ cells with $sop cells.\n"
            )
Example #2
0
    def py_execute(self, args, design):
        ys.log_header(design, "Replacing $sop cells equivalent to $_NOT_\n")
        for module in design.selected_whole_modules_warn():
            cells_to_remove = []
            for cell in [
                    cell for cell in module.selected_cells()
                    if cell.type.str() == "$sop"
            ]:
                sop_depth = cell.parameters.get(
                    ys.IdString("\\DEPTH")).as_int()
                sop_width = cell.parameters.get(
                    ys.IdString("\\WIDTH")).as_int()
                sop_table = cell.parameters.get(
                    ys.IdString("\\TABLE")).as_int()
                sop_input = get_cell_port(cell, ID_PORT_A)
                sop_output = get_cell_port(cell, ID_PORT_Y)

                if sop_depth != 1 or sop_width != 1 or sop_table != 1:
                    continue

                not_cell = module.addCell(
                    module.uniquify(ys.IdString("$notsop")),
                    ys.IdString("$_NOT_"))
                not_cell.setPort(ys.IdString("\\A"), sop_input)
                not_cell.setPort(ID_PORT_Y, sop_output)
                ys.log(
                    f"$sop cell {cell.name.str()} replaced with $_NOT_ cell {not_cell.name.str()}\n"
                )
                cells_to_remove.append(cell)

            for cell in cells_to_remove:
                module.remove(cell)

            ys.log(
                f"Replaced {len(cells_to_remove)} $sop cells with $_NOT_ cells.\n"
            )
Example #3
0
 def py_clear_flags(self):
     ys.log("Clear Flags - CellStatsPass\n")
Example #4
0
 def py_help(self):
     ys.log("This pass uses the matplotlib library to display cell stats\n")
Example #5
0
 def py_help(self):
     ys.log("Writes a JED file.\n")
Example #6
0
 def py_help(self):
     ys.log("Sets UIM multiplexer and product term fuses.\n")
Example #7
0
 def py_help(self):
     ys.log("Allocates $__macrocell cells for $sop cells.\n")
Example #8
0
 def py_execute(self, args, design):
     ys.log_header(design, "Adding IO macrocells\n")
     for module in design.selected_whole_modules_warn():
         tbufs = [
             cell for cell in module.selected_cells()
             if cell.type.str() == "$_TBUF_"
         ]
         for tbuf in tbufs:
             tbuf_output = get_cell_port(tbuf, ID_PORT_Y)
             tbuf_enable = get_cell_port(tbuf, ID_PORT_E)
             print(
                 f"TBUF {sigspec_str(tbuf_output)}, enable = {sigspec_str(tbuf_enable)}"
             )
         print(f" -- Number of TBUFS: {len(tbufs)}")
         for wire in module.wires_.values():
             print(
                 f"Wire {wire.name.str()} offset {wire.start_offset} port_id {wire.port_id} input {wire.port_input} output {wire.port_output}"
             )
         output_wires = [
             wire for wire in module.wires_.values() if wire.port_output
         ]
         print(f" -- Number of output wires (ports): {len(output_wires)}")
         i_wires = [
             wire for wire in module.wires_.values()
             if self.is_input_pin(wire)
         ]
         o_wires = [
             wire for wire in module.wires_.values()
             if self.is_output_pin(wire)
         ]
         print(f" -- Input wires: {len(i_wires)}")
         print(f" -- Output wires: {len(o_wires)}")
         i_ports = []
         o_ports = []
         for conn_from, conn_to in module.connections_:
             if not conn_from.is_wire() or not conn_to.is_wire():
                 continue
             conn_from_name = conn_from.as_wire().name.str()
             conn_to_name = conn_to.as_wire().name.str()
             if self.is_input_pin(conn_from.as_wire()):
                 i_ports.append(conn_to_name)
             if self.is_output_pin(conn_from.as_wire()):
                 o_ports.append(conn_to_name)
             if self.is_input_pin(conn_to.as_wire()):
                 i_ports.append(conn_from_name)
             if self.is_output_pin(conn_to.as_wire()):
                 o_ports.append(conn_from_name)
         print(f" -- Input ports: {i_ports}")
         print(f" -- Output ports: {o_ports}")
         for wire in output_wires:
             n = wire.name.str().split("_")[1]
             mc = self.device.gpiobuf_to_mc[int(n)]
             new_cell = module.addCell(
                 module.uniquify(ys.IdString(f"$mc{n}")),
                 ys.IdString("$__macrocell"))
             new_cell.set_string_attribute(ys.IdString("$gpiobuf"), n)
             new_cell.set_string_attribute(ID_ATTR_MC, mc)
             if wire.name.str() in i_ports:
                 new_cell.setPort(ID_PORT_PAD, ys.SigSpec(wire))
                 new_cell.setPort(ID_PORT_IO_EN, ys.SigSpec(ys.State.S0))
                 new_cell.set_string_attribute(ID_ATTR_IO_FUNC, "input")
                 self.device.input_mcs[wire.name.str()] = mc
                 self.device.input_sigs[wire.name.str()] = f"M{mc}_PAD"
             else:
                 new_cell.setPort(ID_PORT_IO_A, ys.SigSpec(wire))
                 new_cell.setPort(ID_PORT_IO_EN, ys.SigSpec(ys.State.S1))
                 new_cell.set_string_attribute(ID_ATTR_IO_FUNC, "output")
                 self.device.input_mcs[wire.name.str()] = mc
                 # Remove this MC from the list of available MCs
                 self.device.available_mcs.remove(mc)
         ys.log(
             f"Added {len(output_wires)} macrocells ({len(i_ports)} inputs, {len(o_ports)} outputs)\n"
         )
Example #9
0
 def py_help(self):
     ys.log("Adds $__macrocell cells for inputs and outputs.\n")
Example #10
0
    def py_execute(self, args, design):
        ys.log_header(design, "Splitting overly large $sop cells\n")
        threshold = 5
        if len(args) > 1:
            threshold = int(args[1])
        new_cells = 0
        cells_to_remove = []

        for module in design.selected_whole_modules_warn():
            sops = [
                cell for cell in module.selected_cells()
                if cell.type.str() == "$sop"
            ]
            for sop in sops:
                # Depth is the number of product terms
                sop_depth = sop.parameters.get(ID_PARAM_DEPTH).as_int()
                if sop_depth <= threshold:
                    continue
                cells_to_remove.append(sop)

                # Width is the number of inputs
                sop_width = sop.parameters.get(ID_PARAM_WIDTH)
                # for (int i = 0; i < sop_depth; i++) {
                # for (int j = 0; j < sop_width; j++)
                # {
                # 	if (sop_table[2 * (i * sop_width + j) + 0])
                # 	{
                # 		and_in_comp.insert(sop_inputs[j]);
                # 	}
                # 	if (sop_table[2 * (i * sop_width + j) + 1])
                # 	{
                # 		and_in_true.insert(sop_inputs[j]);
                # 	}
                # }
                sop_table = sop.parameters.get(ID_PARAM_TABLE)
                sop_inputs = get_cell_port(sop, ID_PORT_A)
                sop_output = get_cell_port(sop, ID_PORT_Y)
                table = sop_table.as_string()
                product_terms = []
                print(f"Table is {table}")
                for i in range(sop_depth):
                    offset = 2 * i * sop_width.as_int()
                    size = 2 * sop_width.as_int()
                    product_term = table[offset:offset + size]
                    product_terms.append(product_term)
                    print(f"  Term {i}: {product_term}")

                # Rather than create $sops with 5 inputs each and then ORing
                # them together in another $sop, we ripple $sops together.
                new_output = None
                offset = 0
                while offset < sop_depth:
                    is_first = offset == 0
                    is_last = sop_depth - offset < threshold
                    # We can fit N inputs into the first $sop, but only
                    # N-1 inputs into the subsequent $sops because they
                    # ripple their outputs.
                    if is_first:
                        new_inputs = sop_inputs
                        new_product_terms = product_terms[:threshold]
                        offset += threshold
                    else:
                        new_inputs = sop_inputs
                        new_product_terms = [
                            f"{p}00" for p in product_terms[offset:offset +
                                                            threshold - 1]
                        ]
                        additional_product_term = f"{'00'*sop_inputs.size()}01"
                        new_inputs.append(new_output)
                        new_product_terms.append(additional_product_term)
                        offset += threshold - 1
                    new_width = new_inputs.size()
                    new_depth = len(new_product_terms)
                    print(f"New width: {new_width}")
                    print(f"New depth: {new_depth}")
                    print(f"New product terms: {''.join(new_product_terms)}")
                    new_table = ys.Const.from_string(
                        "".join(new_product_terms))

                    print(f"new inputs for sop: {sigspec_str(new_inputs)}")
                    if is_last:
                        new_output = sop_output
                        print(f"final output: {sigspec_str(new_output)}")
                    else:
                        new_output = ys.SigSpec(
                            module.addWire(
                                module.uniquify(
                                    ys.IdString("$smaller_sop_out"))))
                        print(f"new ripple output: {sigspec_str(new_output)}")

                    table = new_table.as_string()
                    print(f"New table: {table}")
                    for i in range(new_depth):
                        off = 2 * i * new_width
                        size = 2 * new_width
                        product_term = table[off:off + size]
                        print(f"  Term {i}: {product_term}")

                    new_cell = module.addCell(
                        module.uniquify(ys.IdString("$smaller_sop")),
                        ys.IdString("$sop"))
                    new_cell.setPort(ys.IdString("\\A"), new_inputs)
                    new_cell.setPort(ID_PORT_Y, new_output)
                    new_cell.setParam(ys.IdString("\\TABLE"), new_table)
                    new_cell.setParam(ys.IdString("\\DEPTH"),
                                      ys.Const(new_depth, 32))
                    new_cell.setParam(ys.IdString("\\WIDTH"),
                                      ys.Const(new_width, 32))
                    new_cells += 1

            for cell in cells_to_remove:
                module.remove(cell)

            ys.log(
                f"Removed {len(cells_to_remove)} overly large $sop cells and replaced with {new_cells} cells.\n"
            )
Example #11
0
 def py_help(self):
     ys.log("Splits $sop cells with more product terms than desired.\n")
     ys.log("  Usage: split_large_sop [threshold]\n")
     ys.log("  The default threshold is 5.\n")
Example #12
0
 def py_help(self):
     ys.log("Coalesces $_NOT_ gates with $sop outputs\n")
Example #13
0
 def py_help(self):
     ys.log("Replaces $sop cells that implement not with $_NOT_ cells\n")
Example #14
0
 def py_clear_flags(self):
     ys.log("Clear Flags - CellStatsPass\n")
Example #15
0
 def py_help(self):
     ys.log("This pass uses the matplotlib library to display cell stats\n")