Skip to content

Commit

Permalink
New Method For Getting Timing Libs (#706)
Browse files Browse the repository at this point in the history
Co-authored-by: ken_ho <ken_ho@eecs.berkeley.edu>
  • Loading branch information
kenhoberkeley and ken_ho authored Feb 2, 2023
1 parent cc0927d commit cbc1414
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 0 deletions.
6 changes: 6 additions & 0 deletions hammer/config/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ vlsi.technology:
# the extracted contents of foobar.tar.gz.
# If this is not specified, then the tarballs will be extracted to obj/<tech_dir>/extracted/.

timing_lib_pref: "NLDM"
# Select a timing lib preference, available options include:
# NLDM, ECSM, and CCS (lower or upper case acceptable).
# If no preference is specified, then the following preference order is followed:
# NLDM -> ECSM -> CCS

# General VLSI inputs.
# These will vary per run of hammer-vlsi.
vlsi.inputs:
Expand Down
3 changes: 3 additions & 0 deletions hammer/config/defaults_types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ vlsi.technology:
# Path where tarballs have been extracted.
extracted_tarballs_dir: Optional[str]

# A preference for the timing lib.
timing_lib_pref: str

# General VLSI inputs.
# These will vary per run of hammer-vlsi.
vlsi.inputs:
Expand Down
39 changes: 39 additions & 0 deletions hammer/tech/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,45 @@ def paths_func(lib: Library) -> List[str]:
is_file=True
)

def get_timing_lib_with_preference(self, lib_pref: str = "NLDM") -> LibraryFilter:
"""
Select ASCII .lib timing libraries. Prefers NLDM, then ECSM, then CCS if multiple are present for
a single given .lib.
"""
lib_pref = lib_pref.upper()

def paths_func(lib: Library) -> List[str]:
pref_list = ["NLDM", "ECSM", "CCS"]
index = None

try:
index = pref_list.index(lib_pref)
except:
raise ValueError("Library preference must be one of NLDM, ECSM, or CCS.")
pref_list.insert(0, pref_list.pop(index))

for elem in pref_list:
if elem == "NLDM":
if lib.nldm_liberty_file is not None:
return [lib.nldm_liberty_file]
elif elem == "ECSM":
if lib.ecsm_liberty_file is not None:
return [lib.ecsm_liberty_file]
elif elem == "CCS":
if lib.ccs_liberty_file is not None:
return [lib.ccs_liberty_file]
else:
pass

return []

return LibraryFilter(
tag="timing_lib_with_nldm",
description="ECSM/CCS/NLDM timing lib (liberty ASCII .lib)",
paths_func=paths_func,
is_file=True
)

