Skip to content

Commit

Permalink
complete reformatting
Browse files Browse the repository at this point in the history
  • Loading branch information
ken_ho committed Jan 27, 2023
1 parent 29614ea commit 138a0b9
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 92 deletions.
32 changes: 32 additions & 0 deletions hammer/config/config_src.py
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,11 @@ def get(self, key: str) -> Any:
"""Alias for get_setting()."""
return self.get_setting(key)

def get_suffix(self, key: str, suffix: str) -> Any:
"""Alias for get_setting_suffix()."""
return self.get_setting_suffix(key, suffix)


def __getitem__(self, key: str) -> Any:
"""Alias for get_setting()."""
return self.get_setting(key)
Expand All @@ -755,6 +760,33 @@ def get_setting(self, key: str, nullvalue: Any = None, check_type: bool = True)
value = self.get_config()[key]
return nullvalue if value is None else value

def get_setting_suffix(self, key: str, suffix: str, nullvalue: Any = None, check_type: bool = True) -> Any:
"""
Retrieve a key, first trying with a suffix but returning base if found.
:param key: Desired key.
:param suffix: Required suffix to search for.
:param nullvalue: Value to return out for nulls.
:param check_type: Flag to enforce type checking
:return: The given config
"""
default = key
override = default + "_" + suffix
value = None
try:
value = self.get_config()[override]
except:
try:
value = self.get_config()[default]
except:
raise KeyError(f"Both base key: {default} and overriden key: {override} are missing.")

if default not in self.defaults:
warn(f"Base key: {default} does not have a default implementation")
if check_type:
self.check_setting(default)
return nullvalue if value is None else value

