Skip to content

Commit

Permalink
Updates for DDI221 (#798)
Browse files Browse the repository at this point in the history
* updates for DDI221

* output load units should be CapacitanceValue

* also OutputLoadConstraint

* enable clock mapping flow by adding more special cells

* Update __init__.py

Perhaps 211 not 2111?

* make special cell types in docs point to schema compilation output

* bring in design power key

---------

Co-authored-by: kenhoberkeley <[email protected]>
Co-authored-by: ken_ho <[email protected]>
  • Loading branch information
3 people authored Sep 28, 2023
1 parent b1f970a commit 07d430d
Show file tree
Hide file tree
Showing 11 changed files with 68 additions and 31 deletions.
2 changes: 1 addition & 1 deletion doc/Technology/Tech-json.rst
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ The example below shows a subset of the ASAP7 tech plugin for 2 types of cells:
{"cell_type": "tapcell", "name": ["TAPCELL_ASAP7_75t_L"]},
{"cell_type": "stdfiller", "name": ["FILLER_ASAP7_75t_R", "FILLER_ASAP7_75t_L", "FILLER_ASAP7_75t_SL", "FILLER_ASAP7_75t_SRAM", "FILLERxp5_ASAP7_75t_R", "FILLERxp5_ASAP7_75t_L", "FILLERxp5_ASAP7_75t_SL", "FILLERxp5_ASAP7_75t_SRAM"]},
There are 8 ``cell_type`` s supported: ``tiehicell``, ``tielocell``, ``tiehilocell``, ``endcap``, ``iofiller``, ``stdfiller``, ``decap``, and ``tapcell``. Depending on the tech/tool, some of these cell types can only have 1 cell in the ``name`` list.
See the ``SpecialCell`` subsection in the :ref:`full_schema` for a list of special cell types. Depending on the tech/tool, some of these cell types can only have 1 cell in the ``name`` list.
There is an optional ``size`` list. For each element in its corresponding ``name`` list, a size (type: str) can be given. An example of how this is used is for ``decap`` cells, where each listed cell has a typical capacitance, which a place and route tool can then use to place decaps to hit a target total decapacitance value. After characterizing the ASAP7 decaps using Voltus, the nominal capacitance is filled into the ``size`` list:
Expand Down
8 changes: 4 additions & 4 deletions hammer/config/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ vlsi.inputs:

constraints: [] # Manual hierarchical constraints. Overrides generic constraints on a per module basis.
# Should be a list along the lines of [{"module1": <list of other hammer constraints>}].
# For example [{"mod1": [vlsi.inputs.default_output_load: 2], "mod2": [vlsi.inputs.clocks:<clock constraints>] }].
# For example [{"mod1": [vlsi.inputs.default_output_load: "2 pF"], "mod2": [vlsi.inputs.clocks:<clock constraints>] }].

ilms: [] # ILMs for hierarchical mode.
# ILM struct (ILMStruct) members:
Expand Down Expand Up @@ -188,13 +188,13 @@ vlsi.inputs:
# group (str) - Optional. The name of the clock group this clock belongs to. Clocks in the same group will not be marked as asynchronous.
# Clocks with no group specified will all be placed in separate groups and thus marked as asynchronous to each other and all other groups.

default_output_load: 1 # Default output pin load capacitance.
# Default: 1pF
default_output_load: "1 pF" # Default output pin load capacitance.
# type: CapacitanceValue

output_loads: [] # List of output load constraints.
# Each item in the list should be a struct with the following members:
# name (str) - Name of the output load (e.g. io_out)
# load (float) - Output load capacitance in pF.
# load (CapacitanceValue) - Output load capacitance (e.g. "1 pF").

delays: [] # List of delay constraints.
# These either constrain inputs to arrive after a certain delay relative
Expand Down
2 changes: 1 addition & 1 deletion hammer/config/defaults_types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ vlsi.inputs:
clocks: list[dict[str, Any]]

# Default output pin load capacitance.
default_output_load: int
default_output_load: str

# List of output load constraints.
output_loads: list[dict[str, str]]
Expand Down
20 changes: 18 additions & 2 deletions hammer/par/innovus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ def output_ilm_sdcs(self) -> List[str]:
def env_vars(self) -> Dict[str, str]:
v = dict(super().env_vars)
v["INNOVUS_BIN"] = self.get_setting("par.innovus.innovus_bin")
if self.version() >= self.version_number("221"): # support critical region resynthesis with DDI
v["PATH"] = f'{os.environ.copy()["PATH"]}:{os.path.dirname(self.get_setting("par.innovus.innovus_bin").replace("INNOVUS", "GENUS"))}'
return v

@property
Expand Down Expand Up @@ -327,7 +329,8 @@ def init_design(self) -> bool:
verbose_append(f"set_db route_design_top_layer {layers[1]}")

# Set design effort.
verbose_append("set_db design_flow_effort {}".format(self.get_setting("par.innovus.design_flow_effort")))
verbose_append(f"set_db design_flow_effort {self.get_setting('par.innovus.design_flow_effort')}")
verbose_append(f"set_db design_power_effort {self.get_setting('par.innovus.design_power_effort')}")

# Set "don't use" cells.
for l in self.generate_dont_use_commands():
Expand Down Expand Up @@ -362,7 +365,7 @@ def place_bumps(self) -> bool:
# TODO: Fix this once the stackup supports vias ucb-bar/hammer#354
block_layer = self.get_setting("vlsi.technology.bump_block_cut_layer") # type: str
for bump in bumps.assignments:
self.append("create_bump -cell {cell} -location_type cell_center -name_format \"Bump_{c}.{r}\" -orient r0 -location \"{x} {y}\"".format(
self.append("create_bump -allow_overlap_control keep_all -cell {cell} -location_type cell_center -name_format \"Bump_{c}.{r}\" -orient r0 -location \"{x} {y}\"".format(
cell = bump.custom_cell if bump.custom_cell is not None else bumps.cell,
c = bump.x,
r = bump.y,
Expand Down Expand Up @@ -523,6 +526,19 @@ def clock_tree(self) -> bool:
'''.format(sdc=self.post_synth_sdc), clean=True)
if len(self.get_clock_ports()) > 0:
# Ignore clock tree when there are no clocks
# If special cells are specified, explicitly set them instead of letting tool infer from libs
buffers = self.technology.get_special_cell_by_type(CellType.CTSBuffer)[0].name
if len(buffers) > 0:
self.append(f"set_db cts_buffer_cells {{{' '.join(buffers)}}}")
inverters = self.technology.get_special_cell_by_type(CellType.CTSInverter)[0].name
if len(inverters) > 0:
self.append(f"set_db cts_inverter_cells {{{' '.join(inverters)}}}")
gates = self.technology.get_special_cell_by_type(CellType.CTSGate)[0].name
if len(gates) > 0:
self.append(f"set_db cts_clock_gating_cells {{{' '.join(gates)}}}")
logics = self.technology.get_special_cell_by_type(CellType.CTSLogic)[0].name
if len(logics) > 0:
self.append(f"set_db cts_logic_cells {{{' '.join(logics)}}}")
self.verbose_append("create_clock_tree_spec")
if bool(self.get_setting("par.innovus.use_cco")):
# -hold is a secret flag for ccopt_design (undocumented anywhere)
Expand Down
14 changes: 8 additions & 6 deletions hammer/par/innovus/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@

par.innovus:
# Location of the binary.
innovus_bin: "${cadence.cadence_home}/INNOVUS/INNOVUS${par.innovus.version}/bin/innovus"
innovus_bin: "${cadence.cadence_home}/DDI/DDI${par.innovus.version}/INNOVUS${par.innovus.version}/bin/innovus"
innovus_bin_meta: lazysubst # we want later overrides to be able to affect this

# Innovus version to use.
# Used to locate the binary - e.g. the '171' in ${cadence.cadence_home}/INNOVUS/INNOVUS171/bin/innovus
# 171_ISR3 supports ILMs properly in contrast to 171.
version: "171_ISR3"
# Used to locate the binary - e.g. the '221' in ${cadence.cadence_home}/DDI/DDI221/INNOVUS2211/bin/innovus
version: "221"

# Design flow effort.
# Valid options: express (fastest), standard, and extreme (slowest).
# Default: express to increase turnaround speed.
design_flow_effort: "express"
design_flow_effort: "standard"

# Design power effort.
# Valid options: none, low, high.
design_power_effort: "low"

# Floorplanning SDC constraints to use.
# Valid options are:
Expand Down
30 changes: 22 additions & 8 deletions hammer/synthesis/genus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,7 @@ def do_pre_steps(self, first_step: HammerToolStep) -> bool:
def do_between_steps(self, prev: HammerToolStep, next: HammerToolStep) -> bool:
assert super().do_between_steps(prev, next)
# Write a checkpoint to disk.
if self.version() >= self.version_number("221"):
# -common now enables database reading in Innovus
self.verbose_append("write_db -common -to_file pre_{step}".format(step=next.name))
else:
self.verbose_append("write_db -to_file pre_{step}".format(step=next.name))
self.verbose_append("write_db -to_file pre_{step}".format(step=next.name))
return True

def do_post_steps(self) -> bool:
Expand Down Expand Up @@ -198,10 +194,9 @@ def init_environment(self) -> bool:
# Clock gating setup
if self.get_setting("synthesis.clock_gating_mode") == "auto":
verbose_append("set_db lp_clock_gating_infer_enable true")
# Innovus will create instances named CLKGATE_foo, CLKGATE_bar, etc.
# Genus will create instances named CLKGATE_foo, CLKGATE_bar, etc.
verbose_append("set_db lp_clock_gating_prefix {CLKGATE}")
verbose_append("set_db lp_insert_clock_gating true")
verbose_append("set_db lp_insert_clock_gating_incremental true")
verbose_append("set_db lp_clock_gating_register_aware true")

# Set up libraries.
Expand Down Expand Up @@ -287,6 +282,22 @@ def retime_modules(self) -> bool:
return True

def syn_generic(self) -> bool:
# Add clock mapping flow if special cells are specified
if self.version() >= self.version_number("211"):
buffers = self.technology.get_special_cell_by_type(CellType.CTSBuffer)[0].name
if len(buffers) > 0:
self.append(f"set_db cts_buffer_cells {{{' '.join(buffers)}}}")
inverters = self.technology.get_special_cell_by_type(CellType.CTSInverter)[0].name
if len(inverters) > 0:
self.append(f"set_db cts_inverter_cells {{{' '.join(inverters)}}}")
gates = self.technology.get_special_cell_by_type(CellType.CTSGate)[0].name
if len(gates) > 0:
self.append(f"set_db cts_clock_gating_cells {{{' '.join(gates)}}}")
logics = self.technology.get_special_cell_by_type(CellType.CTSLogic)[0].name
if len(logics) > 0:
self.append(f"set_db cts_logic_cells {{{' '.join(logics)}}}")
if any(c > 0 for c in [len(buffers), len(inverters), len(gates), len(logics)]):
self.append("set_db map_clock_tree true")
self.verbose_append("syn_generic")
return True

Expand Down Expand Up @@ -348,7 +359,10 @@ def write_outputs(self) -> bool:
verbose_append("write_hdl > {}".format(self.mapped_v_path))
if self.hierarchical_mode.is_nonleaf_hierarchical() and self.version() >= self.version_number("191"):
verbose_append("write_hdl -exclude_ilm > {}".format(self.mapped_hier_v_path))
verbose_append("write_script > {}.mapped.scr".format(top))
if self.version() >= self.version_number("221"):
verbose_append("write_template -full -outfile {}.mapped.scr".format(top))
else:
verbose_append("write_script > {}.mapped.scr".format(top))
corners = self.get_mmmc_corners()
if corners:
# First setup corner is default view
Expand Down
6 changes: 3 additions & 3 deletions hammer/synthesis/genus/defaults.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Default settings for synthesis in Genus, for project/technology configuration and overriding.
synthesis.genus:
# Location of the binary.
genus_bin: "${cadence.cadence_home}/GENUS/GENUS${synthesis.genus.version}/bin/genus"
genus_bin: "${cadence.cadence_home}/DDI/DDI${synthesis.genus.version}/GENUS${synthesis.genus.version}/bin/genus"
genus_bin_meta: lazysubst # we want later overrides to be able to affect this

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

# Generate the TCL file but do not run it yet.
generate_only: false
3 changes: 3 additions & 0 deletions hammer/tech/specialcells.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class CellType(str, Enum):
TapCell = "tapcell"
Driver = "driver"
CTSBuffer = "ctsbuffer"
CTSInverter = "ctsinverter"
CTSGate = "ctsgate"
CTSLogic = "ctslogic"


class SpecialCell(BaseModel):
Expand Down
2 changes: 1 addition & 1 deletion hammer/vlsi/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ def name_bump(self, definition: BumpsDefinition, assignment: BumpAssignment) ->

OutputLoadConstraint = NamedTuple('OutputLoadConstraint', [
('name', str),
('load', float)
('load', CapacitanceValue)
])


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 @@ -1558,7 +1558,7 @@ def get_output_load_constraints(self) -> List[OutputLoadConstraint]:
for load_src in output_loads:
load = OutputLoadConstraint(
name=str(load_src["name"]),
load=float(load_src["load"])
load=CapacitanceValue(load_src["load"])
)
output.append(load)
return output
Expand Down
10 changes: 6 additions & 4 deletions hammer/vlsi/hammer_vlsi_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -2170,7 +2170,9 @@ def sdc_pin_constraints(self) -> str:
"""Generate a fragment for I/O pin constraints."""
output = [] # type: List[str]

default_output_load = float(self.get_setting("vlsi.inputs.default_output_load"))
output.append("set_units -capacitance fF")

default_output_load = CapacitanceValue(self.get_setting("vlsi.inputs.default_output_load")).value_in_units("fF", round_zeroes = True)

# Specify default load.
output.append("set_load {load} [all_outputs]".format(
Expand All @@ -2179,14 +2181,14 @@ def sdc_pin_constraints(self) -> str:

# Also specify loads for specific pins.
for load in self.get_output_load_constraints():
output.append("set_load {load} [get_port \"{name}\"]".format(
load=load.load,
output.append("set_load {load} [get_port {name}]".format(
load=load.load.value_in_units("fF", round_zeroes = True),
name=load.name
))

# Also specify delays for specific pins.
for delay in self.get_delay_constraints():
output.append("set_{direction}_delay {delay} -clock {clock} [get_port \"{name}\"]".format(
output.append("set_{direction}_delay {delay} -clock {clock} [get_port {name}]".format(
delay=delay.delay.value_in_units(self.get_time_unit().value_prefix + self.get_time_unit().unit),
clock=delay.clock,
direction=delay.direction,
Expand Down

0 comments on commit 07d430d

Please sign in to comment.