Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Method For Getting Timing Libs #706

Merged
merged 2 commits into from
Feb 2, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions hammer/config/defaults.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ 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"
harrisonliew marked this conversation as resolved.
Show resolved Hide resolved

# 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