def set_setting(self, key: str, value: Any) -> None:
"""
Set the given key. The setting will be placed into the runtime dictionary.
Expand Down
30 changes: 16 additions & 14 deletions hammer/pcb/generic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,18 +111,19 @@ def create_bom_builder_pindata_txt(self) -> bool:
sorted_assignments = naming_scheme.sort_by_name(bumps, assignments)

# Use post-shrink pitch
pitch = self.technology.get_post_shrink_length(bumps.pitch)
pitch_x = self.technology.get_post_shrink_length(bumps.pitch_x)
pitch_y = self.technology.get_post_shrink_length(bumps.pitch_y)

# There is no meaningful verion for this file
# Set the units to metric (mm)
output = "VER 0.0\nUNIT M\n"
x_offset = ((1 - bumps.x) * pitch) / 2 # type: Decimal
y_offset = ((1 - bumps.y) * pitch) / 2 # type: Decimal
x_offset = ((1 - bumps.x) * pitch_x) / 2 # type: Decimal
y_offset = ((1 - bumps.y) * pitch_y) / 2 # type: Decimal
for bump in sorted_assignments:
# note that the flip-chip mirroring happens here
name = naming_scheme.name_bump(bumps, bump)
x = um2mm(Decimal(str(bumps.x - bump.x)) * pitch + x_offset, 3)
y = um2mm(Decimal(str(bump.y - 1)) * pitch + y_offset, 3)
x = um2mm(Decimal(str(bumps.x - bump.x)) * pitch_x + x_offset, 3)
y = um2mm(Decimal(str(bump.y - 1)) * pitch_y + y_offset, 3)
# Fields in order (with valid options):
# Name
# X position (mm)
Expand Down Expand Up @@ -182,14 +183,15 @@ def create_footprint(self) -> bool:
bumps, assignments = self.get_bumps_and_assignments()

# Use post-shrink pitch
pitch = self.technology.get_post_shrink_length(bumps.pitch)
pitch_x = self.technology.get_post_shrink_length(bumps.pitch_x)
pitch_y = self.technology.get_post_shrink_length(bumps.pitch_y)

# Here is a good ref for the PADS V9 format:
# ftp://ftp.freecalypso.org/pub/CAD/PADS/pdfdocs/Plib_ASCII.pdf

# for now, let's make the outline 4 pitches larger than the bump array
outline_width = ((bumps.x + 3) * pitch)
outline_height = ((bumps.y + 3) * pitch)
outline_width = ((bumps.x + 3) * pitch_x)
outline_height = ((bumps.y + 3) * pitch_y)

output = "*PADS-LIBRARY-PCB-DECALS-V9*\n\n"
# Fields in order from left to right
Expand All @@ -216,20 +218,20 @@ def create_footprint(self) -> bool:
# we'll dog-ear the outline to indicate the reference bump in the top left
# x and y are in mm, not um
output += "{x} {y}\n".format(x=um2mm(-outline_width/2, 3), y=um2mm(-outline_height/2, 3))
output += "{x} {y}\n".format(x=um2mm(-outline_width/2, 3), y=um2mm( outline_height/2 - 2*pitch, 3))
output += "{x} {y}\n".format(x=um2mm(-outline_width/2 + 2*pitch, 3), y=um2mm( outline_height/2, 3))
output += "{x} {y}\n".format(x=um2mm(-outline_width/2, 3), y=um2mm( outline_height/2 - 2*pitch_y, 3))
output += "{x} {y}\n".format(x=um2mm(-outline_width/2 + 2*pitch_x, 3), y=um2mm( outline_height/2, 3))
output += "{x} {y}\n".format(x=um2mm( outline_width/2, 3), y=um2mm( outline_height/2, 3))
output += "{x} {y}\n".format(x=um2mm( outline_width/2, 3), y=um2mm(-outline_height/2, 3))
output += "{x} {y}\n".format(x=um2mm(-outline_width/2, 3), y=um2mm(-outline_height/2, 3))

# create all of the terminals
x_offset = ((1 - bumps.x) * pitch) / 2 # type: Decimal
y_offset = ((1 - bumps.y) * pitch) / 2 # type: Decimal
x_offset = ((1 - bumps.x) * pitch_x) / 2 # type: Decimal
y_offset = ((1 - bumps.y) * pitch_y) / 2 # type: Decimal
naming_scheme = self.naming_scheme
for bump in bumps.assignments:
# note that the flip-chip mirroring happens here
x = um2mm(Decimal(str(bumps.x - bump.x)) * pitch + x_offset, 3)
y = um2mm(Decimal(str(bump.y - 1)) * pitch + y_offset, 3)
x = um2mm(Decimal(str(bumps.x - bump.x)) * pitch_x + x_offset, 3)
y = um2mm(Decimal(str(bump.y - 1)) * pitch_y + y_offset, 3)
label = naming_scheme.name_bump(bumps, bump)
output += "T{x} {y} {x} {y} {label}\n".format(x=x, y=y, label=label)

Expand Down
11 changes: 11 additions & 0 deletions hammer/tech/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,17 @@ def get_setting(self, key: str) -> Any:
print(e) # TODO: fix the root cause
return None

def get_setting_suffix(self, key: str) -> Any:
"""Get a particular setting from the database with a suffix.
"""
try:
return self._database.get(key)
except AttributeError:
raise ValueError("Internal error: no database set by hammer-vlsi")
except KeyError as e: # this function is expected to return Optional[str] from extracted_tarballs_dir()
print(e) # TODO: fix the root cause
return None

def has_setting(self, key: str) -> bool:
"""Check if a setting exists in the database.
"""
Expand Down
22 changes: 22 additions & 0 deletions hammer/vlsi/hammer_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,19 @@ def get_setting(self, key: str, nullvalue: Any = None) -> Any:
except AttributeError:
raise ValueError("Internal error: no database set by hammer-vlsi")

def get_setting_suffix(self, key: str, suffix: str, nullvalue: Any = None) -> Any:
"""
Get a particular setting from the database with a suffix.
:param key: Key of the setting to receive.
:param suffix: Suffix to search for on top of the base.
:param nullvalue: Value to return in case of null (leave as None to use the default).
"""
try:
return self._database.get_setting_suffix(key, suffix, nullvalue)
except AttributeError:
raise ValueError("Internal error: no database set by hammer-vlsi")

def set_setting(self, key: str, value: Any) -> None:
"""
Set a runtime setting in the database.
Expand Down Expand Up @@ -1092,6 +1105,15 @@ def get_all_ground_nets(self) -> List[Supply]:
def get_independent_ground_nets(self) -> List[Supply]:
return list(filter(lambda x: x.tie is None, self.get_all_ground_nets()))

def _get_by_bump_dim_pitch(self) -> Dict[str, float]:
"""
Return pitches in the x and y directions.
"""
pitch_x = self.get_setting_suffix('vlsi.inputs.bumps.pitch', 'x')
pitch_y = self.get_setting_suffix('vlsi.inputs.bumps.pitch', 'y')

return {'x': pitch_x, 'y': pitch_y}

def get_bumps(self) -> Optional[BumpsDefinition]:
bumps_mode = self.get_setting("vlsi.inputs.bumps_mode")
if bumps_mode == "empty":
Expand Down
61 changes: 2 additions & 59 deletions hammer/vlsi/hammer_vlsi_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -775,15 +775,8 @@ def _get_by_tracks_metal_setting(self, key: str, layer_name: str) -> Any:
:param key: The base key name (e.g. track_spacing). Do not include the namespace or metal override.
:return: The value associated with the key, after applying any metal overrides
"""
default = "par.generate_power_straps_options.by_tracks." + key
override = default + "_" + layer_name
try:
return self.get_setting(override)
except KeyError:
try:
return self.get_setting(default)
except KeyError:
raise ValueError("No value set for key {}".format(default))
key = "par.generate_power_straps_options.by_tracks." + key
return self.get_setting_suffix(key, layer_name)

def _get_by_tracks_track_pitch(self, layer_name: str) -> int:
"""
Expand All @@ -804,32 +797,6 @@ def _get_by_tracks_track_pitch(self, layer_name: str) -> int:
consumed_tracks = 2 * track_width + track_spacing
return round(consumed_tracks / power_utilization)

