Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 0 additions & 4 deletions .cockpitrc
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,7 @@

libs = SG13CMOS5L_0.2 \
open_stdcell_rev0.1.3 \
sg13cmos5l_stdcell_v0.1 \
sg13cmos5l_io_v0.1 \
SG13G2_1.3.1 \
ez130_8t_stdcell_v1.0 \
open_io_v0.2 \
open_sram_v2.2 \
bondpad5l_70x70_v0

Expand Down
9 changes: 8 additions & 1 deletion .github/scripts/run_full_flow.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# Full backend flow:
# - Yosys synthesis
# - OpenROAD P&R
# - KLayout GDS export
# - KLayout GDS export, sealing, and minimal DRC

set -euo pipefail

Expand Down Expand Up @@ -63,6 +63,13 @@ echo " Step 3: KLayout GDS export"
echo "============================================="
cd klayout
./run_finishing.sh --gds --seal

echo ""
echo "============================================="
echo " Step 4: KLayout minimal DRC"
echo "============================================="
./run_drc.sh --minimal --jobs 1

cd "$CROC_ROOT"

echo ""
Expand Down
15 changes: 13 additions & 2 deletions .github/workflows/full-flow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,33 @@ jobs:
with:
cmd: ".github/scripts/run_full_flow.sh"
- name: Upload openroad outputs
if: always()
uses: actions/upload-artifact@v4
with:
name: croc-openroad-out
path: |
openroad/out
openroad/logs
openroad/reports
continue-on-error: true
if-no-files-found: ignore
- name: Upload gds
if: always()
uses: actions/upload-artifact@v4
with:
name: croc-gds
path: klayout/out/croc.gds.gz
if-no-files-found: ignore
- name: Upload sealed gds
if: always()
uses: actions/upload-artifact@v4
with:
name: croc-gds-sealed
path: klayout/out/croc.sealed.gds.gz
continue-on-error: true
if-no-files-found: ignore
- name: Upload DRC results
if: always()
uses: actions/upload-artifact@v4
with:
name: croc-drc
path: klayout/drc-minimal
if-no-files-found: ignore
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ Maintainers can update the pinned PDK mirror with `scripts/update_pdk.sh`.
You can also run `scripts/setup_technology.sh` manually to print the active technology view. `env.sh` runs the same setup quietly before the ASIC scripts use the PDK.

KLayout needs technology scripts, filling rules, and layer properties in addition to the files mentioned above.
On ETH systems, the installed CMOS5L KLayout support package takes priority when available.
Otherwise, the appropriate submodule, either `ihp13/sg13cmos5l` or `ihp13/sg13g2`, is required for the KLayout setup.
KLayout tool files are always taken from the pinned PDK submodule, either
`ihp13/sg13cmos5l` or `ihp13/sg13g2`.

The OSIC/oseda container also contains a PDK under `/foss/pdks`, but Croc does not currently use it.

