diff --git a/CLAUDE.md b/CLAUDE.md index 354facb5..8abf3451 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,6 +4,19 @@ ECC is the EDA toolchain component of ECOS Studio, orchestrating EDA tools (Yosy For setup, testing, and code quality commands, see [docs/development.md](docs/development.md). +# Repository Skills + +ECC-specific agent skills are versioned under `SKILLS/`. For matching work, +read the corresponding `SKILL.md` completely before acting. The repository +copy is authoritative for this checkout when a user-level skill has the same +name. Resolve explicit `$run-and-test-ecc` and `$debug-ecc-in-tmux` requests +to these repository copies as well. + +- `SKILLS/run-and-test-ecc/SKILL.md`: setup, builds, CLI and Workspace runs, + focused tests, integration flows, and native import provenance. +- `SKILLS/debug-ecc-in-tmux/SKILL.md`: persistent GDB/cuda-gdb debugging for + ECC Python, C++, pybind, iDB/iRT, and CUDA failures. + # Workflow If Nix is available, enter the dev shell before syncing: diff --git a/SKILLS/debug-ecc-in-tmux/SKILL.md b/SKILLS/debug-ecc-in-tmux/SKILL.md new file mode 100644 index 00000000..a33fe2d5 --- /dev/null +++ b/SKILLS/debug-ecc-in-tmux/SKILL.md @@ -0,0 +1,199 @@ +--- +name: debug-ecc-in-tmux +description: Reproduce and inspect this repository's ECC Python, C++, pybind, iDB/iRT, and CUDA failures under GDB or cuda-gdb inside a persistent tmux session. Use for native crashes, wrong database values, missed native breakpoints, pin/net/geometry inspection, attaching to a running ECC process, or preserving a stopped debugger for later commands. +--- + +# Debug ECC in tmux + +Keep one reproducible ECC invocation stopped at the narrowest useful native boundary. Preserve the tmux session so another person or turn can inspect it without rerunning an expensive flow. + +## Establish the Reproduction + +1. Read `AGENTS.md`, `docs/development.md`, `.vscode/launch.json` when present, native package `pyproject.toml` files, and `.venv/bin/ecc run --help`. +2. Record the repository commit, recursive submodule commits, Workspace, persisted Step, exact failure, and whether replacing that Step's output is acceptable. +3. Inspect `ps` and existing tmux sessions for another writer. ECC has no Workspace process lock; never start a second writer. +4. Prefer the public Workspace entry: + +```bash +.venv/bin/python -m chipcompiler.cli.main run \ + --workspace /path/to/workspace --only place --force --json +``` + +Replace `place` with the exact Step from `home/flow.json`. Reproduce once without a debugger when practical and capture the error, signal, thread behavior, and log path. + +## Prepare Native Code + +Follow `../run-and-test-ecc/SKILL.md` for checkout, submodule, Nix, uv, and import-provenance checks. Build the affected package before launching a debugger: + +```bash +cmake --build chipcompiler/thirdparty/ecc-tools/build --target ecc_py -j 8 +cmake --build chipcompiler/thirdparty/ecc-dreamplace/build -j 8 +``` + +If the build tree is stale, missing, or ABI-incompatible, recreate the editable package with `uv sync --reinstall-package ` and the repository's `--no-build-isolation-package` options. + +Require a Debug/unstripped extension for source-line breakpoints. For CUDA device stepping, rebuild with device debug flags such as `CUDA_NVCC_FLAGS_DEBUG=-G`; host GDB cannot step a device kernel. + +Prevent scikit-build from rebuilding after the debugger starts by passing the exact build directories: + +```bash +repo=$(git rev-parse --show-toplevel) +export SKBUILD_EDITABLE_SKIP="$repo/chipcompiler/thirdparty/ecc-dreamplace/build:$repo/chipcompiler/thirdparty/ecc-tools/build" +``` + +Do not use `SKBUILD_EDITABLE_SKIP=1`; it is interpreted as a list of paths. + +## Start a Persistent Session + +Choose a unique session name. Never reuse or kill an existing session without authorization. + +```bash +repo=$(git rev-parse --show-toplevel) +workspace="/absolute/path/to/workspace" +session=ecc-place-native-debug +skip_paths="$repo/chipcompiler/thirdparty/ecc-dreamplace/build:$repo/chipcompiler/thirdparty/ecc-tools/build" + +if tmux has-session -t "$session" 2>/dev/null; then + echo "tmux session already exists: $session" >&2 + exit 1 +fi + +printf -v quoted_skip_paths '%q' "$skip_paths" +printf -v quoted_python '%q' "$repo/.venv/bin/python" +printf -v quoted_workspace '%q' "$workspace" +debug_command="exec env SKBUILD_EDITABLE_SKIP=$quoted_skip_paths PYTHONFAULTHANDLER=1 PYTHONUNBUFFERED=1 /usr/bin/gdb --args $quoted_python -m chipcompiler.cli.main run --workspace $quoted_workspace --only place --force --json" +tmux new-session -d -s "$session" -c "$repo" "$debug_command" +``` + +`printf %q` keeps repository and Workspace paths as single shell words when tmux starts the command. Attach with `tmux attach -t "$session"`, or send one debugger command at a time and verify it with `tmux capture-pane`. Do not enqueue an unchecked command batch. + +## Configure GDB + +Use this baseline for ECC-Tools, iDB, iRT, and host-side DreamPlace code: + +```gdb +set pagination off +set confirm off +set print pretty on +set print elements 0 +set breakpoint pending on +set follow-fork-mode parent +set detach-on-fork on +add-auto-load-safe-path /absolute/path/to/ecc +break /absolute/path/to/source.cpp:LINE +run +``` + +Pending breakpoints are normal because native extensions load after Python starts. Prefer `follow-fork-mode parent` until evidence shows the target executes in a child. + +For signal failures, stop before teardown: + +```gdb +handle SIGSEGV stop print pass +handle SIGFPE stop print pass +handle SIGABRT stop print pass +catch throw +``` + +Break immediately before a fatal logger or abort when the handler destroys useful locals. + +## Inspect a Hit + +Start with execution context rather than guessed accessors: + +```gdb +info breakpoints +info sharedlibrary +info threads +thread apply all bt 3 +thread THREAD_NUMBER +frame 0 +bt 40 +info args +info locals +ptype TYPE_OR_EXPRESSION +``` + +iRT and placement use worker threads; select the thread stopped at the target frame. For pin, net, placement, or geometry failures, capture: + +- Native thread and full backtrace. +- Net and pin names/indices. +- IO versus instance-pin ownership, instance name, and placement status. +- Access point and shape rectangles/layers. +- Die/core/grid bounds and the exact failed comparison. +- Pointer identities when aliasing or ownership is suspected. + +Use verified singleton/global state only after `ptype`, `info args`, and `info locals` establish the current types. Change one value or hypothesis at a time; prefer inspection over debugger mutation. + +## Debug CUDA + +Use the installed `cuda-gdb`, serialize launches, and verify the local toolkit path instead of hard-coding a version: + +```bash +env CUDA_LAUNCH_BLOCKING=1 \ + SKBUILD_EDITABLE_SKIP="$SKBUILD_EDITABLE_SKIP" \ + /path/to/cuda-gdb --args .venv/bin/python /path/to/reproducer.py +``` + +```gdb +set breakpoint pending on +break /absolute/path/to/kernel.cu:LINE +run +info cuda kernels +info cuda threads +bt +``` + +Use host GDB for wrappers and cuda-gdb only when the suspected defect is in device code. + +## Attach to an Existing Process + +Confirm the exact Python process that loaded the target extension, not a Yosys/Sizer child or monitor: + +```bash +ps -eo pid,ppid,stat,etime,cmd | rg 'chipcompiler.cli.main|\.venv/bin/python' +repo=$(git rev-parse --show-toplevel) +session=ecc-native-attach +pid=PID + +[[ "$pid" =~ ^[0-9]+$ ]] || { echo "invalid PID: $pid" >&2; exit 2; } +if tmux has-session -t "$session" 2>/dev/null; then + echo "tmux session already exists: $session" >&2 + exit 1 +fi + +tmux new-session -d -s "$session" -c "$repo" "exec /usr/bin/gdb -p $pid" +tmux attach -t "$session" +``` + +Respect host ptrace restrictions and do not attach to an unrelated user process. + +## Preserve and Hand Off + +Leave GDB stopped unless explicitly asked to continue or terminate. Report: + +- tmux target `session:window.pane`. +- Repository, Workspace, Step, and inferior command. +- Breakpoint file/line or function. +- Thread, frame, stop reason, and key inspected values. +- Next falsifiable question. +- Workspace outputs/configs changed by reproduction. + +Inspect without disturbing the inferior: + +```bash +tmux list-panes -a -F '#{session_name}:#{window_index}.#{pane_index} pid=#{pane_pid} cmd=#{pane_current_command}' +tmux capture-pane -p -t session:0.0 -S -200 +``` + +Do not treat a short capture as complete history. Never continue, detach, or kill the session merely for cleanup. + +## Diagnose Missed Breakpoints + +- Pending forever: inspect `info sharedlibrary`, module `__file__`, source path, and loaded extension provenance. +- GDB follows CMake/Ninja: prebuild, pass exact `SKBUILD_EDITABLE_SKIP` paths, and keep parent-following. +- No line symbols: rebuild Debug and confirm the `.so` is not stripped. +- Host breakpoint works but kernel does not: rebuild with `-G` and use cuda-gdb. +- Failure occurs before the Step: inspect persisted absolute paths and configs; do not silently repair the artifact. +- Logger breakpoint loses locals: move to the error call site. +- Session appears idle: inspect process state, current frame, logs, and pane before calling it hung. diff --git a/SKILLS/debug-ecc-in-tmux/agents/openai.yaml b/SKILLS/debug-ecc-in-tmux/agents/openai.yaml new file mode 100644 index 00000000..381216ed --- /dev/null +++ b/SKILLS/debug-ecc-in-tmux/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Debug ECC in tmux" + short_description: "Hold ECC native breakpoints in persistent tmux" + default_prompt: "Use $debug-ecc-in-tmux to reproduce this ECC failure under GDB in a persistent tmux session." diff --git a/SKILLS/run-and-test-ecc/SKILL.md b/SKILLS/run-and-test-ecc/SKILL.md new file mode 100644 index 00000000..6a7c7648 --- /dev/null +++ b/SKILLS/run-and-test-ecc/SKILL.md @@ -0,0 +1,203 @@ +--- +name: run-and-test-ecc +description: "Operate and verify this ECC checkout: prepare its Nix and uv editable environment, run project flows, resume or rerun an existing Workspace in place, repeat one persisted Step with --only and --force, choose focused Python/formal/integration tests, verify native import provenance, and report reproducible evidence. Use for ECC installation, builds, tests, flow runs, Workspace reproduction, one-Step tool development, and native-package readiness checks." +--- + +# Run and Test ECC + +Use the live checkout as the source of truth. Verify the current CLI and Workspace contracts before reusing commands from an older branch or report. + +## Establish the Checkout + +1. Work from the repository root and read `AGENTS.md`, `docs/development.md`, and `pyproject.toml`. +2. Inspect `git status --short --branch` and `git submodule status --recursive`. Preserve unrelated dirt, local commits, and detached submodule state. +3. Treat a leading `-` in recursive submodule status as uninitialized. Do not call the native environment ready until required nested submodules are present. +4. When `.venv` exists, run: + +```bash +.venv/bin/ecc --help +.venv/bin/ecc run --help +.venv/bin/ecc version +``` + +Treat this output and the current implementation as authoritative. Do not claim historical commands such as `metrics`, `artifacts`, `diagnose`, or a top-level `workspace` command unless the live help lists them. + +## Prepare the Editable Environment + +For a clean or intentionally realigned checkout, initialize the commits pinned by the parent repository before syncing. Run the sync inside the Nix environment without opening an interactive subshell: + +```bash +git submodule sync --recursive +git submodule update --init --recursive --progress +nix develop --command uv sync \ + --no-build-isolation-package ecc-dreamplace \ + --no-build-isolation-package ecc-tools-bin \ + --verbose +``` + +If Nix is unavailable, run the same `uv sync` command directly. Use explicit `.venv/bin/*` commands afterward; shell activation is not required. Do not place commands after a bare `nix develop` in the same outer-shell batch because they run only after the interactive Nix shell exits. + +Do not run `git submodule update` through dirty submodules without first protecting their changes. Do not use `--remote` unless the task explicitly asks to follow each submodule's remote branch instead of the parent gitlinks. + +Verify the interpreter and actual native extensions, not only package metadata: + +```bash +.venv/bin/python -c 'import sys; print(sys.executable)' +.venv/bin/python -c 'import torch; print(torch.__version__, torch.__file__)' +.venv/bin/python -c 'import dreamplace; print(dreamplace.__file__)' +.venv/bin/python -c 'from ecc_tools_bin import ecc_py; print(ecc_py.__file__)' +``` + +An `ecc version` result or successful `import ecc_tools_bin` does not prove that `ecc_py.so` loads. Diagnose editable rebuild failures, missing nested dependencies, stale build trees, GLIBC/ABI errors, and source-versus-installed version drift separately. + +Apply this rebuild boundary: + +- Python-only ECC edit: restart the Python process; ECC is editable. +- C/C++/CUDA edit: rebuild the affected configured target or reinstall that editable package. +- Build metadata, dependency, ABI, interpreter, or submodule change: rerun `uv sync`; use `--reinstall-package ecc-dreamplace` or `--reinstall-package ecc-tools-bin` when needed. +- Wheel: build only for delivery, release, or wheel-specific integration validation. + +## Run a Project + +Use the public CLI for a project containing `ecc.toml`: + +```bash +.venv/bin/ecc init gcd +.venv/bin/ecc check --project /path/to/project +.venv/bin/ecc run --project /path/to/project +.venv/bin/ecc status --project /path/to/project +.venv/bin/ecc log --project /path/to/project +.venv/bin/ecc config --resolved --project /path/to/project +``` + +Use `nix run . -- ` to test the packaged Nix entry. Use `--overwrite` only when intentionally replacing an existing ECC run directory. Use repeatable `--set key=value` only in project mode. + +## Reuse an Existing Workspace + +List persisted Step names, tools, and states before selecting a Step: + +```bash +jq -r '.steps[] | [.name, .tool, .state] | @tsv' \ + /path/to/workspace/home/flow.json +``` + +Use the public Workspace entry in place: + +```bash +workspace=/path/to/workspace + +# Re-execute one Step even when it is already Success. +.venv/bin/ecc run --workspace "$workspace" --only place --force + +# Continue from the first non-Success Step. +.venv/bin/ecc run --workspace "$workspace" --resume + +# Re-execute one Step and its persisted suffix. +.venv/bin/ecc run --workspace "$workspace" --from place +``` + +The common `rtl2gds` preset currently uses: + +```text +Synthesis +Floorplan +fixFanout +place +CTS +legalization +route +drc +filler +``` + +`rcx` appends `RCX` and `sta`; `harden` appends `Harden`. Always prefer the reported Workspace's `home/flow.json`, which may contain a custom sequence. + +Enforce these contracts: + +- `--resume`, `--from`, and `--only` are mutually exclusive. +- Omitting a selector in Workspace mode is equivalent to `--resume`. +- `--force` is valid only with `--only`; without it, a successful Step is a no-op. +- Workspace mode cannot be combined with `--project`, `--run-id`, `--overwrite`, or `--set`. +- Workspace mode loads and mutates the Workspace in place; it does not create or copy one. +- Re-execution deletes the selected Step's current `output/`. A failed rerun does not restore it. +- Starting from an upstream Step invalidates persisted runtime/state for its suffix before execution. +- Tool builders may regenerate `config/*.json` from `home/parameters.json` and current Step paths. Inspect the live builder before relying on manual generated-config edits. +- ECC provides no Workspace process lock. Confirm that no second writer is active. + +Use `--json` or `--jsonl` for machine-readable evidence. The current Workspace result contract uses `status`, `executed_steps`, and `no_op`; failures also use `failed_step` and `resume_cmd`. Do not claim `reused_steps`, `stale_steps`, or a top-level `state` field unless the implementation adds them. + +For Python-level stepping with the same command contract: + +```bash +.venv/bin/python -m chipcompiler.cli.main run \ + --workspace "$workspace" --only place --force --json +``` + +## Inspect Before Running + +1. Read `home/flow.json` and identify the exact Step, tool, state, and predecessor. +2. Inspect the Step's `input/`, `output/`, `data/`, `feature/`, configs, and logs. +3. Verify absolute PDK, DEF, Verilog, SPEF, and external-tool paths embedded in the Workspace. +4. Confirm required inputs, including accepted `.gz` alternatives. +5. Record the command, environment variables, parent commit, recursive submodule commits, and observed failure before changing the artifact. + +Do not silently copy a reported Workspace. Request authorization when the original must remain immutable and a copy is needed. + +## Choose Tests by Ownership + +Start narrow and widen according to risk: + +```bash +# CLI and Workspace selectors +.venv/bin/python -m pytest test/cli/test_typer_cli.py test/cli/commands -q +.venv/bin/python -m pytest test/test_engine_rerun.py -q + +# Tool wrapper +.venv/bin/python -m pytest test/tools/ecc/test_runner.py -q + +# Cross-cutting contracts +.venv/bin/python -m pytest test/formal/ -q + +# Full Python suite +.venv/bin/python -m pytest test/ -q +``` + +For the real ICS55 GCD integration, verify Yosys with the slang plugin, the PDK, and the external Sizer. Set `CHIPCOMPILER_OSS_CAD_DIR` when selecting an OSS CAD Suite instead of a `yosys` already available on `PATH`: + +```bash +export CHIPCOMPILER_OSS_CAD_DIR=/path/to/oss-cad-suite +export CHIPCOMPILER_ICS55_PDK_ROOT=/path/to/ics55-pdk +export PATH=/path/to/ecc-sizer/build/src:$PATH +.venv/bin/python - <<'PY' +import os +import sys + +from chipcompiler.tools.yosys.utility import check_slang_plugin, get_yosys_runtime + +yosys_cmd, yosys_env = get_yosys_runtime() +if not yosys_cmd: + raise SystemExit("Yosys is unavailable") +if not check_slang_plugin(yosys_cmd, os.getcwd(), yosys_env, sys.stdout): + raise SystemExit("Yosys slang plugin is unavailable") +print(f"Yosys: {yosys_cmd[0]}") +PY +command -v Sizer +.venv/bin/python -m pytest \ + test/integration/test_rtl2gds_flow.py::test_ics55_gcd -q -s +``` + +Do not treat mocked CLI tests as native-flow proof, and do not run a full physical flow when a focused selector, parser, or wrapper test proves the requested behavior. + +## Report Completion + +Report separately: + +- Checkout and recursive submodule provenance. +- Environment, interpreter, and imported native-extension provenance. +- Focused tests and exact node IDs or test files. +- Integration/full-flow status, including prerequisites not exercised. +- Workspace Steps executed, skipped as no-op, failed, or invalidated. +- Files, configs, and outputs changed during reproduction. +- Remaining native-build, PDK, license, or external-tool risks. + +Never collapse configured, compiled, imported, unit-tested, and full-flow-validated into one claim. diff --git a/SKILLS/run-and-test-ecc/agents/openai.yaml b/SKILLS/run-and-test-ecc/agents/openai.yaml new file mode 100644 index 00000000..ae789530 --- /dev/null +++ b/SKILLS/run-and-test-ecc/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Run and Test ECC" + short_description: "Run ECC flows, resume workspaces, and choose tests" + default_prompt: "Use $run-and-test-ecc to run or test this ECC checkout."