@property
def qrc_tech_filter(self) -> LibraryFilter:
"""
Expand Down
136 changes: 136 additions & 0 deletions tests/test_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import List, Dict, Any
import sys
from pathlib import Path
from abc import ABCMeta, abstractmethod

import pytest

Expand Down Expand Up @@ -69,6 +70,141 @@ def test_tool_format(lib, filt) -> List[str]:
"drink {0}/orange".format(tech_dir)
]

def test_timing_lib_with_preference_filter(self, tmp_path, request) -> None:
"""
Test that the library preference filter works as expected.
"""
import hammer.config as hammer_config

tech_dir_base = str(tmp_path)
tech_name = request.function.__name__ # create unique technology folders for each test
tech_dir = HammerToolTestHelpers.create_tech_dir(tech_dir_base, tech_name)
tech_json_filename = os.path.join(tech_dir, f"{tech_name}.tech.json")
tech_json = {
"name": f"{tech_name}",
"libraries": [
{
"ecsm_liberty_file": "eggs.ecsm",
"ccs_liberty_file": "eggs.ccs",
"nldm_liberty_file": "eggs.nldm"
},
{
"ccs_liberty_file": "custard.ccs",
"nldm_liberty_file": "custard.nldm"
},
{
"nldm_liberty_file": "noodles.nldm"
},
{
"ecsm_liberty_file": "eggplant.ecsm"
},
{
"ccs_liberty_file": "cookies.ccs"
}
]

}
with open(tech_json_filename, "w") as f:
f.write(json.dumps(tech_json, cls=HammerJSONEncoder, indent=4))
(Path(tech_dir) / "eggs.ecsm").write_text("eggs ecsm")
(Path(tech_dir) / "eggs.ccs").write_text("eggs ccs")
(Path(tech_dir) / "eggs.nldm").write_text("eggs nldm")
(Path(tech_dir) / "custard.ccs").write_text("custard ccs")
(Path(tech_dir) / "custard.nldm").write_text("custard nldm")
(Path(tech_dir) / "noodles.nldm").write_text("noodles nldm")
(Path(tech_dir) / "eggplant.ecsm").write_text("eggplant ecsm")
(Path(tech_dir) / "cookies.ccs").write_text("cookies ccs")

sys.path.append(tech_dir_base)
tech = self.get_tech(hammer_tech.HammerTechnology.load_from_module(tech_name))
tech.cache_dir = tech_dir

logger = HammerVLSILogging.context("")
logger.logging_class.clear_callbacks()
tech.logger = logger

class Tool(hammer_vlsi.DummyHammerTool, metaclass=ABCMeta):

def __init__(self, removal=False):
self.geek = "GeekforGeeks"


lib_outputs = [] # type: List[str]
@property
def steps(self) -> List[hammer_vlsi.HammerToolStep]:
return self.make_steps_from_methods([
self.step_one,
self.step_two,
self.step_three
])

# Test default NLDM preference.
def step_one(self) -> bool:
Tool.lib_outputs = tech.read_libs([hammer_tech.filters.get_timing_lib_with_preference()],
hammer_tech.HammerTechnologyUtils.to_plain_item,
must_exist=False)
return True

# Test lower case key input.
def step_two(self) -> bool:
Tool.lib_outputs = tech.read_libs([hammer_tech.filters.get_timing_lib_with_preference("ecsm")],
hammer_tech.HammerTechnologyUtils.to_plain_item,
must_exist=False)
return True

def step_three(self) -> bool:
Tool.lib_outputs = tech.read_libs([hammer_tech.filters.get_timing_lib_with_preference("CCS")],
hammer_tech.HammerTechnologyUtils.to_plain_item,
must_exist=False)
return True

test = Tool()
test.logger = HammerVLSILogging.context("")
test.run_dir = str(tmp_path / "rundir")
test.technology = tech
test.set_database(hammer_config.HammerDatabase())
tech.set_database(hammer_config.HammerDatabase())

# Test the default case:
test.run(hook_actions=[
hammer_vlsi.HammerTool.make_removal_hook("step_two"),
hammer_vlsi.HammerTool.make_removal_hook("step_three")])

assert set(Tool.lib_outputs) == {
"{0}/eggs.nldm".format(tech_dir),
"{0}/custard.nldm".format(tech_dir),
"{0}/noodles.nldm".format(tech_dir),
"{0}/eggplant.ecsm".format(tech_dir),
"{0}/cookies.ccs".format(tech_dir)
}

# Test the lower case input key and non-default ECSM preference.
test.run(hook_actions=[
hammer_vlsi.HammerTool.make_removal_hook("step_one"),
hammer_vlsi.HammerTool.make_removal_hook("step_three")])

assert set(Tool.lib_outputs) == {
"{0}/eggs.ecsm".format(tech_dir),
"{0}/custard.nldm".format(tech_dir),
"{0}/noodles.nldm".format(tech_dir),
"{0}/eggplant.ecsm".format(tech_dir),
"{0}/cookies.ccs".format(tech_dir)
}

# Test the non-default CCS preference.
test.run(hook_actions=[
hammer_vlsi.HammerTool.make_removal_hook("step_one"),
hammer_vlsi.HammerTool.make_removal_hook("step_two")])

assert set(Tool.lib_outputs) == {
"{0}/eggs.ccs".format(tech_dir),
"{0}/custard.ccs".format(tech_dir),
"{0}/noodles.nldm".format(tech_dir),
"{0}/eggplant.ecsm".format(tech_dir),
"{0}/cookies.ccs".format(tech_dir)
}


def test_timing_lib_ecsm_filter(self, tmp_path, request) -> None:
"""
Test that the ECSM-first filter works as expected.
Expand Down

0 comments on commit cbc1414

Please sign in to comment.