Source code for fabulous.fabric_generator.gds_generator.script.odb_power

"""OpenDB script to connect power rails for FABulous fabric."""
#
# Original src: https://github.com/mole99/librelane_plugin_fabulous/blob/main/librelane_plugin_fabulous/scripts/odb_power.py
# OpenDB script for custom Power for FABulous fabric
# This script places vertical PDN straps on top
# of already existing straps in order to tell OpenROAD
# that they should be considered connected and are pins
#
# Copyright (c) 2023 Sylvain Munaut <tnt@246tNt.com>
# Copyright (c) 2025 Leo Moser <leo.moser@pm.me>
# SPDX-License-Identifier: Apache-2.0
#

from typing import Any

import click
import odb
from librelane.logging.logger import info
from librelane.scripts.odbpy.reader import click_odb


@click.option(
    "--metal-layer-name",
    default=None,
    type=str,
    help="Metal layer for the power/ground straps",
)
@click.command()
@click_odb
[docs] def power( reader: Any, # noqa: ANN401 metal_layer_name: str, ) -> None: """Connect power rails for the tiles using a custom script.""" # Create ground / power nets tech = reader.db.getTech() info(f"metal_layer_name: {metal_layer_name}") metal_layer = tech.findLayer(metal_layer_name) # Create nets, if they don't exist yet # TODO make this generic using VDD_NETS, GND_NETS for net_name, net_type in [("VPWR", "POWER"), ("VGND", "GROUND")]: net = reader.block.findNet(net_name) if net is None: # Create net net = odb.dbNet.create(reader.block, net_name) net.setSpecial() net.setSigType(net_type) vpwr_net = reader.block.findNet("VPWR") vgnd_net = reader.block.findNet("VGND") # Create wires vpwr_wire = odb.dbSWire.create(vpwr_net, "ROUTED") vgnd_wire = odb.dbSWire.create(vgnd_net, "ROUTED") # Create bterms (top-level) vpwr_bterm = odb.dbBTerm.create(vpwr_net, "VPWR") vpwr_bterm.setIoType("INOUT") vpwr_bterm.setSigType(vpwr_net.getSigType()) vpwr_bterm.setSpecial() vpwr_bpin = odb.dbBPin_create(vpwr_bterm) vgnd_bterm = odb.dbBTerm.create(vgnd_net, "VGND") vgnd_bterm.setIoType("INOUT") vgnd_bterm.setSigType(vgnd_net.getSigType()) vgnd_bterm.setSpecial() vgnd_bpin = odb.dbBPin_create(vgnd_bterm) # Connect instance-iterms to power nets, # draw the wires and pins for blk_inst in reader.block.getInsts(): info(f"Instance: {blk_inst.getName()}") for iterm in blk_inst.getITerms(): iterm_name = iterm.getMTerm().getName() if iterm_name == "VPWR": info("Connecting VPWR") iterm.connect(vpwr_net) if iterm_name == "VGND": info("Connecting VGND") iterm.connect(vgnd_net) inst_master = blk_inst.getMaster() # Now, for each power/ground mterm (TODO: check signal type instead of name) # Copy the geomtry of the pins to wires and top-level pins for master_mterm in inst_master.getMTerms(): if master_mterm.getName() == "VPWR" or master_mterm.getName() == "VGND": for mterm_mpins in master_mterm.getMPins(): for mpins_dbox in mterm_mpins.getGeometry(): if master_mterm.getName() == "VPWR": odb.dbSBox_create( vpwr_wire, metal_layer, blk_inst.getLocation()[0] + mpins_dbox.xMin(), blk_inst.getLocation()[1] + mpins_dbox.yMin(), blk_inst.getLocation()[0] + mpins_dbox.xMax(), blk_inst.getLocation()[1] + mpins_dbox.yMax(), "STRIPE", ) odb.dbBox_create( vpwr_bpin, metal_layer, blk_inst.getLocation()[0] + mpins_dbox.xMin(), blk_inst.getLocation()[1] + mpins_dbox.yMin(), blk_inst.getLocation()[0] + mpins_dbox.xMax(), blk_inst.getLocation()[1] + mpins_dbox.yMax(), ) if master_mterm.getName() == "VGND": odb.dbSBox_create( vgnd_wire, metal_layer, blk_inst.getLocation()[0] + mpins_dbox.xMin(), blk_inst.getLocation()[1] + mpins_dbox.yMin(), blk_inst.getLocation()[0] + mpins_dbox.xMax(), blk_inst.getLocation()[1] + mpins_dbox.yMax(), "STRIPE", ) odb.dbBox_create( vgnd_bpin, metal_layer, blk_inst.getLocation()[0] + mpins_dbox.xMin(), blk_inst.getLocation()[1] + mpins_dbox.yMin(), blk_inst.getLocation()[0] + mpins_dbox.xMax(), blk_inst.getLocation()[1] + mpins_dbox.yMax(), ) vpwr_bpin.setPlacementStatus("FIRM") vgnd_bpin.setPlacementStatus("FIRM")
if __name__ == "__main__": power()