Skip to content

Commit

Permalink
fix(tt_um_kmakise_sram): workaround for SRAM macro DRC errors
Browse files Browse the repository at this point in the history
  • Loading branch information
urish committed Nov 8, 2024
1 parent 2edacaf commit b12490e
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .github/workflows/gds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ jobs:
python ../sky130_density_fix/replace_decap.py --design $project --user-gds $project/$project.gds --replacement-gds ../sky130_density_fix/sky130_ef_sc_hd__newfill_12.gds
done
# Workaround for DRC errors in the SRAM macro of tt_um_kmakise_sram:
- name: Patch tt_um_kmakise_sram for SRAM DRC errors
run: python sky130_sram_workaround/extract_sram_macro.py -n tt_um_kmakise_sram -p projects/tt_um_kmakise_sram/tt_um_kmakise_sram.gds -m myconfig_sky_dual -x projects/tt_um_kmakise_sram/myconfig_sky_dual.gds

# run OpenLane to build the GDS
- name: Harden Chip ROM
run: nix-shell $GITHUB_WORKSPACE/openlane2/shell.nix --run "python -m openlane tt/rom/config.json"
Expand All @@ -107,6 +111,13 @@ jobs:
working-directory: tt-multiplexer/ol2/tt_top
run: nix-shell $GITHUB_WORKSPACE/openlane2/shell.nix --run "python build.py --skip-xor-checks"

- name: Copy sram macro back into tt_um_kmakise_sram
run: |
# Find the latest run directory:
RUN_DIR=$(ls -d tt-multiplexer/ol2/tt_top/runs/RUN_* | sort -n | tail -n 1)
cp $RUN_DIR/final/gds/openframe_project_wrapper.gds $RUN_DIR/final/gds/openframe_project_wrapper.orig.gds
python sky130_sram_workaround/inject_sram_macro.py -i $RUN_DIR/final/gds/openframe_project_wrapper.gds -o $RUN_DIR/final/gds/openframe_project_wrapper.gds -p tt_um_kmakise_sram -m myconfig_sky_dual --inject-gds projects/tt_um_kmakise_sram/myconfig_sky_dual.gds
- name: Copy final results
run: python ./tt/configure.py --copy-final-results

Expand Down
51 changes: 51 additions & 0 deletions sky130_sram_workaround/extract_sram_macro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# SPDX-License-Identifier: Apache-2.0
# Authors: Uri Shaked

import klayout.db as pya
import argparse

parser = argparse.ArgumentParser(
description="Extracts a given macro from a user project into a separate file, removing the original macro content from the user's project."
)

parser.add_argument("--design-name", "-n", required=True)
parser.add_argument("--project-gds", "-p", required=True)
parser.add_argument("--macro-name", "-m", required=True)
parser.add_argument("--extracted-gds", "-x", required=True)


args = parser.parse_args()

design_name = args.design_name
project_gds = args.project_gds
macro_name = args.macro_name
extracted_gds = args.extracted_gds

user_layout = pya.Layout()
user_layout.read(project_gds)

macro_to_extract = user_layout.cell(macro_name)
if macro_to_extract.is_empty():
raise ValueError(f"Cell {macro_name} is empty.")

extracted_layout = pya.Layout()
extracted_layout.dbu = user_layout.dbu
extracted_cell = extracted_layout.create_cell(macro_to_extract)
extracted_cell.name = macro_name
extracted_cell.copy_tree(macro_to_extract)

macro_to_extract.clear()
# Create a single shape in the original cell to avoid opelane error about empty cells during the Stream Out (KLayout) step.
macro_to_extract.shapes(0).insert(pya.Box(0, 0, 0, 0))

has_orphan_cells = True
while has_orphan_cells:
has_orphan_cells = False
for cell in user_layout.top_cells():
if cell.name != design_name:
cell.delete()
has_orphan_cells = True

print(f"Extracted {macro_name} from {project_gds} to {extracted_gds}.")
user_layout.write(project_gds)
extracted_layout.write(extracted_gds)
43 changes: 43 additions & 0 deletions sky130_sram_workaround/inject_sram_macro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# SPDX-License-Identifier: Apache-2.0
# Authors: Uri Shaked

import klayout.db as pya
import argparse

parser = argparse.ArgumentParser(description="Injects the macro into a user's project.")

parser.add_argument("--input-gds", "-i", required=True)
parser.add_argument("--output-gds", "-o", required=True)
parser.add_argument("--project-name", "-p", required=True)
parser.add_argument("--macro-name", "-m", required=True)
parser.add_argument("--inject-gds", required=True)

args = parser.parse_args()

input_gds = args.input_gds
output_gds = args.output_gds
macro_name = args.macro_name
project_name = args.project_name
inject_gds = args.inject_gds

tt_layout = pya.Layout()
tt_layout.read(input_gds)

user_project_cell = tt_layout.cell(project_name)
prefix = None
for inst in user_project_cell.each_inst():
assert inst
prefix = inst.cell.name[:3]
assert prefix[2] == "_"

assert prefix

macro_layout = pya.Layout()
macro_layout.read(inject_gds)

target_cell = tt_layout.cell(prefix + macro_name)
target_cell.clear()
target_cell.copy_tree(macro_layout.cell(macro_name))

print(f"Injected {macro_name} and wrote the result into {output_gds}.")
tt_layout.write(output_gds)

0 comments on commit b12490e

Please sign in to comment.