Skip to content

Commit

Permalink
Many Genus + Innovus enhancements (#843)
Browse files Browse the repository at this point in the history
* Many enhancements

* regexp may match anything if any cell types were empty (trailing |)

* update versions, set power analysis views, fix add_tieoffs

* report timing constraint issues after init-ing design

* add soft & hard placement constraint types - maps to guide & region, respectively

* typo

* fix viz

* move fanout fixing earlier
  • Loading branch information
harrisonliew authored Mar 6, 2024
1 parent 5897249 commit 303c375
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 46 deletions.
9 changes: 7 additions & 2 deletions hammer/common/cadence/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,15 @@ def append_mmmc(cmd: str) -> None:

# Finally, apply the analysis view.
# TODO: should not need to analyze extra views as well. Defaulting to hold for now (min. runtime impact).
append_mmmc("set_analysis_view -setup {{ {setup_views} }} -hold {{ {hold_views} {extra_views} }}".format(
# First extra view is assumed to be for dynamic and leakage power calculation.
power_opts = ""
if len(extra_view_names) > 0:
power_opts = f"-dynamic {extra_view_names[0]} -leakage {extra_view_names[0]}"
append_mmmc("set_analysis_view -setup {{ {setup_views} }} -hold {{ {hold_views} {extra_views} }} {power}".format(
setup_views=" ".join(setup_view_names),
hold_views=" ".join(hold_view_names),
extra_views=" ".join(extra_view_names)
extra_views=" ".join(extra_view_names),
power=power_opts
))
else:
# First, create an Innovus library set.
Expand Down
3 changes: 2 additions & 1 deletion hammer/config/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ vlsi.inputs:
# - Required for all types
# - One of the following:
# - "dummy" (does nothing with this constraint)
# - "placement" (creates a placement constraint for an instance)
# - "placement" or "soft_placement" (creates a soft placement constraint for a hierarchical instance)
# - "hard_placement" (creates a hard placement constraint for a hierarchical instance)
# - "toplevel" (top-level chip dimensions; may only occur once, for the top-level module)
# - "hardmacro" (places this hard macro at a particular spot)
# - "hierarchical" (marks this instance as part of hierarchical place and route)
Expand Down
179 changes: 156 additions & 23 deletions hammer/par/innovus/__init__.py

Large diffs are not rendered by default.

12 changes: 11 additions & 1 deletion hammer/par/innovus/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ par.innovus:

# Innovus version to use.
# Used to locate the binary - e.g. the '221' in ${cadence.cadence_home}/DDI/DDI221/INNOVUS221/bin/innovus
version: "221"
version: "231"

# Design flow effort.
# Valid options: express (fastest), standard, and extreme (slowest).
Expand All @@ -35,3 +35,13 @@ par.innovus:
# Note that this requires an optional licence (enccco).
# type: bool
use_cco: true

# Route bumps with early global router (version >= 23.1 only).
# By default, bumps are ignored for routing. If true, turn on early bump routing.
# This is useful for RC delay estimation if you don't have IO cells routed to bumps via the flip-chip router.
early_route_bumps: false

# Perform signoff timing, then timing/DRV/power optimization with opt_signoff.
# Should only be run at the very end, as runtime impact is significant.
# Requires the same version of Tempus to be installed at ${cadence.cadence_home}/SSV/SSV${par.innovus.bin}/bin
signoff: false
2 changes: 1 addition & 1 deletion hammer/par/openroad/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1814,7 +1814,7 @@ def generate_floorplan_tcl(self) -> List[str]:
pass
if constraint.type == PlacementConstraintType.Dummy:
pass
elif constraint.type == PlacementConstraintType.Placement:
elif constraint.type in [PlacementConstraintType.SoftPlacement, PlacementConstraintType.HardPlacement]:
pass
# for OpenROAD
elif constraint.type in [PlacementConstraintType.HardMacro, PlacementConstraintType.Hierarchical]:
Expand Down
2 changes: 1 addition & 1 deletion hammer/power/joules/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ power.joules:

# Joules version to use.
# Used to locate the binary - e.g. the '221' in ${cadence.cadence_home}/DDI/DDI221/JLS221/bin/joules
version: "221"
version: "231"
16 changes: 10 additions & 6 deletions hammer/synthesis/genus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ def init_environment(self) -> bool:
verbose_append("set_db module:{top}/{mod} .preserve true".format(top=self.top_module, mod=ilm.module))
verbose_append("init_design -top {}".format(self.top_module))

# Report timing constraint issues
verbose_append("report_timing -lint -verbose")

# Setup power settings from cpf/upf
# Difference from other tools: apply_power_intent after read
power_cmds = self.generate_power_spec_commands()
Expand Down Expand Up @@ -357,12 +360,13 @@ def add_tieoffs(self) -> bool:
self.verbose_append("set_db message:WSDF-201 .max_print 20")
self.verbose_append("set_db use_tiehilo_for_const duplicate")

# If there is more than 1 corner or a certain type, use lib cells for only the active analysis view
corner_counts = Counter(list(map(lambda c: c.type, self.get_mmmc_corners())))
if any(cnt>1 for cnt in corner_counts.values()):
self.verbose_append("set ACTIVE_VIEW [string map { .setup_view {} .hold_view {} .extra_view {} } [get_db analysis_view:[get_analysis_views] .name]]")
self.verbose_append("set HI_TIEOFF [get_db base_cell:{TIE_HI_CELL} .lib_cells -if {{ .library.default_opcond == $ACTIVE_VIEW }}]".format(TIE_HI_CELL=tie_hi_cell))
self.verbose_append("set LO_TIEOFF [get_db base_cell:{TIE_LO_CELL} .lib_cells -if {{ .library.default_opcond == $ACTIVE_VIEW }}]".format(TIE_LO_CELL=tie_lo_cell))
# If MMMC corners specified, get the single lib cell for the active analysis view
# Else, Genus will complain that multiple objects match for the cell name
corners = self.get_mmmc_corners()
if corners:
self.verbose_append("set ACTIVE_SET [string map { .setup_view .setup_set .hold_view .hold_set .extra_view .extra_set } [get_db [get_analysis_views] .name]]")
self.verbose_append("set HI_TIEOFF [get_db base_cell:{TIE_HI_CELL} .lib_cells -if {{ .library.library_set.name == $ACTIVE_SET }}]".format(TIE_HI_CELL=tie_hi_cell))
self.verbose_append("set LO_TIEOFF [get_db base_cell:{TIE_LO_CELL} .lib_cells -if {{ .library.library_set.name == $ACTIVE_SET }}]".format(TIE_LO_CELL=tie_lo_cell))
self.verbose_append("add_tieoffs -high $HI_TIEOFF -low $LO_TIEOFF -max_fanout 1 -verbose")
else:
self.verbose_append("add_tieoffs -high {HI_TIEOFF} -low {LO_TIEOFF} -max_fanout 1 -verbose".format(HI_TIEOFF=tie_hi_cell, LO_TIEOFF=tie_lo_cell))
Expand Down
2 changes: 1 addition & 1 deletion hammer/synthesis/genus/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ synthesis.genus:

# Genus version to use.
# Used to locate the binary - e.g. the '221' in ${cadence.cadence_home}/DDI/DDI221/GENUS221/bin/genus
version: "221"
version: "231"

# Generate the TCL file but do not run it yet.
generate_only: false
19 changes: 11 additions & 8 deletions hammer/vlsi/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,18 +530,21 @@ def __str__(self) -> str:

class PlacementConstraintType(Enum):
Dummy = 1
Placement = 2
TopLevel = 3
HardMacro = 4
Hierarchical = 5
Obstruction = 6
Overlap = 7
SoftPlacement = 2
HardPlacement = 3
TopLevel = 4
HardMacro = 5
Hierarchical = 6
Obstruction = 7
Overlap = 8

@classmethod
def __mapping(cls) -> Dict[str, "PlacementConstraintType"]:
return {
"dummy": PlacementConstraintType.Dummy,
"placement": PlacementConstraintType.Placement,
"placement": PlacementConstraintType.SoftPlacement,
"soft_placement": PlacementConstraintType.SoftPlacement,
"hard_placement": PlacementConstraintType.HardPlacement,
"toplevel": PlacementConstraintType.TopLevel,
"hardmacro": PlacementConstraintType.HardMacro,
"hierarchical": PlacementConstraintType.Hierarchical,
Expand Down Expand Up @@ -781,7 +784,7 @@ def from_dict(constraint: dict) -> "PlacementConstraint":
assert isinstance(create_physical, bool)

### Width & height ###
# These fields are mandatory for Hierarchical, Dummy, Placement, TopLevel, and Obstruction constraints
# These fields are mandatory for Hierarchical, Dummy, Soft/HardPlacement, TopLevel, and Obstruction constraints
# These fields are optional for HardMacro and Overlap constraints
# TODO(ucb-bar/hammer#414) make them mandatory for HardMacro and Overlap once there's a more robust way of automatically getting that data into hammer
# This is not None because we don't want to make width optional for the reason above
Expand Down
2 changes: 1 addition & 1 deletion hammer/vlsi/hammer_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -1268,7 +1268,7 @@ def get_macro_wh(macro: Optional[str]) -> Tuple[Decimal, Decimal]:
if viz_mode in ["all", "floorplan"]:
macro_rects = macro_text = obs_rects = obs_text = orient_lines = '<g transform="{}">\n'.format(translate)
for c in fp_consts:
if c.type in [PlacementConstraintType.Placement, PlacementConstraintType.HardMacro, PlacementConstraintType.Hierarchical]:
if c.type in [PlacementConstraintType.SoftPlacement, PlacementConstraintType.HardPlacement, PlacementConstraintType.HardMacro, PlacementConstraintType.Hierarchical]:
# macros & hierarchical not required to have width/height, will resolve to 0
(width, height) = (c.width, c.height)
if width == 0 or height == 0:
Expand Down
8 changes: 7 additions & 1 deletion tests/test_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,13 @@ def test_placement(self) -> None:
"height": Decimal(20),
"orientation": "r0"}
tc = PlacementConstraint.from_dict(d)
assert tc.type == PlacementConstraintType.Placement
assert tc.type == PlacementConstraintType.SoftPlacement
d["type"] = "soft_placement"
tc = PlacementConstraint.from_dict(d)
assert tc.type == PlacementConstraintType.SoftPlacement
d["type"] = "hard_placement"
tc = PlacementConstraint.from_dict(d)
assert tc.type == PlacementConstraintType.HardPlacement
assert tc.path == "path/to/placement"
assert tc.x == Decimal(4)
assert tc.y == Decimal(6)
Expand Down

0 comments on commit 303c375

Please sign in to comment.