Expand All @@ -207,9 +207,20 @@ To run the synthesis and place & route flow execute:
git submodule update --init --recursive
cd yosys && ./run_synthesis.sh --synth
cd ../openroad && ./run_backend.sh --all
cd ../klayout && ./run_finishing.sh --gds
cd ../klayout && ./run_finishing.sh --gds --seal
./run_drc.sh --minimal
```

Use `./run_drc.sh --minimal` after OpenROAD and during layout iteration. It
checks the interconnect and top-level layout produced by the implementation
flow while skipping transistor layers inside library cells. This keeps it
quick enough for regular CI and layout iteration. It is not a tapeout signoff
check.

Use `./run_drc.sh --full` when reviewing the final layout before tapeout. It
runs the slower and stricter checks across all layers. Full DRC is the default
when no mode is specified.

The ASIC flow defaults to `CROC_PDK=sg13cmos5l`.
To switch back to the original metal stack, export `CROC_PDK=sg13g2` before running the scripts.

Expand Down
92 changes: 31 additions & 61 deletions env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@
# This file is sourced by all scripts to set up tool paths and PDK location

# Determine repository root
if [[ -n "${BASH_SOURCE[0]}" ]]; then
export CROC_ROOT=$(realpath $(dirname "${BASH_SOURCE[0]}"))
else
export CROC_ROOT=$(pwd)
fi
export CROC_ROOT="$(realpath "$(dirname "${BASH_SOURCE[0]}")")"
echo "[INFO][ENV] Croc root: $CROC_ROOT"


Expand All @@ -24,7 +20,6 @@ echo "[INFO][ENV] Croc root: $CROC_ROOT"
######################
export PROJ_NAME="${PROJ_NAME:-croc}"
export TOP_DESIGN="${TOP_DESIGN:-croc_chip}"
export DUT_DESIGN="${DUT_DESIGN:-croc_soc}"
if [[ -z "${CROC_PDK:-}" ]]; then
if [[ "${PDK:-}" == "sg13g2" || "${PDK:-}" == "sg13cmos5l" ]]; then
echo "[WARNING][ENV] Ignoring PDK=$PDK. Use CROC_PDK to select the Croc PDK."
Expand All @@ -38,22 +33,36 @@ export PDK_STDCELL_LEF_FILE="sg13g2_stdcell.lef"
export PDK_STDCELL_GDS_FILE="sg13g2_stdcell.gds"
export PDK_STDCELL_LIB_TT_FILE="sg13g2_stdcell_typ_1p20V_25C.lib"
export PDK_STDCELL_LIB_FF_FILE="sg13g2_stdcell_fast_1p32V_m40C.lib"
export PDK_TECH_LEF_FILE="sg13cmos5l_tech.lef"
export PDK_IO_LEF_FILE="sg13cmos5l_io.lef"
export PDK_IO_GDS_FILE="sg13cmos5l_io.gds"
export PDK_IO_LIB_TT_FILE="sg13cmos5l_io_typ_1p2V_3p3V_25C.lib"
export PDK_IO_LIB_FF_FILE="sg13cmos5l_io_fast_1p32V_3p6V_m40C.lib"
export PDK_LAYER_MAP_FILE=""
export CROC_TECHNOLOGY_VIEW=""
export PDK_BONDPAD_CELL="bondpad_70x70"
export PDK_BONDPAD_LEF="bondpad_70x70.lef"
export PDK_BONDPAD_GDS="bondpad_70x70.gds"

if [[ "$CROC_PDK" == "sg13cmos5l" ]]; then
export BENDER_PDK_ARGS="-D IHP_SG13CMOS5L=1"
else
export BENDER_PDK_ARGS=""
fi
case "$CROC_PDK" in
sg13cmos5l)
export BENDER_PDK_ARGS="-D IHP_SG13CMOS5L=1"
export PDK_TECH_LEF_FILE="sg13cmos5l_tech.lef"
export PDK_IO_LEF_FILE="sg13cmos5l_io.lef"
export PDK_IO_GDS_FILE="sg13cmos5l_io.gds"
export PDK_IO_LIB_TT_FILE="sg13cmos5l_io_typ_1p2V_3p3V_25C.lib"
export PDK_IO_LIB_FF_FILE="sg13cmos5l_io_fast_1p32V_3p6V_m40C.lib"
export PDK_BONDPAD_LEF="bondpad5l_70x70.lef"
export PDK_BONDPAD_GDS="bondpad5l_70x70.gds"
export KLAYOUT_PATH="$CROC_ROOT/ihp13/sg13cmos5l/libs.tech/klayout"
;;
sg13g2)
export BENDER_PDK_ARGS=""
export PDK_TECH_LEF_FILE="sg13g2_tech.lef"
export PDK_IO_LEF_FILE="sg13g2_io.lef"
export PDK_IO_GDS_FILE="sg13g2_io.gds"
export PDK_IO_LIB_TT_FILE="sg13g2_io_typ_1p2V_3p3V_25C.lib"
export PDK_IO_LIB_FF_FILE="sg13g2_io_fast_1p32V_3p6V_m40C.lib"
export PDK_BONDPAD_LEF="bondpad_70x70.lef"
export PDK_BONDPAD_GDS="bondpad_70x70.gds"
export KLAYOUT_PATH="$CROC_ROOT/ihp13/sg13g2/ihp-sg13g2/libs.tech/klayout"
;;
*)
echo "[ERROR][ENV] Unknown CROC_PDK '$CROC_PDK'" >&2
return 1 2>/dev/null || exit 1
;;
esac


###################
Expand All @@ -80,11 +89,6 @@ if [[ -e "${CROC_ROOT}/technology" || ( "${CROC_SKIP_TECH_SETUP:-0}" == "1" && -
# Dry runs use the public mirror directly without creating technology/.
export PDK_ROOT="$PUBLIC_PDK_ROOT"
fi
export PDK_TECH_HOME="$PDK_ROOT"
export PDK_STD_HOME="$PDK_ROOT"
export PDK_SRAM_HOME="$PDK_ROOT"
export PDK_IO_HOME="$PDK_ROOT"

public_pdk_realpath="$(realpath -m "$PUBLIC_PDK_ROOT")"
technology_realpath="$(realpath -m "$PDK_ROOT")"
if [[ "$technology_realpath" == "$public_pdk_realpath" ]]; then
Expand All @@ -106,36 +110,6 @@ if [[ -e "${CROC_ROOT}/technology" || ( "${CROC_SKIP_TECH_SETUP:-0}" == "1" && -
export PDK_DIR_GDS_IOS="$PDK_ROOT/gds"
export PDK_DIR_GDS_BOND="$PDK_ROOT/gds"

if [[ "$CROC_PDK" == "sg13cmos5l" ]]; then
export PDK_BONDPAD_CELL="bondpad5l_70x70"
export PDK_BONDPAD_GDS="bondpad5l_70x70.gds"
export PDK_TECH_LEF_FILE="sg13cmos5l_tech.lef"
export PDK_IO_LEF_FILE="sg13cmos5l_io.lef"
export PDK_IO_GDS_FILE="sg13cmos5l_io.gds"
export PDK_IO_LIB_TT_FILE="sg13cmos5l_io_typ_1p2V_3p3V_25C.lib"
export PDK_IO_LIB_FF_FILE="sg13cmos5l_io_fast_1p32V_3p6V_m40C.lib"
export PDK_BONDPAD_LEF="bondpad5l_70x70.lef"

# KLayout needs separate tool files. Cockpit takes precedence.
export KLAYOUT_PATH="$CROC_ROOT/ihp13/sg13cmos5l/libs.tech/klayout"
if [[ -d "/usr/pack/ihp-sg13-kgf/open_ihp_sg13cmos5l/sg13cmos5l_tech/v0.2/klayout" ]]; then
export KLAYOUT_PATH="/usr/pack/ihp-sg13-kgf/open_ihp_sg13cmos5l/sg13cmos5l_tech/v0.2/klayout"
fi
elif [[ "$CROC_PDK" == "sg13g2" ]]; then
export PDK_TECH_LEF_FILE="sg13g2_tech.lef"
export PDK_IO_LEF_FILE="sg13g2_io.lef"
export PDK_IO_GDS_FILE="sg13g2_io.gds"
export PDK_IO_LIB_TT_FILE="sg13g2_io_typ_1p2V_3p3V_25C.lib"
export PDK_IO_LIB_FF_FILE="sg13g2_io_fast_1p32V_3p6V_m40C.lib"
export PDK_BONDPAD_CELL="bondpad_70x70"
export PDK_BONDPAD_LEF="bondpad_70x70.lef"
export PDK_BONDPAD_GDS="bondpad_70x70.gds"
export KLAYOUT_PATH="$CROC_ROOT/ihp13/sg13g2/ihp-sg13g2/libs.tech/klayout"
else
echo "[ERROR][ENV] Unknown CROC_PDK '$CROC_PDK'"
exit 1
fi

else
echo "[WARNING][ENV] PDK not found. Initialize cockpit or ensure ihp13/pdk exists"
export PDK_ROOT="" # Set to empty to avoid unbound variable error
Expand All @@ -150,10 +124,6 @@ echo "[INFO][ENV] Bender PDK args: ${BENDER_PDK_ARGS:-<none>}"
echo "[INFO][ENV] Tech LEF: $PDK_TECH_LEF_FILE"
echo "[INFO][ENV] IO LEF/GDS: $PDK_IO_LEF_FILE/$PDK_IO_GDS_FILE"
echo "[INFO][ENV] IO Liberty tt/ff: $PDK_IO_LIB_TT_FILE/$PDK_IO_LIB_FF_FILE"
echo "[INFO][ENV] Bondpad cell: $PDK_BONDPAD_CELL ($PDK_BONDPAD_LEF/$PDK_BONDPAD_GDS)"
echo "[INFO][ENV] Bondpad LEF/GDS: $PDK_BONDPAD_LEF/$PDK_BONDPAD_GDS"
export KLAYOUT_TECH="$CROC_PDK"
if [[ -f "$PDK_ROOT/SG13G2_streamout.map" ]]; then
export PDK_LAYER_MAP_FILE="$PDK_ROOT/SG13G2_streamout.map"
else
export PDK_LAYER_MAP_FILE="$KLAYOUT_PATH/tech/${CROC_PDK}.map"
fi
export PDK_LAYER_MAP_FILE="$KLAYOUT_PATH/tech/${CROC_PDK}.map"
2 changes: 1 addition & 1 deletion ihp13/sg13cmos5l
Submodule sg13cmos5l updated 380 files
2 changes: 1 addition & 1 deletion ihp13/sg13g2
Submodule sg13g2 updated 1222 files
2 changes: 2 additions & 0 deletions klayout/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.klayout
out
__pycache__/
drc-*/
133 changes: 133 additions & 0 deletions klayout/run_drc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#!/usr/bin/env bash
# Copyright (c) 2026 ETH Zurich and University of Bologna.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CROC_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
DRYRUN=0
MODE="full"
MODE_SELECTED=0
JOBS="${DRC_JOBS:-1}"

show_help() {
cat <<'EOF'
KLayout DRC coordinator

Usage: ./run_drc.sh [OPTIONS]

Options:
--minimal Check the sealed layout during implementation
--full Check the sealed layout before tapeout (default)
--jobs N Run at most N DRC tables concurrently (default: 1)
--dry-run, -n Print the planned command without changing files
--verbose, -v Print commands while executing
--help, -h Show this help message

Use --minimal after OpenROAD and during floorplan or routing iteration. It
checks the generated interconnect and top-level layout while skipping the
transistor layers inside library cells, making it suitable for regular CI.
It is not a tapeout signoff check. Use --full for the final pre-tapeout review;
it runs slower, stricter checks across all layers.

Both modes use klayout/out/<PROJ_NAME>.sealed.gds.gz and top cell
<TOP_DESIGN>_sealed. Results are written to klayout/drc-minimal or
klayout/drc-full.
EOF
}

while [[ $# -gt 0 ]]; do
case "$1" in
--help|-h) show_help; exit 0 ;;
--dry-run|-n) DRYRUN=1; shift ;;
--verbose|-v) set -x; shift ;;
--minimal|--full)
if [[ "$MODE_SELECTED" -eq 1 ]]; then
echo "[ERROR][KLayout] Select only one DRC mode" >&2
exit 2
fi
MODE="${1#--}"
MODE_SELECTED=1
shift
;;
--jobs)
[[ $# -ge 2 ]] || { echo "[ERROR][KLayout] --jobs requires a value" >&2; exit 2; }
JOBS="$2"
shift 2
;;
*)
echo "[ERROR][KLayout] Unknown option: $1 (use --help for usage)" >&2
exit 2
;;
esac
done

if [[ ! "$JOBS" =~ ^[1-9][0-9]*$ ]]; then
echo "[ERROR][KLayout] --jobs must be a positive integer" >&2
exit 2
fi
if [[ "$DRYRUN" -eq 1 ]]; then
export CROC_SKIP_TECH_SETUP=1
fi
source "$CROC_ROOT/env.sh"

GDS_PATH="$SCRIPT_DIR/out/${PROJ_NAME}.sealed.gds.gz"
TOP_CELL="${TOP_DESIGN}_sealed"
RUN_DIR="$SCRIPT_DIR/drc-$MODE"
DRC_RUNNER="$KLAYOUT_PATH/tech/drc/run_drc.py"

# The upstream runner builds a shell command from these values.
for value in "$GDS_PATH" "$TOP_CELL" "$RUN_DIR"; do
if [[ ! "$value" =~ ^[A-Za-z0-9_./:@%+,=-]+$ ]]; then
echo "[ERROR][KLayout] DRC path contains unsupported characters: $value" >&2
exit 1
fi
done

if [[ "$DRYRUN" -eq 0 ]]; then
[[ -f "$DRC_RUNNER" ]] || {
echo "[ERROR][KLayout] DRC runner not found: $DRC_RUNNER" >&2
exit 1
}
[[ -f "$GDS_PATH" ]] || {
echo "[ERROR][KLayout] Input GDS not found: $GDS_PATH" >&2
exit 1
}
mkdir -p "$RUN_DIR"
fi

command=(
python3 "$DRC_RUNNER"
"--path=$GDS_PATH"
"--topcell=$TOP_CELL"
"--run_dir=$RUN_DIR"
"--mp=$JOBS"
--density_thr=1
)
if [[ "$MODE" == "minimal" ]]; then
command+=(--precheck_drc --no_feol --no_recommended --no_offgrid --no_density --disable_extra_rules)
echo "[INFO][KLayout] Running minimal DRC on $TOP_CELL with $JOBS worker(s)"
else
command+=(--antenna)
echo "[INFO][KLayout] Running full DRC on $TOP_CELL with $JOBS worker(s)"
fi

if [[ "$DRYRUN" -eq 1 ]]; then
printf '%q ' "${command[@]}"
printf '\n'
exit 0
fi

coordinator_log="$RUN_DIR/drc-coordinator.log"
set +e
"${command[@]}" 2>&1 | tee "$coordinator_log"
run_status=${PIPESTATUS[0]}
set -e
if [[ "$run_status" -ne 0 ]]; then
exit "$run_status"
fi
if grep -Fq " generated an exception:" "$coordinator_log"; then
echo "[ERROR][KLayout] One or more parallel DRC checks failed; see $coordinator_log" >&2
exit 1
fi
Loading