Skip to content

Commit

Permalink
Improvements to supplies API (#816)
Browse files Browse the repository at this point in the history
* Change supply.pin: str to supply.pins: List[str]

This enables generation of CPFs where a single supply net can be
global_connect'd to many pins

* Add power_straps.by_tracks.power_nets API

This setting, if set, allows precise control over which supplies in a
design the auto-strap generation should generate stripes for.
Previously, it would generate straps for all supplies

* Add supplies.voltage to override the vlsi.inputs.supplies.VDD

Allow per-supply voltage specification. If unset, defaults to
vlsi.inputs.supplies.VDD (old behavior)

* Change supply.pins to a Option[List[str]] | fix upf gen for supplies
  • Loading branch information
jerryz123 authored and nayiri-k committed Nov 13, 2023
1 parent 5342441 commit d1f46ca
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 42 deletions.
9 changes: 6 additions & 3 deletions hammer/config/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,13 @@ vlsi.inputs:
# Supply voltages and names
# Supply Struct:
# name (str) - The name of your supply's net
# pin (Optional[str]) - The cell pin that this net should drive, no pins are connected when omitted
# pins (Optional[List[str]]) - The cell pin/s that this net should drive. If None, pin name is assumed to be net name. If empty, no pins are connected
# tie (Optional[str]) - Another supply this supply is tied to. Nets with this set will not end up in your final layout.
# weight (Optional[int]) - The weight of this supply when building power straps (larger number = more straps).
# Not used for grounds. Mandatory, but defaults to 1 if omitted.
supplies:
power: [{name: "VDD", pin: "VDD"}] # power (List(Supply)): A list of of all power net(s) in the design
ground: [{name: "VSS", pin: "VSS"}] # ground (List(Supply)): A list of all ground net(s) in the design
power: [{name: "VDD", pins: ["VDD"]}] # power (List(Supply)): A list of of all power net(s) in the design
ground: [{name: "VSS", pins: ["VSS"]}] # ground (List(Supply)): A list of all ground net(s) in the design
VDD: "0.85 V" # VDD (str): The default voltage of the primary power net
GND: "0 V" # GND (str): The default voltage of the primary ground net

Expand Down Expand Up @@ -621,6 +621,9 @@ par:
# Otherwise should be set to some layer name
# type: str

power_nets: [] # List of power nets to generate straps for. If empty, generates straps for all nets in vlsi.inputs.supplies
# type: List[str]

# DRC settings
drc.inputs:
# DRC settings
Expand Down
8 changes: 6 additions & 2 deletions hammer/config/defaults_types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ vlsi.technology:
vlsi.inputs:
# Supply voltages and names
supplies:
power: list[dict[str, str]]
ground: list[dict[str, str]]
power: list[dict[str, Any]]
ground: list[dict[str, Any]]
VDD: str
GND: str

Expand Down Expand Up @@ -334,6 +334,10 @@ par:
# type: str
bottom_via_layer: str

# Indicates which power nets straps should be generated for
# type: list[str]
power_nets: list[str]

# DRC settings
drc.inputs:
# Top RTL module.
Expand Down
16 changes: 8 additions & 8 deletions hammer/technology/sky130/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ vlsi:
inputs:
supplies: # Supply voltages.
# TODO: add ability to tie pin to net in Hammer Innovus plugin
power: [ {name: "VDD", pin: "VDD"},
{name: "VPWR", pin: "VPWR", tie: "VDD"},
{name: "VPB", pin: "VPB" , tie: "VDD"},
{name: "vdd", pin: "vdd", tie: "VDD"}]
ground: [ {name: "VSS", pin: "VSS"},
{name: "VGND", pin: "VGND", tie: "VSS"},
{name: "VNB", pin: "VNB" , tie: "VSS"},
{name: "vss", pin: "vss", tie: "VSS"}]
power: [ {name: "VDD", pins: ["VDD" ]},
{name: "VPWR", pins: ["VPWR"], tie: "VDD"},
{name: "VPB", pins: ["VPB" ], tie: "VDD"},
{name: "vdd", pins: ["vdd" ], tie: "VDD"}]
ground: [ {name: "VSS", pins: ["VSS" ]},
{name: "VGND", pins: ["VGND"], tie: "VSS"},
{name: "VNB", pins: ["VNB" ], tie: "VSS"},
{name: "vss", pina: ["vss" ], tie: "VSS"}]
VDD: "1.8 V"
GND: "0 V"

Expand Down
5 changes: 3 additions & 2 deletions hammer/vlsi/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,10 @@ def from_setting(d: dict) -> "SRAMParameters":

Supply = NamedTuple('Supply', [
('name', str),
('pin', Optional[str]),
('pins', Optional[List[str]]),
('tie', Optional[str]),
('weight', Optional[int])
('weight', Optional[int]),
('voltage', Optional[str])
])


Expand Down
9 changes: 6 additions & 3 deletions hammer/vlsi/hammer_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -1090,13 +1090,16 @@ def get_all_supplies(self, key: str) -> List[Supply]:
supplies = self.get_setting(key)
output = [] # type: List[Supply]
for raw_supply in supplies:
supply = Supply(name=raw_supply['name'], pin=None, tie=None, weight=1)
if 'pin' in raw_supply:
supply = supply._replace(pin=raw_supply['pin'])
supply = Supply(name=raw_supply['name'], pins=[], tie=None, weight=1, voltage=None)
assert 'pin' not in raw_supply, "supply.pin: str has been replaced with supply.pins: List[str]"
if 'pins' in raw_supply:
supply = supply._replace(pins=raw_supply['pins'])
if 'tie' in raw_supply:
supply = supply._replace(tie=raw_supply['tie'])
if 'weight' in raw_supply:
supply = supply._replace(weight=raw_supply['weight'])
if 'voltage' in raw_supply:
supply = supply._replace(voltage=raw_supply['voltage'])
output.append(supply)
return output

Expand Down
56 changes: 36 additions & 20 deletions hammer/vlsi/hammer_vlsi_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -649,17 +649,24 @@ def generate_power_straps_tcl(self) -> List[str]:
generate_rail_layer = self.get_setting("{}.generate_rail_layer".format(namespace))
ground_net_names = list(map(lambda x: x.name, self.get_independent_ground_nets())) # type: List[str]
power_net_names = list(map(lambda x: x.name, self.get_independent_power_nets())) # type: List[str]
specified_power_net_names = self.get_setting("{}.power_nets".format(namespace))
if len(specified_power_net_names) != 0: # filter by user specified settings
assert all(map(lambda n: n in power_net_names, specified_power_net_names))
power_net_names = specified_power_net_names
bottom_via_option = self.get_setting("{}.bottom_via_layer".format(namespace))
if bottom_via_option == "rail":
bottom_via_layer = self.get_setting("technology.core.std_cell_rail_layer")
else:
bottom_via_layer = bottom_via_option

def get_weight(s: Supply) -> int:
def get_weight(supply_name: str) -> int:
supply = list(filter(lambda s: s.name == supply_name, self.get_independent_power_nets()))
# Check that single supply with name exists
assert len(supply) == 1
# Check that it's not None
assert isinstance(s.weight, int)
return s.weight
weights = list(map(get_weight, self.get_independent_power_nets())) # type: List[int]
assert isinstance(supply[0].weight, int)
return supply[0].weight
weights = list(map(get_weight, power_net_names)) # type: List[int]
assert len(ground_net_names) == 1, "FIXME, I am assuming there's only 1 ground net"
return self.specify_all_power_straps_by_tracks(layers, bottom_via_layer, ground_net_names[0], power_net_names, weights, bbox, pin_layers, generate_rail_layer)
else:
Expand Down Expand Up @@ -2084,25 +2091,28 @@ def upf_power_specification(self) -> str:
ground_nets = self.get_all_ground_nets()
#Create Supply Ports
for pg_net in (power_nets+ground_nets):
if(pg_net.pin != None):
#Create Supply Nets
output.append(f'create_supply_net {pg_net.name} -domain {domain}')
output.append(f'create_supply_port {pg_net.name} -domain {domain} \\')
output.append(f'\t-direction in')
pins = pg_net.pins if pg_net.pins is not None else [pg_net.name]
#Create Supply Nets
output.append(f'create_supply_net {pg_net.name} -domain {domain}')
output.append(f'create_supply_port {pg_net.name} -domain {domain} \\')
output.append(f'\t-direction in')
for pin in pins:
#Connect Supply Net
output.append(f'connect_supply_net {pg_net.name} -ports {pg_net.name}')
#Set Domain Supply Net
output.append(f'connect_supply_net {pg_net.name} -ports {pin}')
#Set Domain Supply Net
output.append(f'set_domain_supply_net {domain} \\')
output.append(f'\t-primary_power_net {power_nets[0].name} \\')
output.append(f'\t-primary_ground_net {ground_nets[0].name}')
#Add Port States
for p_net in power_nets:
if(p_net.pin != None):
output.append(f'add_port_state {p_net.name} \\')
pins = p_net.pins if p_net.pins is not None else [p_net.name]
for pin in pins:
output.append(f'add_port_state {pin} \\')
output.append(f'\t-state {{default {vdd.value}}}')
for g_net in ground_nets:
if(g_net.pin != None):
output.append(f'add_port_state {g_net.name} \\')
pins = g_net.pins if g_net.pins is not None else [g_net.name]
for pin in pins:
output.append(f'add_port_state {pin} \\')
output.append(f'\t-state {{default 0.0}}')
#Create Power State Table
output.append('create_pst pwr_state_table \\')
Expand Down Expand Up @@ -2131,19 +2141,25 @@ def cpf_power_specification(self) -> str:
# Define power and ground nets (HARD CODE)
power_nets = self.get_all_power_nets() # type: List[Supply]
ground_nets = self.get_all_ground_nets()# type: List[Supply]
vdd = VoltageValue(self.get_setting("vlsi.inputs.supplies.VDD")) # type: VoltageValue
output.append(f'create_power_nets -nets {{ {" ".join(map(lambda x: x.name, power_nets))} }} -voltage {vdd.value}')
for power_net in power_nets:
vdd = VoltageValue(self.get_setting("vlsi.inputs.supplies.VDD")) # type: VoltageValue
if power_net.voltage is not None:
vdd = VoltageValue(power_net.voltage)
output.append(f'create_power_nets -nets {power_net.name} -voltage {vdd.value}')
output.append(f'create_ground_nets -nets {{ {" ".join(map(lambda x: x.name, ground_nets))} }}')
# Define power domain and connections
output.append(f'create_power_domain -name {domain} -default')
# Assume primary power are first in list
output.append(f'update_power_domain -name {domain} -primary_power_net {power_nets[0].name} -primary_ground_net {ground_nets[0].name}')
# Assuming that all power/ground nets correspond to pins
for pg_net in (power_nets+ground_nets):
if(pg_net.pin != None):
output.append(f'create_global_connection -domain {domain} -net {pg_net.name} -pins {pg_net.pin}')
pins = pg_net.pins if pg_net.pins is not None else [pg_net.name]
if len(pins):
pins_str = ' '.join(pins)
output.append(f'create_global_connection -domain {domain} -net {pg_net.name} -pins [list {pins_str}]')
# Create nominal operation condtion and power mode
output.append(f'create_nominal_condition -name {condition} -voltage {vdd.value}')
nominal_vdd = VoltageValue(self.get_setting("vlsi.inputs.supplies.VDD")) # type: VoltageValue
output.append(f'create_nominal_condition -name {condition} -voltage {nominal_vdd.value}')
output.append(f'create_power_mode -name {mode} -default -domain_conditions {{{domain}@{condition}}}')
# Footer
output.append("end_design")
Expand Down
8 changes: 4 additions & 4 deletions tests/test_power_straps.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ def simple_straps_options() -> Dict[str, Any]:

straps_options = {
"vlsi.inputs.supplies": {
"power": [{"name": "VDD", "pin": "VDD"}],
"ground": [{"name": "VSS", "pin": "VSS"}],
"power": [{"name": "VDD", "pins": ["VDD"]}],
"ground": [{"name": "VSS", "pins": ["VSS"]}],
"VDD": "1.00 V",
"GND": "0 V"
},
Expand Down Expand Up @@ -129,8 +129,8 @@ def multiple_domains_straps_options() -> Dict[str, Any]:

straps_options = {
"vlsi.inputs.supplies": {
"power": [{"name": "VDD", "pin": "VDD"}, {"name": "VDD2", "pin": "VDD2"}],
"ground": [{"name": "VSS", "pin": "VSS"}],
"power": [{"name": "VDD", "pins": ["VDD"]}, {"name": "VDD2", "pins": ["VDD2"]}],
"ground": [{"name": "VSS", "pins": ["VSS"]}],
"VDD": "1.00 V",
"GND": "0 V"
},
Expand Down

0 comments on commit d1f46ca

Please sign in to comment.