def _get_by_bump_dim_setting(self, key: str, dim_name: str) -> Any:
"""
Return bump settings based on the dimension.
:param key: The base key name (e.g., pitch). Do not include the namespace or metal override
:param dim_name: Provide a dimensional argument (x, y, z!)
"""
default = "vlsi.inputs.bumps." + key
override = default + "_" + dim_name

try:
return self.get_setting(override)
except KeyError:
try:
return self.get_setting(default)
except KeyError:
raise ValueError("No value set for key {}".format(default))

def _get_by_bump_dim_pitch(self) -> Dict[str, float]:
"""
Return pitches in the x and y directions.
"""
pitch_x = self._get_by_bump_dim_setting('pitch', 'x')
pitch_y = self._get_by_bump_dim_setting('pitch', 'y')

return {'x': pitch_x, 'y': pitch_y}

@abstractmethod
def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, blockage_spacing: Decimal, pitch: Decimal, width: Decimal, spacing: Decimal, offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool) -> List[str]:
"""
Expand Down Expand Up @@ -892,30 +859,6 @@ def signoff_results(self) -> int:
"""
pass

class DummyParTool(HammerPlaceAndRouteTool):
"""
This is a dummy implementation of PAR tool.
"""

def fill_outputs(self) -> bool:
return True

def specify_power_straps(self, layer_name: str, bottom_via_layer_name: str, blockage_spacing: Decimal, pitch: Decimal, width: Decimal, spacing: Decimal, offset: Decimal, bbox: Optional[List[Decimal]], nets: List[str], add_pins: bool) -> List[str]:
return []

@property
def specify_std_cell_power_straps(self, blockage_spacing: Decimal, bbox: Optional[List[Decimal]], nets: List[str]) -> List[str]:
return []
def tool_config_prefix(self) -> str:
return ""

def version_number(self, version: str) -> int:
return 1

@property
def steps(self) -> List[HammerToolStep]:
return []

class HammerDRCTool(HammerSignoffTool):

def export_config_outputs(self) -> Dict[str, Any]:
Expand Down
22 changes: 3 additions & 19 deletions tests/test_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
import hammer.config as hammer_config
from hammer.utils import add_dicts
from hammer.tech import MacroSize
from hammer.vlsi import DummyHammerTool, DummyParTool
from hammer.vlsi import DummyHammerTool
from hammer.vlsi.constraints import DelayConstraint, ClockPort, PinAssignment, PinAssignmentError, \
PinAssignmentSemiAutoError, PlacementConstraint, PlacementConstraintType, Margins, \
BumpAssignment, BumpsDefinition, BumpsPinNamingScheme, DecapConstraint
from hammer.vlsi.units import TimeValue, CapacitanceValue

from hammer.par.mockpar import MockPlaceAndRoute

class TestClockConstraint:
def check_src(self, yaml_src: str, ref_port: ClockPort) -> None:
Expand Down Expand Up @@ -192,30 +192,14 @@ def test_bump_naming(self) -> None:

definition = BumpsDefinition(x=8421,y=8421, pitch_x=Decimal("1.23"), pitch_y=Decimal("3.14"), global_x_offset=0, global_y_offset=0, cell="bumpcell",assignments=assignments)
assert BumpsPinNamingScheme.A1.name_bump(definition, assignments[0]) == "AAAA8421"

def test_get_by_bump_dim_setting(self) -> None:
"""
Test that we can extract a bump related key by dimensionality.
Note that the dimension is not optional because the underlying code now requires x, y.
"""
db = hammer_config.HammerDatabase()
db.update_project([{"vlsi.inputs.bumps.pitch": 1}, {"vlsi.inputs.bumps.pitch_b_x": 2}])
tool = DummyParTool()
tool.set_database(db)

pitch_x = tool._get_by_bump_dim_setting('pitch', 'x')
assert pitch_x == 1

pitch_x = tool._get_by_bump_dim_setting('pitch_b', 'x')
assert pitch_x == 2

def test_get_by_bump_dim_pitch(self) -> None:
"""
Test the extraction of x, y, pitches.
"""
db = hammer_config.HammerDatabase()
db.update_project([{"vlsi.inputs.bumps.pitch": 1}])
tool = DummyParTool()
tool = MockPlaceAndRoute()
tool.set_database(db)

pitch_set = tool._get_by_bump_dim_pitch()
Expand Down
2 changes: 2 additions & 0 deletions tests/test_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,8 @@ def test_bumps(self, tmp_path, request) -> None:
"y": 14,
"pitch": 200,
"cell": "MY_REDACTED_BUMP_CELL",
"global_x_offset": 1,
"global_y_offset": 1,
"assignments": [
{"name": "reset", "x": 5, "y": 3},
{"no_connect": true, "x": 5, "y": 4},
Expand Down

0 comments on commit 138a0b9

Please sign in to comment.