diff --git a/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning.json b/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning.json index aa27bf74f..bbf6d0d6b 100644 --- a/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning.json +++ b/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning.json @@ -4,18 +4,14 @@ "time_unit": "1 ns", "installs": [ { - "path": "$SKY130A", - "base var": "technology.sky130.sky130A" - }, - { - "path": "tech-sky130-cache", - "base var": "" + "id": "$SKY130A", + "path": "technology.sky130.sky130A" } ], "libraries": [ { - "lef file": "tech-sky130-cache/sky130_fd_sc_hd.tlef", - "verilog sim": "tech-sky130-cache/primitives.v", + "lef_file": "tech-sky130-cache/sky130_fd_sc_hd__nom.tlef", + "verilog_sim": "tech-sky130-cache/primitives.v", "provides": [ { "lib_type": "technology" diff --git a/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning_nda.json b/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning_nda.json index d3a27a59a..9d9674759 100644 --- a/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning_nda.json +++ b/hammer/technology/sky130/extra/sky130-tech-gen-files/beginning_nda.json @@ -4,41 +4,36 @@ "time_unit": "1 ns", "installs": [ { - "path": "$SKY130_NDA", - "base var": "technology.sky130.sky130_nda" + "id": "$SKY130_NDA", + "path": "technology.sky130.sky130_nda" }, { - "path": "$SKY130A", - "base var": "technology.sky130.sky130A" - }, - { - "path": "tech-sky130-cache", - "base var": "" + "id": "$SKY130A", + "path": "technology.sky130.sky130A" } ], - "layer map file": "$SKY130_NDA/s8/V2.0.1/VirtuosoOA/libs/technology_library/technology_library.layermap", - "drc decks": [ + "layer_map_file": "$SKY130_NDA/s8/V2.0.1/VirtuosoOA/libs/technology_library/technology_library.layermap", + "drc_decks": [ { - "tool name": "calibre", - "deck name": "all_drc", + "tool_name": "calibre", + "deck_name": "all_drc", "path": "$SKY130_NDA/s8/V2.0.1/DRC/Calibre/s8_drcRules" } ], "additional_drc_text": "", - "lvs decks": [ + "lvs_decks": [ { - "tool name": "calibre", - "deck name": "all_lvs", - "old path": "$SKY130_NDA/s8/V2.0.1/LVS/Calibre/lvsRules_s8", - "path": "tech-sky130-cache/lvsControlFile_s8" + "tool_name": "calibre", + "deck_name": "all_lvs", + "old_path": "$SKY130_NDA/s8/V2.0.1/LVS/Calibre/lvsRules_s8", + "path": "cache/lvsControlFile_s8" } ], "additional_lvs_text": "", "libraries": [ { - "lef file": "tech-sky130-cache/sky130_fd_sc_hd.tlef", - "spice file": "$SKY130_NDA/s8/V2.0.1/LVS/Calibre/source.cdl", - "verilog sim": "tech-sky130-cache/primitives.v", + "lef_file": "cache/sky130_fd_sc_hd__nom.tlef", + "verilog_sim": "cache/primitives.v", "provides": [ { "lib_type": "technology" diff --git a/hammer/technology/sky130/extra/sky130-tech-gen-files/cells.json b/hammer/technology/sky130/extra/sky130-tech-gen-files/cells.json index 64e578d39..440b8afcf 100644 --- a/hammer/technology/sky130/extra/sky130-tech-gen-files/cells.json +++ b/hammer/technology/sky130/extra/sky130-tech-gen-files/cells.json @@ -1,18 +1,54 @@ { - "physical only cells list": [ + "physical_only_cells_list": [ "sky130_fd_sc_hd__tap_1", "sky130_fd_sc_hd__tap_2", "sky130_fd_sc_hd__tapvgnd_1", "sky130_fd_sc_hd__tapvpwrvgnd_1", "sky130_fd_sc_hd__fill_1", "sky130_fd_sc_hd__fill_2", "sky130_fd_sc_hd__fill_4", "sky130_fd_sc_hd__fill_8", "sky130_fd_sc_hd__diode_2" ], - "dont use list": [ + "dont_use_list": [ "*sdf*", - "sky130_fd_sc_hd__probe_p_8" + "sky130_fd_sc_hd__probe_p_*", + "sky130_fd_sc_hd__probec_p_*" ], - "special cells": [ - {"cell_type": "tiehilocell", "name": ["sky130_fd_sc_hd__conb_1"]}, - {"cell_type": "endcap", "name": ["sky130_fd_sc_hd__tap_1"]}, - {"cell_type": "tapcell", "name": ["sky130_fd_sc_hd__tapvpwrvgnd_1"]}, - {"cell_type": "stdfiller", "name": ["sky130_fd_sc_hd__fill_1", "sky130_fd_sc_hd__fill_2", "sky130_fd_sc_hd__fill_4", "sky130_fd_sc_hd__fill_8"]}, - {"cell_type": "decap", "name": ["sky130_fd_sc_hd__decap_3", "sky130_fd_sc_hd__decap_4", "sky130_fd_sc_hd__decap_6", "sky130_fd_sc_hd__decap_8", "sky130_fd_sc_hd__decap_12"]} + "special_cells": [ + { + "cell_type": "tiehilocell", + "name": ["sky130_fd_sc_hd__conb_1"] + }, + { + "cell_type": "tiehicell", + "name": ["sky130_fd_sc_hd__conb_1"], + "output_ports": ["HI"] + }, + { + "cell_type": "tielocell", + "name": ["sky130_fd_sc_hd__conb_1"], + "output_ports": ["LO"] + }, + { + "cell_type": "endcap", + "name": ["sky130_fd_sc_hd__tap_1"] + }, + { + "cell_type": "tapcell", + "name": ["sky130_fd_sc_hd__tapvpwrvgnd_1"] + }, + { + "cell_type": "stdfiller", + "name": ["sky130_fd_sc_hd__fill_1", "sky130_fd_sc_hd__fill_2", "sky130_fd_sc_hd__fill_4", "sky130_fd_sc_hd__fill_8"] + }, + { + "cell_type": "decap", + "name": ["sky130_fd_sc_hd__decap_3", "sky130_fd_sc_hd__decap_4", "sky130_fd_sc_hd__decap_6", "sky130_fd_sc_hd__decap_8", "sky130_fd_sc_hd__decap_12"] + }, + { + "cell_type": "driver", + "name": ["sky130_fd_sc_hd__buf_4"], + "input_ports": ["A"], + "output_ports": ["X"] + }, + { + "cell_type": "ctsbuffer", + "name": ["sky130_fd_sc_hd__clkbuf_1"] + } ] } \ No newline at end of file diff --git a/hammer/technology/sky130/extra/sky130-tech-gen-files/stackups-gen.py b/hammer/technology/sky130/extra/sky130-tech-gen-files/stackups-gen.py new file mode 100755 index 000000000..b6abc3511 --- /dev/null +++ b/hammer/technology/sky130/extra/sky130-tech-gen-files/stackups-gen.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +# type: ignore +# tell mypy to ignore this file during typechecking +# -*- coding: utf-8 -*- +# +# Generate Hammer Sky130 tech plugin file: sky130.tech.json +# +# See LICENSE for licence details. +import sys +import json +import os + +library='sky130_fd_sc_hd' + +def main(args) -> int: + if len(args) != 3: + print("Usage: ./stackups-gen.py /path/to/sky130A stackups.json") + return 1 + + SKY130A = sys.argv[1] + + stackup = {} + stackup["name"] = library + stackup["grid_unit"] = 0.001 + stackup["metals"] = [] + + def is_float(string): + try: + float(string) + return True + except ValueError: + return False + + def get_min_from_line(line): + words = line.split() + nums = [float(w) for w in words if is_float(w)] + return min(nums) + + + tlef_path = os.path.join(SKY130A, 'libs.ref', library, 'techlef', f"{library}__min.tlef") + with open(tlef_path, 'r') as f: + metal_name = None + metal_index = 0 + lines = f.readlines() + idx = -1 + while idx < len(lines): + idx += 1 + if idx == len(lines) - 1: break + line = lines[idx] + if '#' in line: line = line[:line.index('#')] + words = line.split() + if line.startswith('LAYER') and len(words) > 1: + if words[1].startswith('li') or words[1].startswith('met'): + metal_name = words[1] + metal_index += 1 + metal = {} + metal["name"] = metal_name + metal["index"] = metal_index + + if metal_name is not None: + line = line.strip() + if line.startswith("DIRECTION"): + metal["direction"] = words[1].lower() + if line.startswith("PITCH"): + metal["pitch"] = get_min_from_line(line) + if line.startswith("OFFSET"): + metal["offset"] = get_min_from_line(line) + if line.startswith("WIDTH"): + metal["min_width"] = get_min_from_line(line) + if line.startswith("SPACINGTABLE"): + metal["power_strap_widths_and_spacings"] = [] + while ';' not in line: + idx += 1 + if idx == len(lines) - 1: break + line = lines[idx].strip() + if '#' in line: line = line[:line.index('#')] + words = line.split() + d = {} + if line.startswith("WIDTH"): + d["width_at_least"] = float(words[1]) + d["min_spacing"] = float(words[2]) + metal["power_strap_widths_and_spacings"].append(d.copy()) + if line.startswith("END"): + metal["grid_unit"] = 0.001 + stackup["metals"].append(metal.copy()) + metal_name = None + + + with open(sys.argv[2], 'w') as f: + json.dump(stackup, f, indent=2) + + return 0 + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/hammer/technology/sky130/extra/sky130-tech-gen-files/stackups.json b/hammer/technology/sky130/extra/sky130-tech-gen-files/stackups.json index 7e2e3d1e6..576f61446 100644 --- a/hammer/technology/sky130/extra/sky130-tech-gen-files/stackups.json +++ b/hammer/technology/sky130/extra/sky130-tech-gen-files/stackups.json @@ -1,11 +1,112 @@ +{ + "name": "sky130_fd_sc_hd", + "grid_unit": 0.001, + "metals": [ { - "name" : "sky130_fd_sc_hd", - "metals": [ - {"name": "li1", "index": 1, "direction": "vertical", "min_width": 0.17, "max_width": 2147483.647, "pitch": 0.34, "offset": 0.23, "power_strap_widths_and_spacings": [{"width_at_least": 0.0, "min_spacing": 0.17}]}, - {"name": "met1", "index": 2, "direction": "horizontal", "min_width": 0.14, "max_width": 2147483.647, "pitch": 0.28, "offset": 0.17, "power_strap_widths_and_spacings": [{"width_at_least": 0.0, "min_spacing": 0.14}, {"width_at_least": 3.0, "min_spacing": 0.28}]}, - {"name": "met2", "index": 3, "direction": "vertical", "min_width": 0.14, "max_width": 2147483.647, "pitch": 0.28, "offset": 0.23, "power_strap_widths_and_spacings": [{"width_at_least": 0.0, "min_spacing": 0.14}, {"width_at_least": 3.0, "min_spacing": 0.28}]}, - {"name": "met3", "index": 4, "direction": "horizontal", "min_width": 0.3, "max_width": 2147483.647, "pitch": 0.6, "offset": 0.34, "power_strap_widths_and_spacings": [{"width_at_least": 0.0, "min_spacing": 0.3}, {"width_at_least": 3.0, "min_spacing": 0.4}]}, - {"name": "met4", "index": 5, "direction": "vertical", "min_width": 0.3, "max_width": 2147483.647, "pitch": 0.6, "offset": 0.46, "power_strap_widths_and_spacings": [{"width_at_least": 0.0, "min_spacing": 0.3}, {"width_at_least": 3.0, "min_spacing": 0.4}]}, - {"name": "met5", "index": 6, "direction": "horizontal", "min_width": 1.6, "max_width": 2147483.647, "pitch": 3.2, "offset": 1.7, "power_strap_widths_and_spacings": [{"width_at_least": 0.0, "min_spacing": 1.6}]} - ] + "name": "li1", + "index": 1, + "direction": "vertical", + "pitch": 0.34, + "offset": 0.17, + "min_width": 0.17, + "power_strap_widths_and_spacings": [ + { + "width_at_least": 0.0, + "min_spacing": 0.17 + } + ], + "grid_unit": 0.001 + }, + { + "name": "met1", + "index": 2, + "direction": "horizontal", + "pitch": 0.34, + "offset": 0.17, + "min_width": 0.14, + "power_strap_widths_and_spacings": [ + { + "width_at_least": 0.0, + "min_spacing": 0.14 + }, + { + "width_at_least": 3.0, + "min_spacing": 0.28 + } + ], + "grid_unit": 0.001 + }, + { + "name": "met2", + "index": 3, + "direction": "vertical", + "pitch": 0.46, + "offset": 0.23, + "min_width": 0.14, + "power_strap_widths_and_spacings": [ + { + "width_at_least": 0.0, + "min_spacing": 0.14 + }, + { + "width_at_least": 3.0, + "min_spacing": 0.28 + } + ], + "grid_unit": 0.001 + }, + { + "name": "met3", + "index": 4, + "direction": "horizontal", + "pitch": 0.68, + "offset": 0.34, + "min_width": 0.3, + "power_strap_widths_and_spacings": [ + { + "width_at_least": 0.0, + "min_spacing": 0.3 + }, + { + "width_at_least": 3.0, + "min_spacing": 0.4 + } + ], + "grid_unit": 0.001 + }, + { + "name": "met4", + "index": 5, + "direction": "vertical", + "pitch": 0.92, + "offset": 0.46, + "min_width": 0.3, + "power_strap_widths_and_spacings": [ + { + "width_at_least": 0.0, + "min_spacing": 0.3 + }, + { + "width_at_least": 3.0, + "min_spacing": 0.4 + } + ], + "grid_unit": 0.001 + }, + { + "name": "met5", + "index": 6, + "direction": "horizontal", + "pitch": 3.4, + "offset": 1.7, + "min_width": 1.6, + "power_strap_widths_and_spacings": [ + { + "width_at_least": 0.0, + "min_spacing": 1.6 + } + ], + "grid_unit": 0.001 } + ] +} \ No newline at end of file diff --git a/hammer/technology/sky130/extra/sky130-tech-gen.py b/hammer/technology/sky130/extra/sky130-tech-gen.py index 81fedb424..b9c5c2979 100755 --- a/hammer/technology/sky130/extra/sky130-tech-gen.py +++ b/hammer/technology/sky130/extra/sky130-tech-gen.py @@ -1,94 +1,99 @@ -''' - Purpose: generate the json file required by the Hammer Sky130 tech plugin - Usage: - export PDK_ROOT= - python sky130-tech-gen.py - Output: - sky130.tech.json: specifies Sky130 PDK file locations and various details -''' - +#!/usr/bin/env python3 +# type: ignore +# tell mypy to ignore this file during typechecking +# -*- coding: utf-8 -*- +# +# Generate Hammer Sky130 tech plugin file: sky130.tech.json +# +# See LICENSE for licence details. +import sys import json import os -from pathlib import Path use_nda_files=True library='sky130_fd_sc_hd' -PDK_ROOT = os.getenv('PDK_ROOT') -if PDK_ROOT is None: - print("Error: Must set $PDK_ROOT to the directory that contains skywater-pdk and the root of the sky130A install.") - exit() -SKY130A = os.path.join(PDK_ROOT, 'share/pdk/sky130A') - -if use_nda_files: - with open('sky130-tech-gen-files/beginning_nda.json', 'r') as f: data = json.load(f) -else: - with open('sky130-tech-gen-files/beginning.json', 'r') as f: data = json.load(f) - -with open('sky130-tech-gen-files/cells.json', 'r') as f: - cells = json.load(f) -data["physical only cells list"] = cells["physical only cells list"] -data["dont use list"] = cells["dont use list"] -data["special cells"] = cells["special cells"] - -SKYWATER_LIBS = os.path.join('$SKY130A','libs.ref',library) -LIBRARY_PATH = os.path.join(SKY130A,'libs.ref',library,'lib') -lib_corner_files=os.listdir(LIBRARY_PATH) -for cornerfilename in lib_corner_files: - if (not (library in cornerfilename) ) : continue - if ('ccsnoise' in cornerfilename): continue # ignore duplicate corner.lib/corner_ccsnoise.lib files - - tmp = cornerfilename.replace('.lib','') - if (tmp+'_ccsnoise.lib' in lib_corner_files): - cornerfilename=tmp+'_ccsnoise.lib' # use ccsnoise version of lib file - - cornername = tmp.split('__')[1] - cornerparts = cornername.split('_') - - speed = cornerparts[0] - if (speed == 'ff'): speed = 'fast' - if (speed == 'tt'): speed = 'typical' - if (speed == 'ss'): speed = 'slow' - - temp = cornerparts[1] - temp = temp.replace('n','-') - temp = temp.split('C')[0]+' C' - - vdd = cornerparts[2] - vdd = vdd.split('v')[0]+'.'+vdd.split('v')[1]+' V' - - lib_entry = { - "nldm liberty file": os.path.join(SKYWATER_LIBS,'lib', cornerfilename), - "verilog sim": os.path.join('tech-sky130-cache', library+'.v'), - "lef file": os.path.join(SKYWATER_LIBS,'lef', library+'.lef'), - "spice file": os.path.join('tech-sky130-cache', library+'.cdl'), - "gds file": os.path.join(SKYWATER_LIBS,'gds', library+'.gds'), - "corner": { - "nmos": speed, - "pmos": speed, - "temperature": temp - }, - "supplies": { - "VDD": vdd, - "GND": "0 V" - }, - "provides": [ - { - "lib_type": "stdcell", - "vt": "RVT" +def main(args) -> int: + if len(args) != 3: + print("Usage: ./sky130-tech-gen.py /path/to/sky130A sky130.tech.json") + return 1 + + SKY130A = sys.argv[1] + + if use_nda_files: + with open('sky130-tech-gen-files/beginning_nda.json', 'r') as f: data = json.load(f) + else: + with open('sky130-tech-gen-files/beginning.json', 'r') as f: data = json.load(f) + + with open('sky130-tech-gen-files/cells.json', 'r') as f: + cells = json.load(f) + data["physical_only_cells_list"] = cells["physical_only_cells_list"] + data["dont_use_list"] = cells["dont_use_list"] + data["special_cells"] = cells["special_cells"] + + SKYWATER_LIBS = os.path.join('$SKY130A', 'libs.ref', library) + LIBRARY_PATH = os.path.join( SKY130A, 'libs.ref', library, 'lib') + lib_corner_files=os.listdir(LIBRARY_PATH) + for cornerfilename in lib_corner_files: + if (not (library in cornerfilename) ) : continue + if ('ccsnoise' in cornerfilename): continue # ignore duplicate corner.lib/corner_ccsnoise.lib files + + tmp = cornerfilename.replace('.lib','') + if (tmp+'_ccsnoise.lib' in lib_corner_files): + cornerfilename=tmp+'_ccsnoise.lib' # use ccsnoise version of lib file + + cornername = tmp.split('__')[1] + cornerparts = cornername.split('_') + + speed = cornerparts[0] + if (speed == 'ff'): speed = 'fast' + if (speed == 'tt'): speed = 'typical' + if (speed == 'ss'): speed = 'slow' + + temp = cornerparts[1] + temp = temp.replace('n','-') + temp = temp.split('C')[0]+' C' + + vdd = cornerparts[2] + vdd = vdd.split('v')[0]+'.'+vdd.split('v')[1]+' V' + + lib_entry = { + "nldm_liberty_file": os.path.join(SKYWATER_LIBS,'lib', cornerfilename), + "verilog_sim": os.path.join('cache', library+'.v'), + "lef_file": os.path.join(SKYWATER_LIBS,'lef', library+'.lef'), + "spice_file": os.path.join('cache', library+'.cdl'), + "gds_file": os.path.join(SKYWATER_LIBS,'gds', library+'.gds'), + "corner": { + "nmos": speed, + "pmos": speed, + "temperature": temp + }, + "supplies": { + "VDD": vdd, + "GND": "0 V" + }, + "provides": [ + { + "lib_type": "stdcell", + "vt": "RVT" + } + ] } - ] - } - data["libraries"].append(lib_entry) + data["libraries"].append(lib_entry) + + with open('sky130-tech-gen-files/stackups.json', 'r') as f: + stackups = json.load(f) + data["stackups"] = [stackups] -with open('sky130-tech-gen-files/stackups.json', 'r') as f: - stackups = json.load(f) -data["stackups"] = [stackups] + with open('sky130-tech-gen-files/sites.json', 'r') as f: + sites = json.load(f) + data["sites"] = sites["sites"] -with open('sky130-tech-gen-files/sites.json', 'r') as f: - sites = json.load(f) -data["sites"] = sites["sites"] + with open(sys.argv[2], 'w') as f: + json.dump(data, f, indent=2) + + return 0 -with open('../sky130.tech.json', 'w') as f: - json.dump(data, f, indent=2) \ No newline at end of file +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/hammer/technology/sky130/sky130.tech.json b/hammer/technology/sky130/sky130.tech.json index c7557e96b..a8fc01c65 100644 --- a/hammer/technology/sky130/sky130.tech.json +++ b/hammer/technology/sky130/sky130.tech.json @@ -33,7 +33,6 @@ "libraries": [ { "lef_file": "cache/sky130_fd_sc_hd__nom.tlef", - "spice_file": "$SKY130_NDA/s8/V2.0.1/LVS/Calibre/source.cdl", "verilog_sim": "cache/primitives.v", "provides": [ {