diff --git a/ball-design-guide/SKILL.md b/ball-design-guide/SKILL.md new file mode 100644 index 0000000..d8e3011 --- /dev/null +++ b/ball-design-guide/SKILL.md @@ -0,0 +1,99 @@ +--- +name: ball-design-guide +description: "Design methodology for a new Buckyball ball: contract questions, funct7/ballId selection, isa/ctest templates, bemu golden model, Blink RTL wrapper, core wiring, MLIRTest, regression stems, verification-report reading. Use when designing, implementing, wiring, delivering or debugging a ball." +--- + +# Ball Design Guide + +How to implement one new Buckyball ball (operator) so it builds, registers and passes CI. This is methodology and structure; live repository facts (registries, encodings, regression tables, the frozen intrinsic enum) are fetched through the `bb-knowledge` skill, never memorized here. Work happens against a local checkout; commands below use `$BB` for its root. + +## Scope boundary: ball delivery vs model-side lowering + +The ball's delivery endpoint is the dual phase (c-bemu / rtl) plus MLIRTest. Whether the model pipeline lowers an operator to this ball depends on a four-gate pattern chain in the compiler (linalg→tile recognition, Tile dialect op, tile→ball hook, bank-SSA sharding emitter — see `knowledge/shared/model-to-ball-pipeline.md`), which lives outside the ball write-set. The ball implementer does not own it and must not promise it: deliver the ball, and when the chain is missing state plainly that the model path is unreachable — never imply the model will lower to the ball. + +## When to read which file + +- This file: the stage-by-stage flow, the rules that gate each stage, and the PR-body evidence-manifest template. +- `references/templates.md`: the exact shapes to copy (isa header, ctest, bemu crate, RTL wrapper) and how to view the live templates. +- `references/wiring.md`: stage 4 in full — registry rows, the five core wiring sites, the LLVM-export rule, MLIRTest triplets. +- `references/report-debug.md`: the five log layers and the seven failure patterns to read a failed verification report. + +## Stage 0 — Lock the contract, then pick codes + +Answer the five contract questions in writing and attribute each one to the brief (missing ones must be marked, never invented): operator semantics; ISA field and shape source; element width and per-iter footprint; illegal-input table (same checks on every layer); output layout and naming. + +Pick `ballId`, `funct7`, `inBW`/`outBW` only after checking the live tree, never from memory: + +- Check the reserved set first: `bb-knowledge` has the recipe (base ISA files named with two-digit funct7 prefixes — `[0-9][0-9]_*.c`, not a literal `NN_*.c` glob — `BallISA.scala` InitFunct, the analysis-side ISA table). A collision with a base ISA value only surfaces as a `ValueError` during `--analysis` — registration and builds stay green until then. +- Run `buckyball_isa_occupancy` for the occupancy map. `freeRanges` means *unclaimed* only — it does not subtract framework-reserved values. +- funct7 is a 7-bit CUSTOM_3 field: `[6:4]`=enable, `[3:0]`=opcode. Enable legend: `000` none, `001` 1rd, `010` 1wr, `011` 1rd+1wr, `100` 2rd+1wr, `101..111` reserved. The registry row's `inBW`/`outBW` must supply the ports the instruction family needs. +- funct7 must not collide with the target core registry's ballISA rows (veto). Cross-core reuse of a funct7 for the same mnemonic is legal and shows up in `conflicts` as `mnemonic-collision`. +- ballId numbers from 0 with no holes; one ball may hang several funct7 rows off one `ballIdMappings` row. + +## Stage 1 — C tests first, macros via mnemonic + +- Copy the live templates: isa header from `$BB/examples/balls/relu/workloads/isa/relu.h`, ctest from `$BB/examples/balls/relu/workloads/ctests/relu_test.c`, registration list from the same dir's `CMakeLists.txt` (`add_buckyball_ctests`). See `references/templates.md`. +- Never hardcode a funct7 number in a ball's isa header or its `.mlir` files: `#define X_FUNC7 50`, `BB_FUNC7(50)`, `funct7 = 50` and `BUCKYBALL_INSTRUCTION_*(.., 50)` as the last argument are all violations — the value is generated into `ballISA.h` from the registry, so a literal silently survives a renumbering. Use `BB_FUNC7()` only. +- One ctest `.c` file ≤ 100 lines — the build enforces it (`buckyball_enforce_ctest_line_limit`), and moving functional code into `.h` to evade it is explicitly forbidden. Split into focused tests. +- Two test shapes: `small` (short shape, hand-written vectors, boundaries, illegal inputs) and `bank` (random vectors, iter≈BANK_LINES, bemu only — never in the verilator list). + +## Stage 2 — bemu golden model + +- `emu/src/lib.rs` must carry exactly three symbols the generated dispatcher chains: `const BALL_CLASS: &str` (exact string equality with the registry `ballClass`), `execute_known` and `cycles_after_issue`, both returning `Option` (miss = `None`). There is no core-side emu file to wire; the dispatch chain is generated at build time. +- One instruction file per funct7. The numeral lives only in the registry row; lib.rs dispatches by mnemonic, so the instruction file carries no funct7 constant and the file name does not matter to dispatch. +- `exec` must `panic!` on illegal input — no sentinel returns. `.unwrap_or(..)` / `Ok(None)` shapes are flagged as non-blocking warnings by the audit (a saturation clamp and a swallowed error are for a human to tell apart). + +## Stage 3 — RTL wrapper and compute unit + +- Files go under `$BB/examples/balls//arch/src/main/scala/`; `arch/build.sbt` globs them, no registration. BBus instantiates by reflecting the registry `ballClass` FQCN with a `(GlobalConfig)` constructor, so `package` + `class` must spell it exactly. +- Wrapper shape: `@instantiable class XBall(b: GlobalConfig) extends Module with HasBlink`, look up `inBW`/`outBW` from `b.ballDomain.ballIdMappings`, `io = IO(new BlinkIO(b, inBW, outBW))`, tie off unused ports. See `references/templates.md`. +- Hard constraints (self-check list for stage 3): SRAM read is 1 cycle (`resp.valid` the cycle after `req.fire`, never same-cycle data); latch every field on `cmdReq.fire` including rob_id; FSM `idle → read → compute → write → complete → idle` with correct `status.idle/running`; explicit widths (`+&`); block same-bank read/write that would destroy source data. + +## Stage 4 — Register, then wire + +Full detail in `references/wiring.md`. The shape: three registry edits (mappings row, `ballNum` +1, ISA rows), then the ball-local minimum compiler set (exactly one dialect `*.td` + `Transforms/LegalizeForLLVMExport.cpp`), then on a single-core chip the core-side five wiring sites — sites 3, 4, 5 are build gates (missing 3 = link-time `undefined reference`; missing 4 or 5 = compiled but never called), sites 1 and 2 are include/doc surfaces. Then MLIRTest triplets and both regression stems. + +- The LLVM-export form is one: the dialect `*.td` must **not** inherit `Buckyball_IntrOpBase` (that emits an unconditional `llvm::Intrinsic::riscv_bb_` reference; the fork's enum is frozen and cannot be extended by a ball). Emit `CustomIntrOp` + `buckyball_target::getBuckyballFunct7("")` in `LegalizeForLLVMExport.cpp`. Check the actual enum via `bb-knowledge`'s intrinsic recipe. +- regression stem = `--ctest--`; mlirtest stem = `--mlirtest--`. `` is the compiler target name — derive it from `_target_name(core) = core.role or core.pkg` (see `bb-knowledge`), not from the chip directory name. + +## Reading a failed verification report + +The attribution tree lives in the design contract's report section (first question: did bemu pass?). For the RTL lane, the entry path is the five log layers and the seven failure patterns — `references/report-debug.md` lists each pattern with its tell and where to fix. + +## Evidence manifest template (PR body) + +Copy this block into the PR body and fill in the `<…>` slots; delete any optional line you do not use (a leftover placeholder is judged "unfilled template" and PRE-FAILs). The shape rules the machine checks (`validate-manifest.mjs`) are listed in the ball-designer playbook's staged-delivery section; field semantics are owned by the verify-runner prompt. + +``` +stage: ball +# phase 取值:c-bemu | rtl +phase: c-bemu +# round 可选,正整数,第几轮;不用就整行删 +round: 1 +# chip 必填:examples/chips/ 下的实物目录名(不是 core 名,也没有缺省) +chip: +# probe 可选、可多行,逐 stem 声明 probe 预算(分钟,缺省 3,验证侧语义解释; +# 该 stem 走 sim + analysis 成对步骤)。只允许写在无 phase / c-bemu / bind 轮, +# rtl 轮写它 = PRE-FAIL;不用就整行删 +probe: <分钟> +# perf 可选,单 token:本轮是性能轮。rtl 轮对 pmc-evidence.elapsed_avg(本轮自产, +# 不要求 probe: 行),c-bemu 轮对 probe-evidence.cycles(必须有同 stem 的 probe: 行) +perf: +# ball-expect 可选、可多行:逐 stem 声明 ball 落点期望(mnemonic 大写下划线、逗号 +# 分隔)——probe 轮零事件(空流)时它就是该 stem 记 PASS 还是 FAIL 的分界;stem +# 必须是本轮真会跑的那个(即本轮 probe: / perf: 声明过的 stem),否则 PRE-FAIL; +# 不用就整行删 +ball-expect: +- 改了哪些文件:逐条路径 +- 预期应跑的测试:本 ball 全部 ctest 与 mlirtest 的 binary stem 逐个列出, + 命名 --ctest--baremetal(如 pebble 的 transpose: + pebble-pebble-ctest-transpose_i8_16x16_test-baremetal; = 编译器 + target 名 = core.role or core.pkg,按上文「chip 回归 TOML」段那条生成链取, + 别拿 chip 名顶替)与 --mlirtest-_-baremetal +- audit 输出摘要 +``` + +## Rules that are easy to violate + +- The old "default to toy" assumption is gone: the evidence list's `chip:` is required and must name a real `examples/chips//` directory. +- Do not quote repository facts from memory — recipes exist precisely because the tree moved before. `buckyball_ball_audit` judges what it can read (nine structural checks) and reports what it cannot as not judged; a fresh submodule state (`git submodule status` showing `+`) means the intrinsic enum is unreadable until aligned. diff --git a/ball-design-guide/references/report-debug.md b/ball-design-guide/references/report-debug.md new file mode 100644 index 0000000..0e80839 --- /dev/null +++ b/ball-design-guide/references/report-debug.md @@ -0,0 +1,30 @@ +# Reading a verification report: log layers and failure patterns + +The report's carrier (PASS → PR review comment, FAIL → PR comment), its section structure and the attribution tree ("did bemu pass?") live in the design contract's report-reading rules. This file is the RTL-side debugging detail: the five log layers and the seven failure patterns. + +## The five log layers (RTL lane only) + +Trace layers are written by the RTL-side DPI and only appear in verilator/bebop runs — bemu has none of them: + +1. `bbdev/server.log` — build and compile errors first; +2. `stdout.log` — PASSED/FAILED output, panics; +3. `disasm.log` — the custom3 instruction stream: check the `mvin → op → mvout → fence` order; +4. `$BB/log/-*/bdb.ndjson` — trace lines by type: + - `{"type":"itrace"}` — clk / event / rob_id / funct / bank_enable / pc / rs1 / rs2; + - `{"type":"mtrace"}` / `{"type":"mtrace_issue"}` — bank addresses and data; + - `{"type":"pmctrace"}` — elapsed, the RTL-side real-time counter (the only value that can falsify emu `latency`); +5. waveform. + +## The seven failure patterns + +Work through them in order, against the log layers: + +1. **Ball never responds** — `itrace` shows ISSUE but no COMPLETE for the op. Look for a stuck FSM state or a never-fired response; check `status.idle/running` mapping first. +2. **All-zero output** — data comes back but every element is 0. Distinguish from (3) by checking whether the value is written at all; likely the `mvin`/`mvout` addressing, the row width (16B vs 64B), or a zero-filled accumulation. +3. **Output unchanged** — mvout delivers the input unchanged. The op's read of bank data never happened (SRAM handshake), or the compute wrote to the wrong bank. +4. **Partial data wrong** — a slice of elements is off. Tracking iter / stride / boundaries: an off-by-one in the loop bounds, the stride, or the bank row mapping. +5. **SRAM 1-cycle timing** — data wrong by exactly one row/line. `resp.valid` timing: read data on the next cycle after `req.fire`, never same-cycle. +6. **bank_id conflict** — two requests address the same bank, or an op overlaps its own read/write bank. Block same-bank read/write pair in the wrapper; same-bank conflicting ops must be rejected or serialized. +7. **rob_id not latched** — completion goes to the wrong rob_id. `cmdReq.fire` must latch every field including rob_id; a `fire`-guarded pass-through loses it. + +After identifying the layer and pattern, fix the owning layer only: bemu golden-model problems are never fixed in RTL (gold = ctest semantics), and a `latency` estimate is never patched to match RTL measurements — a mismatch at an order of magnitude is reported as a residual risk instead. diff --git a/ball-design-guide/references/templates.md b/ball-design-guide/references/templates.md new file mode 100644 index 0000000..038fb75 --- /dev/null +++ b/ball-design-guide/references/templates.md @@ -0,0 +1,58 @@ +# Templates: exact shapes to copy + +View the live templates before writing anything — they are the ground truth and they move. Every path below is a stable anchor; read the file, do not recall its content. + +## ISA header (stage 1) + +Live template: `$BB/examples/balls/relu/workloads/isa/relu.h` + +Shape: +- include `` and ``; +- macro body encodes the instruction via `BUCKYBALL_INSTRUCTION_R_R` with BB_BANK0 / BB_BANK1 / BB_ITER; +- the funct7 argument is only ever `BB_FUNC7()` — a mnemonic resolved through the registry, never a number. + +## ctest (stage 1) + +Live template: `$BB/examples/balls/relu/workloads/ctests/relu_test.c`, registered in `$BB/examples/balls/relu/workloads/ctests/CMakeLists.txt` via `add_buckyball_ctests`. + +Shape: +- `#include .h>` to get the ball's macros; +- sequence: `bb_mem_alloc → bb_mvin → bb_op → bb_mvout → bb_fence`, compare against the software expected value, print PASSED/FAILED; +- one `.c` ≤ 100 lines (`CTEST_MAX_LINES`); the same-directory `CMakeLists.txt` must list every `.c` with `add_buckyball_ctests`. + +## bemu crate (stage 2) + +Live template: `$BB/examples/balls/relu/emu/src/lib.rs` and `$BB/examples/balls/relu/emu/src/50_relu.rs`. + +Shape (`lib.rs`): +- `pub const BALL_CLASS: &str = ""` — string-identical to the registry row's `ballClass`; +- `#[path = "_.rs"] mod ;` per instruction file; +- `execute_known` / `cycles_after_issue` returning `Option`, `None` on a ballClass/funct mismatch; +- `exec` panic on illegal input. + +Naming note: the numbered filename prefix is a local convention, not an upstream rule — some upstream files are bare-named, and the prefix need not equal the registered funct7. Dispatch is by mnemonic; only the registry ballISA row owns the number. + +## RTL wrapper (stage 3) + +Live template: `$BB/examples/balls/relu/arch/src/main/scala/ReluBall.scala` (+ compute unit in `Relu.scala`). + +Shape: +- `@instantiable class Ball(b: GlobalConfig) extends Module with HasBlink`; +- `package` + `class` spell the registry `ballClass` exactly; +- `inBW`/`outBW` from `b.ballDomain.ballIdMappings` keyed by ballName; +- `io = IO(new BlinkIO(b, inBW, outBW))`; tie off unconnected ports (subRobReq / mmioRead). + +## dialect TD (stage 4) + +Live templates: `$BB/examples/balls/relu/compiler/` — the dialect folder, `Transforms/LegalizeForLLVMExport.cpp`, plus the core-side usage in `$BB/examples/cores/pebble/compiler/`. + +Shape: +- exactly one `*.td` under `compiler/src/Dialect/Buckyball/`; the op must not inherit `Buckyball_IntrOpBase` — emit through the generic `CustomIntrOp` + `buckyball_target::getBuckyballFunct7("")` form in `LegalizeForLLVMExport.cpp` (live proofs: every ball's legalize file). + +## MLIRTest triplet (stage 4) + +Live template: `$BB/examples/balls/transpose/workloads/mlir_tests/` (bank + ball directories, each with `transpose_16x16_i8.mlir` + `_main.cpp` + `CMakeLists.txt`; the group root `mlir_tests/CMakeLists.txt` only does `add_subdirectory(bank)` + `add_subdirectory(ball)`). + +Shape per test: +- `.mlir` — bank layer holds the bank Op, ball layer the lowered ball Op; no funct7 literals in the lit `// CHECK` lines either; +- `_main.cpp`; group `CMakeLists.txt` sets `BUCKYBALL_MLIR_GROUP_TARGET balls-mlir-tests-build`, `BUCKYBALL_MLIR_TEST_PREFIX bank|ball`, then `add_buckyball_mlir_test( TARGET ${BUCKYBALL_MLIR_ACTIVE_TARGET})`. diff --git a/ball-design-guide/references/wiring.md b/ball-design-guide/references/wiring.md new file mode 100644 index 0000000..3c4a898 --- /dev/null +++ b/ball-design-guide/references/wiring.md @@ -0,0 +1,48 @@ +# Stage 4 wiring: registry, compiler, regression + +Full wiring methodology for registering a new ball. Repository facts (exact rows, filenames, enum sets) come from `bb-knowledge`; the shape below is what must exist. + +## Registry edits (core side) + +The core's aggregate `configs/default.toml` points its `balldomain=` at the one active registry (`examples/cores//configs/balldomains/*.toml`, top-level; no variant selection). Three edits: + +1. `ballIdMappings`: one row `{ ballId, ballName, ballClass, config, inBW, outBW }` — `config` is a path relative to the registry file, must resolve to an existing ball config TOML. +2. `ballNum`: +1. +3. `ballISA`: one row per funct7 `{ mnemonic, funct7, bid }` with `bid` = the mapping row's ballId. + +Run `buckyball_ball_audit` right after; its core-registry check is the machine gate (ballNum == row count, consecutive unique ballIds, unique ballNames/mnemonics/funct7s, ≥1 isa row per ball, positive bandwidth). + +## Ball-side minimum compiler set (mandatory) + +`_ball_compilers` (in `compiler/scripts/pb_to_target_registry.py`, called from `compiler/CMakeLists.txt`) `_die`s the build when a registered ball lacks either: + +1. exactly one `*.td` under `compiler/src/Dialect/Buckyball/` (0 or ≥2 both die); +2. `compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExport.cpp`. + +Optional extras: `Conversion/LowerBuckyball/*.cpp` and `Conversion/LowerTileToBuckyball/*.cpp` — the generated lowering hooks (`_emit_lowering_hooks`) reference them only when present; absence is not a violation. + +## LLVM export form (the one legal shape) + +`mlir-tblgen -gen-llvmir-conversions` turns every `LLVM_IntrOpBase` op into an unconditional `llvm::Intrinsic::` reference. The LLVM fork's enum is frozen — a ball cannot add to it, and `Buckyball_IntrOpBase<"">` on an unlisted mnemonic is a compile-time failure. The tree's only shape: the dialect `*.td` does not inherit the IntrOp base; `LegalizeForLLVMExport.cpp` emits generic `CustomIntrOp` + `buckyball_target::getBuckyballFunct7("")`. To check a mnemonic against the live enum, use the `bb-knowledge` intrinsic recipe (check submodule state first — a `+` means the enum is from a drifted fork). + +## Core-side wiring (single-core chip, five sites) + +On a single-core build `compiler/CMakeLists.txt` add_subdirectory's the one core compiler package; the core's own CMake files are a hand-maintained per-ball manifest. To wire the new ball: + +1. `examples/cores//compiler/src/CMakeLists.txt`: add the ball's dialect dir to `_BALL_COMPILER_DIALECT_DIRS`. +2. `examples/cores//compiler/src/Dialect/Buckyball/Buckyball.td`: add `include ".td"`. +3. `examples/cores//compiler/src/Dialect/Buckyball/Transforms/CMakeLists.txt`: list the ball's `LegalizeForLLVMExport.cpp` in `add_mlir_dialect_library` (**build gate** — missing = link-time `undefined reference`). +4. `examples/cores//compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExport.cpp`: declare `populateLegalizeForLLVMExportPatterns` and `configureLegalizeForExportTarget` (**build gate**). +5. same file: call each once from the two export entry points (**build gate** — declaration-only compiles but never runs). + +Sites 1 and 2 are include/doc surfaces: `foreach` existence checks only cover listed dirs, and the op set/include paths are generated. They are not gates, but they are part of the manifest's completeness — the audit reports them in the detail only. A core whose manifest compiles no ball at all (the toy shape) or ships no compiler package cannot speak about this ball; the audit notes it as not judged. + +The audit's compiler-integration check judges sites 3/4/5 mechanically: every compiled legalize source in the core manifest, and each symbol occurring at least twice (declaration + call) in the core's legalize file. + +## MLIRTest (mandatory, phase-5 minimum) + +`workloads/mlir_tests/{bank,ball}/` triplets per `references/templates.md`; stem `--mlirtest-_-baremetal|linux`; every stem registered in the chip's bemu `workloads-elf.toml` (-baremetal) and `workloads-pk.toml` (-linux). The cmake side `continue()`s on a missing `mlir_tests` (so CI builds stay green), and the audit's mlir-regression check is what makes it mandatory — unregistered = blocking. + +## Regression stem (chip side) + +`examples/chips//regression/batch/bemu/workloads-{elf,pk}.toml` `[workloads].tests` lists stems; derive the target token from `_target_name(core) = core.role or core.pkg` (not the chip dir name, not the design filename); on toy/pebble all three happen to agree — do not generalize from that coincidence. Verilator lists take small tests only; bank tests stay bemu-only; pk stems are registered but pk *execution* is not part of acceptance (non-rushB verilator runs elf-tests only; rushB lanes are out of scope, `enable_rushb: true` chips only). diff --git a/bb-knowledge/SKILL.md b/bb-knowledge/SKILL.md new file mode 100644 index 0000000..e385cc1 --- /dev/null +++ b/bb-knowledge/SKILL.md @@ -0,0 +1,48 @@ +--- +name: bb-knowledge +description: "Knowledge base for the buckyball repository workflow: stage-grouped markdown files (chip/ball/workload/verify/shared) stating repository invariants plus live-repo lookup recipes for current values. Use when a task needs buckyball repository facts, reference examples, or current schemas — ball/funct7 counts, TOML schema keys, regression manifests, check.yaml structure, probe evidence grammar, registration write sets — or when any claimed repository fact must be re-derived from the live checkout." +--- + +# Buckyball knowledge base + +One lookup point for buckyball workflow knowledge. Every KB file carries two things: the +invariant (what does not move) and the recipes (how to re-derive what does). State invariants +freely; never state a current value without running a recipe against the live checkout. The +stage guides (`chip-design-guide`, `ball-design-guide`, `workload-integration-guide`, +`ci-verification-guide`) carry methodology and point here for repository facts. + +## Where it lives + +`../knowledge/` — relative to this file. The KB sits inside the skills root +(`$BB/.agents/skills/knowledge/` in the final layout, `out/skills/knowledge/` in staging), +one level up from this skill, so the same relative path holds in both. File layout: +`INDEX.md` (the map) plus `chip/ ball/ workload/ verify/ shared/` topic files. Each file has +`stage` and `tags` in frontmatter and a 活仓库现查 section whose commands use `$BB` for the +buckyball repo root (`$DSH_PLUGIN` for the dsh-plugin repo root, where a command needs it). + +## Lookup + +1. Read `../knowledge/INDEX.md` first — topics grouped by stage, one line each with tags. + Jump straight to the file from there. +2. Or grep instead of browsing: + - by frontmatter stage: `grep -l 'stage: chip' ../knowledge -r` (swap in the stage) + - by body keyword: `grep -rln 'funct7\|MODEL_LAYOUT\|check.yaml' ../knowledge` +3. Open the file, read the invariant section, then run each recipe in 活仓库现查 against the + live repository before quoting any value. Recipes are verbatim commands; the repository + root is `$BB`. +4. No matching topic: grep the live repository directly. Canonical starting points: + - enumerate examples: `ls $BB/examples/chips $BB/examples/balls $BB/examples/cores` + - check.yaml structure: `sed -n '/^ chip-check:/,$p' $BB/.github/workflows/check.yaml` + - bbdev source symbols: `grep -rn '' $BB/bbdev/api/steps --include='*.py'` + +## Rules + +- Repository facts are never quoted from memory — invariants yes, values only after a recipe + run. If a recipe cannot be run (checkout missing, submodule unaligned), say exactly what + you could not verify instead of filling it in. +- One topic lives in exactly one file; other files refer to it (见 xxx.md) instead of + repeating it. Prefer the narrowest file for the question at hand. +- A recipe that fails against the live tree (file moved, symbol renamed) is KB drift. Record + the drift; do not silently substitute a remembered value. +- Current-value assertions like "as of today there are N" do not belong in KB files. Read + what the recipe returns, not what a neighboring file says. diff --git a/chip-design-guide/SKILL.md b/chip-design-guide/SKILL.md new file mode 100644 index 0000000..debd780 --- /dev/null +++ b/chip-design-guide/SKILL.md @@ -0,0 +1,200 @@ +--- +name: chip-design-guide +description: "Guide for designing a new Buckyball chip: D1-D5 capacity chain, skeleton schema, contract.toml, mlirtest stems and batch manifests, model-binding write-set, bind round, perf iteration contract. Use when designing a chip, writing its configs or evidence manifest, deriving stems." +--- + +# Chip Design Guide + +This is the domain-knowledge reference for the chip stages. Discipline (write-set +boundaries, delivery rules, machine-checked manifest fields) lives in the +chip-designer playbook; this guide carries the method and the reference +implementations. Facts about the live checkout are never quoted here: every +value you need comes from a recipe run against the repository. + +## Working with the live repository + +- Treat every fact as current only after you `grep` it yourself; expand `$BB` + to the actual checkout path when running a recipe. Stable anchors only + (directory paths, file names, symbol names) — never line numbers or pins. +- Use the `bb-knowledge` skill for its recipes (chip-toml-schema, + capacity-banks, funct7-reserved, regression-manifest, mlirtest-wiring, + model-binding, verification-trace, model-to-ball-pipeline): this guide + names what to look for, the recipes give the exact commands. + +## Stage 0 — capacity evidence chain (single-core fit) + +The facts come from the index tool plus the capacity-banks recipe: the core's +`[bank]` geometry `{num, width, entries}` (`examples/cores//configs/ +memdomains/`) and, for spillover, the `[sharedMem] enable` of EVERY resolved +tile. The pool is core-private; banks are never pooled across cores. +1. **Row math**: `rowB = width / 8`; `bankB = entries × rowB`; private pool + `pool = num × bankB`; `lines(S) = ceil(elements × elemBytes / rowB)`; + `cols(S) = ceil(lines / entries)`. +2. **D1 — single region fits**: `lines <= cols × entries`. +3. **D2 — encodable columns**: `1 <= cols <= 32` (upper bound: the MSET column + range; lower: the physical-bank allocation's shape check; `cols = 0`, the + "whole pool" shorthand, is rejected — write the real column count). +4. **D3 — concurrency slots**: peak simultaneously-live `Σ concurrent × cols + <= num`. The compiler-side physical-bank allocation judges ONLY this + dimension (a CONTIGUOUS run of `need = row × col` slots); nobody judges + depth statically — that is why stage 0 judges D1 itself. D3 is necessary + but not sufficient: fragmentation can still fail allocation at compile time + (`out of physical banks`), a compile-time fact, not your judgement. +5. **D5 — shared-pool spillover**: admissible only when EVERY tile hosting + this core writes `[sharedMem] enable = true` (a sibling tile's `true` does + not vouch for a `enable = false` tile). Spill re-judges D3 against + `bankNum × nCores` slots — a WIDER slot set, never a deeper one: every + shared bank is the same `SramBank` with `bankEntries` rows, so D1 keeps its + `lines <= cols × entries` bound and the tile's `[sharedMem] entries` is a + declared value, not a per-slot depth. A single-core tile (`nCores = 1`) has + the same slot count as the private pool — no gain. c-bemu does not model the + shared pool, so a spill conclusion is RTL-side evidence only. +6. **Operator-internal shape predicates (D4)**: read each ball op's `*.td` + definition and its legalization for explicit rows/cols/iter constraints — + never guess from memory. +7. **Optimize before declaring failure**: if D1/D3 miss, first try different + tiling (row-group split, smaller blocks, serializing to lower peak + `Σ cols`) without changing op semantics. Still missing → announce the + failure and exit the whole flow. Report format: required vs bound (two + numbers) + the sharding parameters tried + the conclusion. +8. **PPA evidence**: `dc --area` / `dc --power` (needs the chip's `tapeout/` + contract) or `yosys --run`; scale-up reference: toy's 1t4c / 1t8c / 1t16c + and the goban topology family. +9. **Probe rounds (fork-private convention)**: performance PRs earn evidence + through a probe round — CI runs `bebop-bemu --analysis` and posts the + summary (funct hotspots + cycle counts) back to the PR; cite that post. + The before/after cycle-count delta is the ONLY acceptance criterion. + No posted summary → no performance claim, no invented numbers. + +## Stage 1 — topology and naming + +- Prefer ONE tile; express heterogeneity with core types, not tiles. Core + selection: five domain references and the compiler package presence. +- funct7 collision is a veto: a new ball's funct7 must not collide with the + selected core's balldomain (index reports `funct7Duplicates`) nor with the + base-ISA table / framework-reserved value (recipe: funct7-reserved). A + collision fails not at registration but at evidence time — check first. +- Multi-core: copy counts by stage-relative latency (TTFT-critical stages get + more cores for realtime scenarios). Naming: chip and core names are separate + (precedent: chip `poly`, cores `prefill`/`decode`); `prefill`/`decode` stay + reserved for the LLM pipeline. + +## Stage 2 — graph cut (multi-stage / multi-core only) + +- Use the buddy-mlir toolchain: import per model, one + `codegen/partition_strategy.py` per model, `verify_layer_partition.py` to + check, producing `partition_manifest.json` and slice groups. Never write + your own Dynamo partition script. +- One `contract.toml` per slice, locking `[slice]` / `[io.in]` / `[io.out]` / + `[policy]` (`mismatch = "error"`; template `references/contract-template.md`). + Toolchain docs: `compiler/thirdparty/buddy-mlir/docs/LayerPartitioning.md`. +- Slices that cannot be cut: say so plainly (stage-only); do not invent an + out-of-band partitioner, do not push it to the core designer, and do not + require full-model E2E green before cutting. + +## Stage 3 — skeleton checklist (8 mandatory + 1 optional) + +Read `references/skeleton-schema.md` before building (full 8+1 checklist with +an on-disk schema example and a live-tree recipe per item). Build under +`examples/chips//`, note which reference chip each item copies +(toy / pebble / poly / goban), and verify against the live tree. + +Four hard contracts (any violation fails the gate): + +- `configs/chip.toml`: `[designs] include` must point at this chip's design + file and `[sims]` must carry non-empty `verilator` and `p2e` keys. +- design `[top] nTiles` must equal the `[[tiles]]` row count or the + `[tileTemplate] count` expansion. +- every `WithBuckyballTiles` argument in `CustomConfigs.scala` must land under + `examples/chips//` (the config artifact is generated, never hand-written). +- sim config class names (`BuckyballVerilatorConfig`, + `P2EConfig`) are globally unique; `workloads/CMakeLists.txt` must + define the `chip-workloads-build` target. + +`arch/` and `configs/` are walked by the build automatically — no registration +step. Balldomain registries live under `examples/cores//configs/balldomains/`. + +## Stems and batch manifests + +- ctest stem: `--ctest-` + suffix (`-baremetal` for elf + lists, `-linux` for pk lists); `` is the `[[cores]] name` role, else + the package; the CMake side requires `BUCKYBALL_CTEST_TARGET` set (naming in + `bb-tests/workloads/src/CTest/CMakeLists.txt`). +- mlirtest stem: `--mlirtest-_` + same suffixes; + `` is the source's direct parent directory; the macro prevents + double-prefixing when `BUCKYBALL_MLIR_TEST_PREFIX` already carries the group + token, and a chip-local bespoke generator spells its full stem itself. +- **Cross-check both directions**: every ball-side mlirtest under the + referenced cores and every chip-side stem the wired `add_subdirectory` + groups produce must appear in the chip's bemu elf batch. List-present-but- + stem-missing = miss; list-absent because the chip has no `regression/` + directory = lane not registered upstream (report as unjudged, never silent). +- `exclude: — <理由>` lives in the PR evidence manifest (non-empty + reason only); batch TOMLs never carry excludes. +- Verdicts the audit no longer performs live: a `.mlir` in a wired group that + no generator call names is dead weight (nothing builds it, nothing to list); + a call whose stem is not derivable (interpolated `TARGET ${VAR}`, + `foreach`-generated names, unrecognized local function) is unjudgeable — + say so, never invent a stem. + +## Stage 5 — delivery and the CI sequence + +- The upstream sequence (read the live text, don't trust a copy): + `bbdev config --install` → `compiler --build '--chip '` → + `workload --clean` + `workload --build '--chip '` → bemu batch + `elf-tests` then `pk-tests` → verilator `--clean/--verilog/--build` → + verilator batch `elf-tests`. Recipe: + `grep -n 'nix develop -c bbdev' $BB/.github/workflows/check.yaml` +- Ordering semantics to state in the evidence list: slice unit tests first, + then sharedMem pairwise, then E2E. Command details live in the toolchain + docs (passed as the playbook's dynamic path parameter). +- PR evidence list per field rules: the chip-designer playbook "分阶段交付" + owns the machine-checked field 口径 (whole-line `--model`, probe/perf phase + whitelists, non-empty exclude reasons); template `references/manifest-template.md`. + +## Stage 6 — model binding and the bind round + +- Write-set is chip-side territory, four places, any one missing is red: + ① bbdev `MODEL_LAYOUT` entry (only for a NEW model key); ② e2e layout dir + `models/archs/buckyball///`; ③ three entries in the e2e + `models/archs/buckyball/CMakeLists.txt` (`BUCKYBALL__DIR` variable, + `BUCKYBALL_ALL_MODELS` whitelist item, `if(MODEL_ …)` wiring block); ④ the + parent-repo `bb-tests/workloads/scripts/build.py` `_MODELS` entry (a + parent-tracked plain file, not submodule content). +- Precedent split: chips WITH layout dirs copy the pebble shape; chips outside + the whitelist (e.g. toy, multi-rocket) copy the poly/Gemma4 shape — the two + goban/pebble-only variables are not available to them, and the archs + CMakeLists gates may require e2e branches; first-time binding outside the + whitelist is an upstream-uncovered path — expect the two gates. +- Bind round command sequence (the only source): `workload --build + '--chip --model '` → `kernel --build '--chip --model '` → per + model `bebop-bemu --sim '--chip --binary --pk'` (the run target + is a Linux-ABI static ELF — always `--pk`; `--pk` is bemu's in-process + proxy kernel, and the kernel step's `fw_payload` only feeds the closed + `bebop-p2e` lane). Only models the kernel lane knows are generated. +- Multi-submodule PR paradigm: feature branches in BOTH subrepos; the parent + PR carries the gitlink bump + `.gitmodules` change + the `_MODELS` entry, + with one `--model ` line per model in the evidence list. + +### Bind expectations vs the pattern chain + +A derived ball existing in the tree does NOT mean the model pipeline lowers +to it: model-side lowering needs a four-gate pattern chain (linalg→tile +recognition, Tile dialect op, tile→ball hook, bank-SSA sharding emitter). +Run the recipes in `knowledge/shared/model-to-ball-pipeline.md` before +declaring a bind expectation. Chain missing → the ball still delivers +(MLIRTest layer), but the expectation must state "model path unreachable +(missing pattern chain)" — never "the model will lower to the ball". + +## Reading verification reports + +Read `references/verification-report.md` before writing a perf-round evidence +list or interpreting a FAIL report (PASS/FAIL loop, perf iteration contract, +`latency`/`span_cycles` identity, bemu-first attribution tree). + +## Reference files + +- `references/manifest-template.md` — evidence manifest template; read before writing the manifest. +- `references/skeleton-schema.md` — 8+1 skeleton checklist with recipes; read when building the skeleton. +- `references/contract-template.md` — slice `contract.toml` template; read when cutting a graph. +- `references/verification-report.md` — report reading and perf iteration contract; read after a verification round. diff --git a/chip-design-guide/references/contract-template.md b/chip-design-guide/references/contract-template.md new file mode 100644 index 0000000..0da8184 --- /dev/null +++ b/chip-design-guide/references/contract-template.md @@ -0,0 +1,38 @@ +# Slice contract.toml template + +One file per slice, locked once written — the dispatch brief points at it. +Read when cutting a graph (stage 2). The `[policy] mismatch = "error"` value +is a hard rule: shape mismatch is an error, never silently resized. + +```toml +[slice] +id = "prefill_0" +subgraph = "sg_prefill" +core = "prefill" +instance = 0 + +[io.in] +name = "tokens" +dtype = "i32" +shape = [1, 128] +sharedmem_region = "tokens" + +[io.out] +name = "kv_cache" +dtype = "f16" +shape = [1, 32, 128, 64] +sharedmem_region = "kv_cache" + +[policy] +mismatch = "error" +``` + +- `id` must be unique across slices; `core` names a core package of the + design; `instance` is the core instance index within its tile/role. +- `sharedmem_region` names the tile's shared-memory region the io lives in; + the region's shape/dtype contract is what the capacity evidence chain + judges later. Keep the io shapes in sync with the actual model slice — + the brief locks them. +- The repository has no committed example (per historical records); + `compiler/thirdparty/buddy-mlir/docs/LayerPartitioning.md` is the toolchain + doc that explains what the partition produces. diff --git a/chip-design-guide/references/manifest-template.md b/chip-design-guide/references/manifest-template.md new file mode 100644 index 0000000..74faf77 --- /dev/null +++ b/chip-design-guide/references/manifest-template.md @@ -0,0 +1,67 @@ +# PR evidence manifest template + +Read before writing the evidence list into the PR description (stage 5 +delivery / bind round). The machine-checked field 口径 (comment-on-own-line, +whole-line `--model`, probe/perf phase whitelists, non-empty exclude reasons) +is owned by the chip-designer playbook "分阶段交付"; verify-runner's machine +check is the authority. Fill from the template below, delete every optional +line you do not use — a `<…>` placeholder left in is a failure. + +``` +stage: chip +# phase: skeleton | slices | integrate; bind is the separate multi-submodule PR +phase: skeleton +# round: optional, positive integer, which round +round: 1 +# chip: required, the examples/chips// directory name +chip: +# --model declaration: bind round only, one model per whole line (the key is +# the MODEL_LAYOUT / _MODELS key); [binding] reads ONLY these lines — a --model +# carried in a command is not a declaration +--model +# probe: optional, one line per stem with minutes; allowed only in no-phase / +# c-bemu / bind rounds; delete when unused +probe: +# perf: optional, a single stem token; pairs per instrumentation (rtl round → +# pmc-evidence from this round's own --pmctrace, c-bemu / no phase → the probe +# evidence of the same stem); forbidden in skeleton / slices / integrate +perf: +# ball-expect: optional, one line per stem with the uppercase mnemonics it must +# execute (comma-separated); only in rounds that produce probe steps and only +# for a stem that round really runs +ball-expect: +- 改了哪些文件:逐条路径 +- 预期应跑的测试: + - skeleton 轮:冒烟 ELF stem(该 chip 下已有 ctest) + - slices 轮:slice ELF stem 序列(按切分顺序) + - integrate 轮:regression batch 覆盖的 elf-tests + - bind 轮:模型 run stem 逐模型列出(build.py _MODELS 的 ninja 目标) +# capacity: optional — mandatory when stage-0 capacity evidence was produced; +# one block per core +capacity: + - core: + # peakBanks must equal Σ(concurrent×cols) of this block's region rows + # (excluded regions do not count) + peakBanks: <Σ(concurrent×cols)> + regions: + # exclude sits at the END of the region line as [exclude="<理由>"] — it is + # a field of the region, NOT the line-leading exclude: keyword (that one + # serves mlirtest stems). Empty reason = rejected; a block whose regions + # are ALL excluded judged nothing and fails. + - elements= elemBytes= cols= [concurrent=] [sharedPool=true] [exclude=""] +# exclude: optional, one line per stem with reason; serves the mlirtest +# coverage lanes only (non-empty reason required) +exclude: +- 骨架自查结论(buckyball_chip_audit 输出摘要;bind 轮附绑定向自查清单,容量轮附 core-capacity-fit 摘要) +``` + +Notes: + +- The whole file is pasted into the PR description body; update the body + BEFORE pushing each round (CI reads the body at trigger time). +- `- 改了哪些文件` style free-text lines are exempt from the placeholder + rule; only `probe:` / `perf:` / `ball-expect:` / `--model` declaration lines + are machine-checked. +- Machine input on the verify side treats values as "to end of line": never + write an inline `#` comment (`chip: toy # required` parses as `chip` + missing). Comments occupy their own lines. diff --git a/chip-design-guide/references/skeleton-schema.md b/chip-design-guide/references/skeleton-schema.md new file mode 100644 index 0000000..b7b7a19 --- /dev/null +++ b/chip-design-guide/references/skeleton-schema.md @@ -0,0 +1,128 @@ +# Skeleton checklist (8 mandatory + 1 optional) with on-disk schema examples + +Read this when building the stage-3 skeleton under +`examples/chips//`. Copy each item from the stated reference chip, +note which one it came from, and verify every item against the live tree with +the recipes below (expand `$BB` to the checkout path). + +The schema shapes themselves (chip.toml / design / tile / core config / +balldomain registry) live in the `bb-knowledge` `chip-toml-schema` recipe — +this file covers checklist items and where to look. + +## 1. `configs/chip.toml` (copy toy) + +`[designs] include = "designs/.toml"` (the config pipeline hard-requires +it) + `[sims]` with non-empty `verilator` and `p2e` keys (pipeline reads them +by name). + +```bash +sed -n '1,15p' $BB/examples/chips/toy/configs/chip.toml +``` + +## 2. `configs/designs/.toml` (copy toy) + +`[top] nTiles = 1` + `[[tiles]]` rows (`tile_id`, `include`), or +`[tileTemplate]` (`include`, `count`); include is relative to the design file. +`nTiles` must equal the materialized count. + +```bash +sed -n '1,12p' $BB/examples/chips/toy/configs/designs/toy.toml +# a tileTemplate-enabled design (multi-tile family): +sed -n '1,25p' $BB/examples/chips/goban/configs/designs/goban.toml +``` + +## 3. `configs/designs/tiles/default.toml` (copy toy) + +`memBallChannelNum` + optional `[privateDCache]` + `[sharedMem]` + +`[[cores]]` rows (`core_id`, `include` → resolves under +`examples/cores//configs/`). `[sharedMem]` facts are what the capacity +D5 judgement reads. + +```bash +sed -n '1,40p' $BB/examples/chips/toy/configs/designs/tiles/default.toml +``` + +## 4. `arch/src/main/scala/CustomConfigs.scala` (copy toy) + +`package examples.`, `BuckyballConfig` mixing in +`new WithBuckyballTiles("../examples/chips//configs/generated/chip.pb") +++ new chipyard.config.WithSystemBusWidth(128) ++ new sims.base.BuckyballBaseConfig`. +The `chip.pb` is generated by `bbdev config --install` — never hand-written. +Every `WithBuckyballTiles` argument must land under `examples/chips//`. + +```bash +sed -n '1,30p' $BB/examples/chips/toy/arch/src/main/scala/CustomConfigs.scala +``` + +## 5. `arch/src/main/scala/sims/verilator/TargetConfigs.scala` (copy toy) + +`BuckyballVerilatorConfig` (optional `WithBuckyballRushB` RushB variant); +sim class names are globally unique across chips — grep the whole tree before +reusing a name. + +```bash +sed -n '1,30p' $BB/examples/chips/toy/arch/src/main/scala/sims/verilator/TargetConfigs.scala +grep -rn 'class Buckyball' $BB/examples/chips/*/arch/src/main/scala/sims/ | head +``` + +## 6. `arch/src/main/scala/sims/p2e/TargetConfigs.scala` (copy toy) + +`P2EConfig` — same uniqueness rule. + +```bash +sed -n '1,30p' $BB/examples/chips/toy/arch/src/main/scala/sims/p2e/TargetConfigs.scala +``` + +## 7. `workloads/CMakeLists.txt` (toy precedent) + +Must define the `chip-workloads-build` target; chip-local ctests use +`add_buckyball_ctests()` — no glob. Ball ctests and ball +mlirtests weave in automatically from the balldomain registry via +`buckyball_add_ball_workload_subdirs(...)`; no chip-side listing needed for +them. + +```bash +sed -n '1,40p' $BB/examples/chips/toy/workloads/CMakeLists.txt +grep -rn 'buckyball_add_ball_workload_subdirs' $BB/bb-tests/workloads --include=CMakeLists.txt --include='*.cmake' | grep -v '/build/' | head +``` + +## 8. `regression/batch/{bemu,verilator,p2e}/workloads-{elf,pk}.toml` + +`[workloads] search_path` + `tests` list. Coverage rules and stem derivation: +see SKILL.md "Stems and batch manifests" and the `bb-knowledge` +`regression-manifest` / `mlirtest-wiring` recipes. Base the list on the +actual `add_buckyball_ctests` invocations and the derived mlirtest stems, +then cross-check both directions (CMake ↔ list). + +```bash +find $BB/examples/chips/toy/regression/batch -name 'workloads-*.toml' | sort +grep 'mlirtest' $BB/examples/chips/pebble/regression/batch/bemu/workloads-elf.toml | head +``` + +## 9. (optional) `tapeout/{config.toml,area/dc.tcl,power/power.tcl}` (copy toy) + +PPA evidence prerequisite — stage 0 may claim PPA only when it exists; skip +the whole directory when only bemu verification is planned. + +```bash +find $BB/examples/chips/toy/tapeout -type f | sort +``` + +## Multi-core additions (copy poly) + +- chip-level `emu/{Cargo.toml,src/main.rs}` — copy goban's `emu/src/main.rs` + verbatim (only the log string differs, e.g. `[INFO] Poly Chip BEMU:`); + Cargo `[package] name` / `[[bin]] name` = `bebop-chip-`, keep the + `bebop-bemu` relative dependency. +- design: multi-tile via `[tileTemplate]` (tile_ids / include / count); + tile-internal multi-core via named `[[cores]]` rows or `[coreTemplate] count`. +- Scala: `WithHartIdBits` (log2Ceil of total hart count) + multi-core + config classes; `[sims]` gets the variant class names. +- core stub directory so the include resolves — marked as a stub for the ball + designer to replace. + +```bash +ls $BB/examples/chips/goban/emu/ +sed -n '1,20p' $BB/examples/chips/poly/emu/Cargo.toml +sed -n '1,20p' $BB/examples/chips/poly/configs/designs/tiles/default.toml +``` diff --git a/chip-design-guide/references/verification-report.md b/chip-design-guide/references/verification-report.md new file mode 100644 index 0000000..ceb9bff --- /dev/null +++ b/chip-design-guide/references/verification-report.md @@ -0,0 +1,59 @@ +# Reading verification reports and the perf iteration contract + +Read when a verification round comes back or when you start a performance +optimization round. + +## PASS / FAIL loop + +- PASS = `gh pr review` approval plus evidence (commands run + results): the + task wraps up — final summary carries the PR link, the audit result and the + verification evidence. +- FAIL = a structured report: failed command, log tail, suspected attribution, + nextest JUnit list. The next round uses those three as the modification + input — fix what the report points at, push to update the PR, wait for the + next round. Loop until PASS. Never re-derive the failure from memory; a + failure's attribution is a hypothesis until the next report confirms it. + +## Perf iteration contract (family clause) + +Every optimization round writes THREE paragraphs in the PR description: + +1. what was changed, based on WHICH hotspot of the last probe round + (funct + cycle count) — this is the only accepted basis for the change; +2. which metric is expected to improve — and by what reasoning; +3. the verification basis (candidate evidence you expect in the reply). + +When the posted analysis is NON-EMPTY (funct cycle share / mean_rows / +bank_depth / matrix-instruction (M,N,K) histogram), those three paragraphs +are mandatory for the next round's PR. When the analysis stream is EMPTY +(host-fallback shape), only annotate "performance instrumentation not +applicable" — write no performance conclusion off an empty stream. + +Evidence rules: + +- Emu cycle estimates (a ball's own `latency`) reconcile ONLY against RTL + measured cycles. On the bemu side `span_cycles` IS the sum of those + `latencies` — comparing `latency` against it is an identity, never a valid + check; never report it as one. +- Only `--pmctrace` elapsed (the posted `pmc-evidence` line) measures the + `latency` claim independently; when the estimate deviates from it by more + than an order of magnitude, report it as a leftover risk. +- An optimization claim WITHOUT a prior probe round is an unproven claim: + do not assert it as evidence. + +Trace facts (raw data behind the summaries): `log/-*-bemu-*/bdb.ndjson` +holds one JSON object per line with a `"type"` field (itrace / mtrace / +pmctrace); there are no `[ITRACE]`/`[MTRACE]` marker lines; a 0-byte file is an +empty event stream, not a format issue. See the bb-knowledge +verification-trace recipe. + +## Attribution tree + +Ask one question first: did bemu pass? + +- bemu passes / RTL fails → RTL side: timing or DPI (waveform skill); a + cross-layer inconsistency (RTL ↔ bemu ↔ golden) goes to the ball-align skill. +- bemu fails → fix semantics first (golden model / dispatch chain); everything + on the RTL side is secondary until the semantics pass. + +Same order as ball design phase 6: bemu first, RTL second. diff --git a/ci-verification-guide/SKILL.md b/ci-verification-guide/SKILL.md new file mode 100644 index 0000000..8c05294 --- /dev/null +++ b/ci-verification-guide/SKILL.md @@ -0,0 +1,150 @@ +--- +name: ci-verification-guide +description: "How the buckyball verification pipeline builds and reads its runs: per stage/phase/layer command sequences, probe-round mechanics (budget, log-dir backfill, evidence-line grammar, zero-event classification), verdict and report formats, NDJSON event shapes, and the command whitelist rationale. Use when planning, executing, interpreting or reporting a buckyball PR verification run, or when asked about bbdev plan sequences, probe evidence lines, or perf-gate delta rules." +--- + +# CI Verification Guide + +Background knowledge for buckyball PR verification runs. The playbook's hard discipline +(verdict consumption, tool discipline, report contract) lives in the session prompt and is not +repeated here; this guide carries the mechanics behind it. + +## Command sequences + +The plan maps (stage, phase, layer, chip, stems, models, probes, probeBudget, perf, compilerTouched) +to one ordered step list. Sequence rules: + +- **No-phase baseline** (the v1 full-batch baseline; phase absent): workload clean → workload build → + bemu elf batch; stage `chip` prepends config install → compiler build; declared `models` append one + `workload --build --model` per model, then probe pairs for the declared probe stems. `compilerTouched` + prepends config install → compiler build for non-chip stages too. +- **ball/c-bemu**: (compilerTouched → config install → compiler build →) workload build → one bemu sim + per stem; a stem with `probe:` becomes a probe pair (c-bemu's instrument is the probe). +- **ball/rtl**: (compilerTouched → config install → compiler build →) verilator clean → verilog → + build → one `bebop-verilator sim --no-wave` per stem; the `perf:` stem adds `--pmctrace` (rtl's + instrument is pmc; it generates NO probe steps, and a `probe:` declaration here is a manifest + PRE-FAIL). +- **chip/skeleton**: config install → compiler build → workload build → one smoke stem sim (stems + must be non-empty). +- **chip/slices**: (compilerTouched → config install → compiler build →) one bemu sim per slice stem, + first failure stops the round. +- **chip/integrate**: (compilerTouched → … →) sims for the self-run slices stems (when the slices + gate requires it) → bemu elf batch. +- **chip/bind**: per declared model `workload --build --model`, then (kernel-lane models only) + `kernel --build --model`, then the probe pair — the upstream regression.yml paired run. `models` + must be non-empty. +- **complete layer** adds bemu pk batch + the verilator elf chain. +- **Batch lanes** are pruned when `examples/chips//regression/batch//workloads-.toml` + is absent from the tree (reported in `skippedLanes`, never silently dropped). Verilator pk is never + generated: the upstream non-rushB chain runs elf-tests only, pk-tests is rushB-only, and this + verification surface never enters the rushB space. +- **compilerTouched** is a PR-level judgment (whole PR write-set touching + `examples/balls//compiler/**` or `examples/cores//compiler/**`). Phases that consume the + compiler's product — no-phase baseline off a non-chip stage, c-bemu, rtl, slices, integrate — then + prepend config install → compiler build. skeleton always prepends them; bind never does (its + `workload --build --model` does consume the product, so a broken compiler fails in Provision + instead — that is deliberate). + +### Checking the sequence against the upstream file + +The order mirrors the upstream chip-check chain. To re-check the mapping against the live checkout: + +```sh +# chip-check job's matrix + non-rushB step order +grep -n "chip-check" -A 60 $BB/.github/workflows/check.yaml +# where verilator reaches pk-tests (rushB only) +grep -n "pk-tests\|rushB" $BB/.github/workflows/check.yaml +# the paired workload+kernel run in regression.yml +grep -n "kernel --build\|workload --build" $BB/.github/workflows/regression.yml +``` + +The plan's stage/phase legs and probe pairs exist only in the verification contract, not upstream, so +the check is about the base chain and the lane tomls, not every step. + +## Probe round + +The probe round answers "where is it slow", never "is it correct". It covers bind-round model stems and +stems with a `probe: ` declaration. Probe phases: `c-bemu`, `bind`, and the no-phase +baseline with declared models only — the manifest's phase whitelist PRE-FAILs any `probe:` outside them. + +Flow (strict order, each step submitted through the trio): + +1. Submit the plan-generated sim step (`bebop-bemu --sim … --pk --itrace --mtrace`). +2. Poll status up to the budget (default 3 min; the declaration's minutes override). Cancel at budget — + a budget-to-point `cancelled` is expected, not a failure. +3. Submit the paired analysis step with `--log-dir` replaced by the ONE candidate that + `buckyball_bbdev_probe_logdir({chip, stem, simStartedAt})` returns (it globs + `$BB/log/*--*-bemu-`, filters by mtime vs the sim's startedAt, and throws on zero or + multiple candidates; never glob by hand, never pick "the newest one" yourself). +4. Post evidence: cycles run, funct cycle-share top-5, mtrace bank occupancy, plus one machine-readable + evidence line for this round's instrument (see references/probe-events.md for the exact grammar). + Numbers come verbatim from the probe-read tool's `analysisText`; if it is missing, report + "analysis.txt 不存在" and follow the failure semantics. + +Failure classification (event counts from the probe-read tool; strict, no downgrade path): + +- Zero-byte / zero-itrace stream: if the manifest declares no ball-expectation for the stem, this is + the host-fallback shape — PASS with the note "零 ball-op: host fallback 形态 (probe 仪器不适用)"; + if it does declare one, FAIL "ball 未执行 (layout 管线断点)". The analysis step exiting 1 here is + covered by this branch (upstream analyser throws `no itrace events in ` by design) — do not add + a second "analysis 失败" FAIL. +- Any other analysis failure (truncated last line, `itrace span is 0 cycles`) → FAIL + "probe trace 分析失败", quote the error verbatim; no retry, no trimming, no silent rerun. +- Probe-read throws (log-dir or bdb.ndjson missing) → FAIL "probe log-dir 未找到". + +Judgment callouts for the report: model-level workload fully running >20 min is an unoptimized signal; +optimized-vs-unoptimized sim time differs 10x+. Delta math is per-instrument only: rtl rounds compare +`pmc-evidence` elapsed_avg, c-bemu/bind/no-phase compare `probe-evidence` cycles — never subtract +across instruments. A `perf:` round must present a same-instrument delta (else FAIL "性能结论无证据"); +incomparable budgets → "预算不可比,本轮不作性能结论"; no baseline → mark baseline, never claim an +optimization effect. + +Optimization-iteration contract: a coding-side PR should state three items in its description — which +probe hotspot (funct + cycle count) was addressed, what changed, which metric is expected to improve. +This verification surface has NO machine gate on those three items: missing them is a note at most, +never a FAIL, and having them is not performance evidence. The gates are the evidence line and the +same-instrument delta. + +## Verdict and report formats + +- First line of the final answer: `VERDICT: PASS` or `VERDICT: FAIL`. The process exit code only + reflects session completion, not the verdict. +- Both the PR reply and the final answer carry a `head sha: <40-hex>` line (the PR's headRefOid, + verbatim — no abbreviation, no case change). Integrate rounds' slices gate matches this line against + the current head to accept a previous PASS. +- PASS: `gh pr review --approve` plus a comment (judgment block restated, commands run with exit + codes, key output). When the bind round PASSes on probe evidence, the conclusion must state + 「功能收敛未证,需 complete 层或更长预算补全跑」. +- FAIL: `gh pr comment ` with four elements — failed command verbatim, log tail, suspected + attribution (from the decision tree: workload build → registration/build; bemu batch → semantics/ + integration; verilator after bemu → RTL), and JUnit facts from the junit-read tool. +- Mechanism descriptions in the report must match session evidence verbatim; if unsure, omit. + +## NDJSON event shapes + +Trace files are NDJSON — one event object per line (exact keys and semantics: see +references/probe-events.md). PMCTRACE exists only in RTL/verilator sims, never in bemu traces. + +## Whitelist rationale + +- `config install` — only producer of `chip.pb`; runs ahead of compiler build in the upstream chain. + It is args-free upstream (a boolean switch), so it must be submitted with NO args. +- `kernel build` — open for the bind leg's paired run with `workload --build --model` (regression.yml). + Only models in the kernel lane's own `KERNEL_MODELS` get the step (read from the tree at plan time — + `$BB/bbdev/api/steps/kernel/01_build_event.step.py`); anything else makes `kernel --build` raise + `unknown kernel model`, a guaranteed red. It is NOT a probe prerequisite: `--pk` is bemu's + in-process proxy kernel and never boots `fw_payload`. +- `bebop-p2e` — closed; it is the only consumer of `fw_payload`, outside this verification surface. +- `uvm` — closed: `uvm --run` is a live upstream gate but needs VCS/urg. +- `ip (generate|replace)`, `firesim`, `yosys`, `dc`, legacy `verilator`/`vcs` — closed; the `bebop-*` + front doors cover this surface. +- Sub-args are ONE argv string (bbdev shlex-parses it); pre-split args are rejected with + "must be quoted as one string". + +## Reference files + +Read the matching one when you need the full detail: + +- `references/probe-events.md` — evidence-line grammar (all four forms + sentinel literal, per-round + instrument exclusivity), NDJSON event keys, and how the NEXT round's perf gate parses them. +- `references/command-sequences.md` — per-phase step tables with lane gating and notes. diff --git a/ci-verification-guide/references/command-sequences.md b/ci-verification-guide/references/command-sequences.md new file mode 100644 index 0000000..9144488 --- /dev/null +++ b/ci-verification-guide/references/command-sequences.md @@ -0,0 +1,82 @@ +# Command sequences per stage × phase × layer + +The ordered bbdev step list the plan produces for every legal combination, with the note text the +session sees. Batch lanes are pruned on toml existence +(`examples/chips//regression/batch//workloads-.toml`); a pruned lane is +reported in `skippedLanes`, never silently dropped. + +## No-phase (v1 full-batch baseline) + +| stage | steps | +|---|---| +| workload | workload clean → workload build → bemu elf batch | +| ball | workload clean → workload build → bemu elf batch | +| chip | config install → compiler build → workload clean → workload build → bemu elf batch | + +`compilerTouched` adds config install → compiler build ahead for the non-chip stages. Declared +`models` append, after the batch step, one `workload --build --model` per model, then one probe pair +per declared probe stem (this leg's instrument is the probe; the evidence line is +`probe-evidence`). + +## ball/c-bemu + +(compilerTouched → config install → compiler build →) workload build → per stem either a bemu sim or, +when the stem has `probe:`, a probe pair (sim `--pk --itrace --mtrace` + paired analysis). + +## ball/rtl + +(compilerTouched → config install → compiler build →) verilator clean → verilog → build +(`--jobs 16`) → per stem `bebop-verilator sim --no-wave`; the `perf:` stem adds `--pmctrace`. No +probe steps exist here; a `probe:` declaration in this phase is a manifest PRE-FAIL. Instrument: pmc +(evidence line `pmc-evidence`). + +## chip/skeleton + +config install → compiler build → workload build → the single smoke stem bemu sim. (Always the +config/compiler pair, regardless of compilerTouched.) + +## chip/slices + +(compilerTouched → config install → compiler build →) one bemu sim per slice stem, first failure +stops the round. + +## chip/integrate + +(compilerTouched → config install → compiler build →) per self-run slice stem (present only when the +slices gate requires the round to run the slices sequence itself, stems from the manifest) → bemu elf +batch. + +## chip/bind + +Per declared model: `workload --build --model` → (kernel-lane models only) `kernel --build --model` → +probe pair. `models` must be non-empty. The kernel half is gated on the kernel lane's `KERNEL_MODELS` +(read at plan time from `$BB/bbdev/api/steps/kernel/01_build_event.step.py`); for a model outside the +set the kernel step is skipped with the reason written into that model's workload step note. +Instrument: probe. + +## complete layer extras + +On top of the above: bemu pk batch, and (ball/chip stages) the verilator chain: +clean → verilog → build → elf batch. Verilator pk batch is never generated — see the scope ruling in +SKILL.md. + +## Lane gating facts (verify against the tree) + +```sh +# What the upstream matrix declares per chip +grep -n "chip:" -A 6 $BB/.github/workflows/check.yaml | grep -E "chip:|enable_rushb|run_" +# Which tomls exist for a chip +ls $BB/examples/chips//regression/batch/*/workloads-*.toml 2>/dev/null +# The pairs upstream registration would consume +find $BB/examples/chips -path "*/regression/batch/*/workloads-*.toml" | sort +``` + +The plan prunes on the toml, not on the matrix flags: a lane with no toml cannot run even if the +matrix enables it, and a lane the matrix disables is reported as upstream's registration outside this +surface's space (the pk/verilator case). + +## Skipped-probe reporting + +A declared probe that produced no sim+analysis pair is reported in `skippedProbes` with its reason +(phase outside the probe whitelist, no-phase round without models, or stem absent from `stems`). The +session restates it and never treats it as run evidence. diff --git a/ci-verification-guide/references/probe-events.md b/ci-verification-guide/references/probe-events.md new file mode 100644 index 0000000..ba8e15c --- /dev/null +++ b/ci-verification-guide/references/probe-events.md @@ -0,0 +1,81 @@ +# Probe events, evidence lines and the next-round perf gate + +## Evidence line grammar (one line, one instrument, posted in the round's report) + +Probe instrument (c-bemu / bind / no-phase with models): + +``` +probe-evidence: cycles= +``` + +Multi-chip PR (chip-qualified shape): + +``` +probe-evidence: / cycles= +``` + +Zero-event round (host-fallback shape) — the sentinel. `none` and the parenthesized literal are fixed +strings; do not rewrite as `cycles=0`, do not drop the parenthesis, do not omit the line: + +``` +probe-evidence: cycles=none (instrument-not-applicable) +``` + +PMC instrument (rtl round, the `perf:` stem ran with `--pmctrace`): + +``` +pmc-evidence: calls= elapsed_avg= elapsed_max= elapsed_min= +``` + +Rules: + +- A round posts exactly the line for ITS instrument: rtl rounds never post `probe-evidence:` (their + plan has no probe steps); other phases never post `pmc-evidence:` (they produce no pmctrace). + A cross-instrument line would forge a comparison baseline. +- Line-decoration tolerance (leading whitespace, `-`/`*` bullets, paired backticks) is tolerated by + the retrieving side; key names and field order are NOT — `周期数=` or `probe_evidence:` is treated + as evidence not delivered. +- Any probe-instrument line — numbers line AND the zero-event sentinel — must sit in the SAME report + as the round's `probe: ` declaration line: the next round's perf gate reads + `prev-budget` only from that same report. Without it the next round always gets `unknown` = + "budget not comparable". The evidence line itself carries no budget field; if the declaration is + absent, do not invent one. +- Prose without an evidence line = evidence not delivered (nothing for the next round to compare). + +`cycles` is the analysis report's `span_cycles` verbatim. `span_cycles` is printed by +`$BB/bbdev/api/steps/bebop/bemu/scripts/bemu_analysis.py` (symbol-level check: + +```sh +grep -n "span_cycles\|no itrace events" $BB/bbdev/api/steps/bebop/bemu/scripts/bemu_analysis.py +``` + +## NDJSON event shapes + +`bdb.ndjson`, one event object per line, immediately flushed: + +- `{"type":"itrace", ...}` — every ball-op completion (the only itrace producer). Field set carries the + per-funct cycle spans summed into `span_cycles`. +- `{"type":"mtrace","event":"read|write", ...}` — mvin/mvout memory traffic; the only mtrace producer. +- `{"type":"pmctrace", ...}` — RTL/verilator sims only, produced by `--pmctrace`; carries `elapsed` + values aggregated into the pmc-evidence line (calls, avg/max/min). + +Zero-event shape: a fully-scalar host-fallback run physically emits no itrace (no ball-op executed). +This is why the zero-byte branch exists at all — check the analyser's throw on zero events: +`grep -n "no itrace events" $BB/bbdev/api/steps/bebop/bemu/scripts/bemu_analysis.py`. + +## How the next round's perf gate reads these + +The perf gate (`probe-loop-check.mjs` semantics) merges comments ∪ reviews into one timeline (each +side has its own order; the array tail is NOT the PR's time order), takes the latest hit per +(stem, instrument), and returns: + +- `instrument` — the phase of the round that owns the line: rtl → pmc, else probe. +- `prev-cycles` / `prev-pmc` / `prev-elapsed-avg` — the corresponding numbers, one side always + `(无)`-worth null. +- `prev-found` — whether a same-instrument line exists at all. +- `prev-sentinel` — true when the line is the zero-event sentinel literal. +- `prev-budget` — read from the `probe: <分钟>` declaration in the SAME report as the hit line. +- `baseline` — no previous same-instrument data. + +The consuming round then applies the four gates: instrument alignment (no cross-instrument deltas), +delta obligation when prev-found, budget comparability, and the sentinel/baseline two-shape handling. diff --git a/knowledge/INDEX.md b/knowledge/INDEX.md new file mode 100644 index 0000000..1a0f929 --- /dev/null +++ b/knowledge/INDEX.md @@ -0,0 +1,96 @@ +# 知识库索引 + +本目录最终落在 `$BB/.agents/skills/knowledge/`(与 skill 同仓)。目录内**永远不要出现 +SKILL.md**:skills 根的直属目录一旦带 SKILL.md 就会被 dsh 当成 skill 加载。 + +buckyball 工作流知识库,按 stage 分目录:`chip/`、`ball/`、`workload/`、`verify/`、 +`shared/`。每个文件的结构固定:一段「这是什么」→「不变量 / 契约」 +(稳定事实)→「活仓库现查」(检索配方,一条配方一句说明加一条命令)。现值一律按配方 +在活树上现查,文件不抄现值;单一事实只写在一个文件里,别处引用只写「见 xxx.md」。 + +配方命令里的两个路径变量: + +- `$BB` = buckyball 仓根(当前 checkout:`/home/ROXY/code/bb_work/buckyball`) +- `$DSH_PLUGIN` = dsh-plugin 仓根(`/home/ROXY/code/bb_work/dsh-plugin`),只在 + verify 几篇涉及 CI 物料时用 + +## chip(7 个) + +- `chip-toml-schema.md` — chip 配置五类 TOML(chip.toml / design / tile / core 聚合配置 / + balldomain 注册表)的必要键与 include 链规则,Scala 侧 `WithBuckyballTiles` 与仿真 + 类名约定。 + tags: schema, chip.toml, design, tile, core-config, balldomain +- `capacity-banks.md` — 单核容量判定的事实源:memdomains `[bank]` 三键几何、行字节与 + 池公式、D1–D5 要用到的物理事实;共享池的真相是槽变宽、深度不变。 + tags: capacity, bank, memdomain, sharedMem, D1-D5 +- `funct7-reserved.md` — 指针:funct7 两层禁区的事实源在 `ball/funct7-encoding.md`, + 本文件只补 chip 侧工具边界(`funct7Duplicates` 不覆盖基础 ISA 表与框架自留值)。 + tags: funct7, isa, ball-registry, reserved +- `mlirtest-wiring.md` — MLIRTest 两处接线:ball 侧 registry 织入、chip 侧 + `add_subdirectory` 链;标准宏命名与 bespoke 生成器例外。 + tags: mlirtest, cmake, wiring, mlir_tests +- `model-binding.md` — bind 轮四处写集:bbdev `MODEL_LAYOUT`、e2e layout 目录、 + archs CMakeLists 三处条目、父仓 `build.py` `_MODELS`;白名单内/外的芯片各按哪种 + 先例抄。 + tags: model-binding, MODEL_LAYOUT, _MODELS, archs, layout +- `regression-manifest.md` — regression 批清单(`batch//workloads-.toml`) + 的结构、`exclude:` 只出现在 PR 证据清单、无 `regression/` 目录 = lane 未注册 + (与漏跑是两回事);ctest / mlirtest stem 命名链的事实源在 + `ball/regression-tables.md`,本文只留指针。 + tags: regression, batch, manifest, stem, exclude +- `verification-trace.md` — 验证产物落点(`log/<时间戳>-*-bemu-*/bdb.ndjson`)、 + NDJSON 行格式、空 trace 的语义、`span_cycles` 是 latency 累加和这一恒等式。 + tags: verification, trace, ndjson, log + +## ball(4 个) + +- `balldomain-registry.md` — core 的 balldomain 注册表是 ball 集成的唯一事实源: + `ballIdMappings` / `ballISA` 双表行规则、`ballNum` 连续无洞等 audit 机检不变量。 + tags: balldomain, registry, toml, registration, core +- `funct7-encoding.md` — funct7 的 7 位字段划分(enable `[6:4]` / opcode `[3:0]`)、 + 与基础 ISA 撞值在 `--analysis` 才死、占用图 `freeRanges` 只表示未认领。 + tags: funct7, isa, encoding, reserved, selection +- `intrinsic-enum.md` — LLVM fork 的 intrinsic 枚举是冻结的:唯一合法出口 = + `CustomIntrOp` + `getBuckyballFunct7`;查枚举前先对齐两级 submodule。 + tags: intrinsic, llvm, fork, enum, compiler, submodule +- `regression-tables.md` — bemu 批清单 stem 生成链,其中 `` = `core.role or + core.pkg`(不是 chip 目录名);verilator 只放 small、bank 只走 bemu。 + tags: regression, stem, ctest, mlirtest, target, chip + +## workload(3 个) + +- `build-py-models.md` — 父仓 `bb-tests/workloads/scripts/build.py` 的 `_MODELS` 表 + (模型键 → cmake 名 + ninja 目标);这张表属 bind 轮,workload 轮对 `build.py` + 零 diff。 + tags: build.py, _MODELS, bind, recipe +- `gitignore-conventions.md` — e2e 模型树两层 `.gitignore` 的分工(父级盖粗粒度、 + 目录自己盖特有产物);入库期望值不得被任何一层命中;判忽略用 `git check-ignore`。 + tags: e2e, gitignore, recipe +- `model-tree-and-registration.md` — e2e 模型目录固定位置与两处 CMake 登记(MODEL + reset 列表 + `MODEL__DIR` / `if(MODEL_)` 守卫);旗标拼写以现查为准, + 别从目录名推。 + tags: e2e, models, cmake, registration, recipe + +## shared(1 个) + +- `model-to-ball-pipeline.md` — 模型算子落 ball 的四关 pattern 链(图侧识别 → tile + op → tile→ball hook → 分片发射器)、ball 交付与模型落 ball 的边界、「6144 是 + bank 行数不是代码行数」与逐关检索配方。 + tags: model-to-ball, pattern-chain, linalg-to-tile, tile-hook, bank-ssa, bind + +## verify(4 个) + +- `checkyaml-structure.md` — `.github/workflows/check.yaml` 的 job 结构速览 + (pre-commit / chip-check 矩阵、四条泳道与开关、rushB 条件);引用它只用 + job/步骤/文件名锚,行号与 pin 一律现查。 + tags: buckyball, check.yaml, ci, 检索配方 +- `ci-workflow.md` — `ci/bb-verify.yml` 的五段机制:verdict-gate、评论在场门禁、 + 只读门禁、provision 豁免、INFRA 回流;含镜像侧(豁免组合表)与 plan 唯一事实源 + 的关系。 + tags: buckyball, ci, bb-verify, verdict-gate, INFRA, 检索配方 +- `contract-clauses.md` — 契条款规范文本的指针表(分阶段验证 / 分阶段交付 / prompt + 消费条 / 五个判定脚本);「共 N 条」这类叙述不是数字断言。 + tags: buckyball, 契约, 分阶段验证, 分阶段交付 +- `plan-mapping.md` — `bbdev-plan` 命令序列与 check.yaml chip-check 的对照、核对配方, + 以及「映射只以契约 + 配方核对、不做机检」的决策记录。 + tags: buckyball, bbdev-plan, check.yaml, 检索配方, 决策日志 diff --git a/knowledge/ball/balldomain-registry.md b/knowledge/ball/balldomain-registry.md new file mode 100644 index 0000000..da29c60 --- /dev/null +++ b/knowledge/ball/balldomain-registry.md @@ -0,0 +1,45 @@ +--- +stage: ball +tags: [balldomain, registry, toml, registration, core] +updated: 2026-09-08 +--- + +# balldomain 注册表 + +## 这是什么 + +core 的 balldomain 注册表是 ball 集成的唯一事实源:ball 的行、每行挂的 ISA(mnemonic/funct7)、以及 ball 的 config 文件在此登记。新 ball 的阶段 4 改动就落在这里;注册表也驱动 `ballISA.h` 生成、编译器 target 注册与 bemu 分发链。 + +## 不变量(稳定事实) + +- 位置:`examples/cores//configs/balldomains/*.toml`(顶层文件即注册表;其下 `balls/` 子目录是 per-ball 配置覆盖,不是注册表)。core 的聚合配置 `configs/default.toml` 用 `balldomain=` 指向唯一注册表——每 core 一份,无变体选择。rocket 类 core 只带空注册表(`ballNum = 0`)。 +- 一个 TOML 必须同时带 `ballIdMappings` 与 `ballISA` 两个数组(两者缺一即判「不是注册表」——这是本插件家族自定规则,非上游检查)。 +- `ballIdMappings` 行:`ballId` / `ballName` / `ballClass` 必填;`config` 取值相对注册表文件解析、必须指向存在的 ball configs TOML(悬空即抛错);`inBW`/`outBW` 正数。 +- `ballISA` 行:`mnemonic` / `funct7` 必填,`bid` 必须指向本注册表内已注册的 ballId。 +- 不变量(audit 的 core-registry 机检本体):`ballNum` == 映射行数;ballId 从 0 连续无洞;ballId / ballName 无重复;ballISA 内 funct7 / mnemonic 无重复;每球 ≥1 条 ISA;带宽为正。 + +## 活仓库现查 + +- 全部注册表清单(只看顶层): + + ```bash + find $BB/examples/cores -name '*.toml' -path '*configs/balldomains/*' ! -path '*/configs/balldomains/balls/*' | sort + ``` + +- 某 ball 注册在哪些 core(按 ballClass 全等搜;可换成 ballName): + + ```bash + grep -rln 'examples.balls..Ball' $BB/examples/cores/*/configs/balldomains/*.toml + ``` + +- 某 core 的注册表指向(聚合配置): + + ```bash + grep -n 'balldomain' $BB/examples/cores//configs/default.toml + ``` + +- 一个注册表里全部 mnemonic/funct7 行: + + ```bash + grep -n 'mnemonic =\|funct7 =\|ballId =\|ballName =' $BB/examples/cores//configs/balldomains/default.toml | head -60 + ``` diff --git a/knowledge/ball/funct7-encoding.md b/knowledge/ball/funct7-encoding.md new file mode 100644 index 0000000..4b65b33 --- /dev/null +++ b/knowledge/ball/funct7-encoding.md @@ -0,0 +1,41 @@ +--- +stage: ball +tags: [funct7, isa, encoding, reserved, selection] +updated: 2026-09-08 +--- + +# funct7 编码约束与保留区 + +## 这是什么 + +buckyball 的 CUSTOM_3 指令用 7 位 funct7 编码;新 ball 在阶段 0 选码时必须避开框架保留区,并满足 enable 位与读写语义的对应关系。本文是这条约束的不变量与活仓库现查配方(数值不给现值,按配方查)。 + +## 不变量(稳定事实) + +- funct7 是 7 位字段:`[6:4]` = enable 位,`[3:0]` = opcode。enable 图例:`000` none / `001` 1rd / `010` 1wr / `011` 1rd+1wr / `100` 2rd+1wr / `101..111` 保留(扩展 opcode 空间)。 +- funct7 不得与**目标 core** balldomain 注册表内已注册的 funct7 重复(一票否决)。cross-core 对同一 mnemonic 的复用合法(占用图会把这种行列入 `conflicts` 的 `mnemonic-collision`)。 +- **撞基础 ISA 的拦截时机**:注册表 validate 不查它;是 `bebop-bemu --analysis`(`bemu_analysis.py` 的 ISA 表)抛 `ValueError("ballISA funct7 N (MNEMONIC) collides with ISA ")` 才炸——也就是说球能注册、能构建、能跑完仿真,只在取证分析那步死掉。保留区是**选码期**就要避开的,不是等工具报错。 +- 基础 ISA 表有名字但无对应数字前缀 `.c` 文件的项不会被占用图认领;选码前必须按配方现查,不能只看 `freeRanges`。 + +## 活仓库现查 + +- 基础 mem/frontend 宏前缀(文件名两位数字前缀即 funct7): + + ```bash + find $BB/bb-tests/workloads/lib/bbhw/isa -name '[0-9][0-9]_*.c' | sort + ``` + +- BALL_INIT(framework 从 `BallISA.scala` 的 `InitFunct` 取值,注册表 ballISA 行撞上它直接被 `BallDomainDecoder.scala` 的 `require` 拒绝): + + ```bash + grep -n 'InitFunct' $BB/arch/src/main/scala/framework/balldomain/isa/BallISA.scala + grep -n -A 2 'framework-reserved' $BB/arch/src/main/scala/framework/balldomain/decoder/BallDomainDecoder.scala + ``` + +- analysis 侧 ISA 表(有名字但可能没有对应 `.c` 文件的条目,撞它的球在 `--analysis` 期才死): + + ```bash + grep -n -A 9 '^ISA = {' $BB/bbdev/api/steps/bebop/bemu/scripts/bemu_analysis.py + ``` + +- 已认领 / 冲突概览:调 `buckyball_isa_occupancy`(`freeRanges` 只表示「未被认领」,不含上表两处框架值)。 diff --git a/knowledge/ball/intrinsic-enum.md b/knowledge/ball/intrinsic-enum.md new file mode 100644 index 0000000..ab4f6ef --- /dev/null +++ b/knowledge/ball/intrinsic-enum.md @@ -0,0 +1,33 @@ +--- +stage: ball +tags: [intrinsic, llvm, fork, enum, compiler, submodule] +updated: 2026-09-08 +--- + +# LLVM fork 冻结 intrinsic 枚举 + +## 这是什么 + +ball 的编译器 LLVM 出口引用 `llvm::Intrinsic::riscv_bb_` 枚举。这个枚举由 vendored LLVM fork(`compiler/thirdparty/buddy-mlir/llvm`)声明,是**冻结**的:ball 无法往 fork 里加条目,引用一个不存在的枚举就是编译期挂。本文件是这条约束与现查配方。 + +## 不变量(稳定事实) + +- `mlir-tblgen -gen-llvmir-conversions` 把每个 `LLVM_IntrOpBase` op 转成**无条件**的 `llvm::Intrinsic::` 引用——方言 `*.td` 继承 `Buckyball_IntrOpBase` 就必然生成对冻结枚举的引用,枚举里没有它 = 编译失败。 +- 唯一的合法出口形态:方言 `*.td` **不**继承 IntrOp base,在 `Transforms/LegalizeForLLVMExport.cpp` 里发通用 `CustomIntrOp` + `buckyball_target::getBuckyballFunct7("")`(现有 ball 全部如此)。 +- 枚举的声明文件集合随 fork 的 pin 变(入口 `IntrinsicsRISCVBuckyballExt.td` 加它 include 的 per-core 扩展),所以**不背文件名单**,一律 glob 现查。 +- nested `llvm` 是子模块的子模块:`git submodule status` 里带 `+` 表示工作树不是 fork 记录的 commit——两个不同 commit 声明两个不同的 `int_riscv_bb_*` 集合,必须先对齐再查。 + +## 活仓库现查 + +- 对齐状态(两级都查;带 `+` 就先对齐:`git -C $BB/compiler/thirdparty/buddy-mlir submodule update --init --recursive llvm`): + + ```bash + git -C $BB submodule status compiler/thirdparty/buddy-mlir + git -C $BB/compiler/thirdparty/buddy-mlir submodule status llvm + ``` + +- 冻结枚举集合(路径含 `` 相关的 mnemonics 可直接 grep 核对): + + ```bash + grep -rhoe 'int_riscv_bb_[A-Za-z0-9_]*' $BB/compiler/thirdparty/buddy-mlir/llvm/llvm/include/llvm/IR/*.td | sort -u + ``` diff --git a/knowledge/ball/regression-tables.md b/knowledge/ball/regression-tables.md new file mode 100644 index 0000000..f9c1f57 --- /dev/null +++ b/knowledge/ball/regression-tables.md @@ -0,0 +1,44 @@ +--- +stage: ball +tags: [regression, stem, ctest, mlirtest, target, chip] +updated: 2026-09-08 +--- + +# 回归清单格式与 stem 生成链 + +## 这是什么 + +chip 的 bemu 批回归清单登记每个 ball 的 ctest / mlirtest binary stem,是 CI 按名单跑测试的依据;stem 的第二个 token 是编译器 target 名,不是 chip 目录名。新 ball 的每一行登记必须按本条生成链推导。 + +## 不变量(稳定事实) + +- 位置:`examples/chips//regression/batch/bemu/workloads-{elf,pk}.toml`,内容为 `[workloads].tests` 的字符串数组;elf 表条目以 `-baremetal` 结尾、pk 表以 `-linux` 结尾。 +- ctest stem:`--ctest--baremetal`(elf)/ `-linux`(pk);mlirtest stem:`--mlirtest-_-baremetal`。`` 是 ctest 文件名去 `.c`,`_` 是 mlir 文件按组前缀推出的 test id。 +- **`` = `_target_name(core) = core.role or core.pkg`**(core 的 role,没有 role 就用 core 包名),不是 chip 目录名、不是 design 文件名;toy / pebble 上三者恰巧同值,是巧合不是规则,别拿它推广。 +- verilator 列表只放 small tests;bank tests 仅 bemu;`-rushB.toml` 变体表不进两层判定(pk 执行不作验收:非 rushB 的 verilator batch 只跑 elf-tests)。 + +## 活仓库现查 + +- 谁带 bemu 批表(注册前先确认目标 chip 有表): + + ```bash + find $BB/examples/chips -path '*/regression/batch/bemu/workloads-elf.toml' | sort + ``` + +- 现行 stem 与 target token(升序去重,看实物的形): + + ```bash + grep -h 'ctest-\|mlirtest-' $BB/examples/chips/pebble/regression/batch/bemu/workloads-elf.toml | sort -u | head + ``` + +- target 名推导链(`_target_name` + `profile.name` 匹配): + + ```bash + grep -n -A 1 'def _target_name' $BB/compiler/scripts/pb_to_target_registry.py + ``` + +- chip 的 design token(audit 判回归用 `[designs] include` 的文件名 stem 推 ``): + + ```bash + grep -n -A 2 '\[designs\]' $BB/examples/chips//configs/chip.toml + ``` diff --git a/knowledge/chip/capacity-banks.md b/knowledge/chip/capacity-banks.md new file mode 100644 index 0000000..f2d077f --- /dev/null +++ b/knowledge/chip/capacity-banks.md @@ -0,0 +1,52 @@ +--- +stage: chip +tags: [capacity, bank, memdomain, sharedMem, D1-D5] +updated: 2026-09-08 +--- + +# 容量事实源与银行几何 + +## 这是什么 + +单核容量判定的全部数值事实来自 `examples/cores//configs/memdomains/*.toml` +的 `[bank]` 表(`num`/`width`/`entries`)。银行池是 **core 级私有**:每个 core 实例 +各自铺出自己的 `SramBank` 数组,全树没有跨 core 的共享 bank 集合;编译期的 +physical-bank 分配也只在当前 target 自己的 `bankNum` 里找槽位,借不到别的池。 +本文记录这些不变量与「共享池」的真相,现值一律现查。 + +## 不变量 / 契约 + +- `[bank]` 三键必须都是正整数,`width` 必须是 8 的倍数;行字节 `rowB = width / 8`, + 每 bank 字节数 `bankB = entries × rowB`,单核私有池 `pool = num × bankB`。 + 形状坏了管线直接死(`bank_params`),所以现查时见到异常值要先怀疑写入失误。 +- 私有池的 `num` 是**槽位维**(并发段分配上限),`entries` 是**深度维**——上游 + physical-bank 分配只判槽位维(`need = row × col` 在 `bankNum` 里找**连续**空位), + 深度维全链无人静态判,这也是阶段 0 必须自己判 D1 的原因。 +- 共享池(tile 的 `[sharedMem] enable = true`):RTL 侧铺 `bankNum × nCores` 个 + `SramBank`(`nCores` = 该 tile 的 core 数),每个槽的深度仍等于私有池的 + `bankEntries`——**外溢换来的是更宽的槽集合,不是更深的槽**。tile 里写的 + `[sharedMem] entries` 只是申报值,不是每槽深度。 +- c-bemu 验证面**不建模共享池**(只镜像私有池的映射表),外溢结论只能到 RTL 面 + 取证,不得声称 bemu 已验证;单核 tile(`nCores = 1`)的共享池与私有池槽数相同, + 别指望它扩容。 +- D1–D5 的判定公式与「先优化再判死」的流程是方法论,见 skill `chip-design-guide`; + 本文只提供公式所需的物理事实。 + +## 活仓库现查 + +```bash +# 全部 core 的 [bank] 现值(num/width/entries) +grep -A4 '^\[bank\]' $BB/examples/cores/*/configs/memdomains/default.toml + +# 某 core 的完整 memdomain(含 [dma]/[tlb] 等附属事实) +sed -n '1,40p' $BB/examples/cores/pebble/configs/memdomains/default.toml + +# 某 tile 的 [sharedMem] 申报值(enable/entries,注意它不是每槽深度) +grep -A4 '\[sharedMem\]' $BB/examples/chips/goban/configs/designs/tiles/default.toml + +# 某 chip 全部 tile 的 sharedMem 开关一目表(文件多时的最简筛选) +grep -l 'sharedMem' $BB/examples/chips/*/configs/designs/tiles/*.toml + +# 上游 physical-bank 分配只判槽位维的实物(连续空位搜索) +grep -n 'tryAlloc\|need' $BB/compiler/src/Conversion/LowerBuckyball/PhysicalBankState.cpp | head +``` diff --git a/knowledge/chip/chip-toml-schema.md b/knowledge/chip/chip-toml-schema.md new file mode 100644 index 0000000..87fb332 --- /dev/null +++ b/knowledge/chip/chip-toml-schema.md @@ -0,0 +1,59 @@ +--- +stage: chip +tags: [schema, chip.toml, design, tile, core-config, balldomain] +updated: 2026-09-08 +--- + +# chip 配置 TOML schema + +## 这是什么 + +新 chip 的配置面由五类 TOML 组成:chip 清单(chip.toml)、design 文件、tile 文件、 +core 聚合配置(default.toml)与 balldomain 注册表。它们按 include 链串起来,是 +bbdev config 管线与 chip 构建的输入。本文记录每类的必要键与行规则(不变量), +并给出活仓库里可作为范例的文件位置(现查配方)。 + +## 不变量 / 契约 + +- chip.toml:`[designs] include` 必填,值是相对 `configs/` 的设计文件(如 + `designs/toy.toml`);`[sims]` 表必填,`verilator` 与 `p2e` 两键必为非空字符串 + (值 = Scala 配置类名)——config 管线按键名读取。 +- design 文件:`[top] nTiles` 必填;`[[tiles]]` 行(tile_id + include)或 + `[tileTemplate]`(include + count)至少其一;`nTiles` 必须等于 `[[tiles]]` 条数 + 或 `[tileTemplate] count` 展开数(管线硬校验)。tile include 相对 design 文件 + 所在目录解析。 +- tile 文件:`[[cores]]`(core_id + include)或 `[coreTemplate]`(include + count) + 至少其一;core include 相对 tile 文件目录解析,解析后必须落在 + `examples/cores//configs/` 下;`[sharedMem]` 若写则 `enable` 为布尔、 + `entries` 为正整数;`[privateDCache]` 同理可选。 +- core 聚合配置 `examples/cores//configs/default.toml`:五域键 + `balldomain`/`memdomain`/`frontend`/`gpdomain`/`core` 各为一条相对 `configs/` + 的路径(纯 Rocket 核心如 rocket 可以都不写;`memdomain` 缺省时管线默认读 + `memdomains/default.toml`,`balldomain` 同理默认 `balldomains/default.toml`)。 +- 注册表 `examples/cores//configs/balldomains/.toml`:`ballNum` 可选; + `ballIdMappings` 行(ballId/ballName/ballClass 必填,可选 config/inBW/outBW) + + `ballISA` 行(mnemonic/funct7 必填,`bid` 必须指向本注册表已注册的 ballId)。 + 空注册表(rocket 类)合法。`configs/balldomains/balls/` 下的 TOML 是 per-ball + 变体配置、不是注册表,不列举。 +- Scala 侧:`CustomConfigs.scala` 的 `BuckyballConfig` 需接 + `WithBuckyballTiles("<本 chip 的 configs/generated/chip.pb">)`——chip.pb 是 + `bbdev config --install` 的生成产物、不是手写文件;仿真配置类名 + `BuckyballVerilatorConfig` / `P2EConfig` 跨全部 chip 全局唯一。 + +## 活仓库现查 + +```bash +# chip 清单与 design 头 +sed -n '1,15p' $BB/examples/chips/toy/configs/chip.toml +sed -n '1,12p' $BB/examples/chips/toy/configs/designs/toy.toml +# tile 文件全貌([sharedMem] 与 [[cores]] include 的写法) +sed -n '1,40p' $BB/examples/chips/toy/configs/designs/tiles/default.toml +# 某 chip 的多 tile 拓扑族(全部 tile 文件名) +ls $BB/examples/chips/goban/configs/designs/tiles/ +# 注册表行规则范例(ballIdMappings / ballISA 的实际写法) +sed -n '1,30p' $BB/examples/cores/toy/configs/balldomains/default.toml +# 某 core 的聚合配置五域引用 +sed -n '1,20p' $BB/examples/cores/pebble/configs/default.toml +# 某 chip 的 CustomConfigs.scala(WithBuckyballTiles 写法) +sed -n '1,30p' $BB/examples/chips/toy/arch/src/main/scala/CustomConfigs.scala +``` diff --git a/knowledge/chip/funct7-reserved.md b/knowledge/chip/funct7-reserved.md new file mode 100644 index 0000000..8fe5fda --- /dev/null +++ b/knowledge/chip/funct7-reserved.md @@ -0,0 +1,12 @@ +--- +stage: chip +tags: [funct7, isa, ball-registry, reserved] +updated: 2026-09-08 +--- + +# funct7 保留值契约 + +事实源在 ball 侧:见 `../ball/funct7-encoding.md`(两层禁区结构、出处与现查配方都在那里,不双写)。 + +chip 侧只补一条工具边界:`buckyball_core_ball_index` 的 `funct7Duplicates` 只查所选 core +注册表内的同域重复,不覆盖基础 ISA 表与框架自留值——撞后两层的球注册不炸、取证时炸。 diff --git a/knowledge/chip/mlirtest-wiring.md b/knowledge/chip/mlirtest-wiring.md new file mode 100644 index 0000000..4cebe89 --- /dev/null +++ b/knowledge/chip/mlirtest-wiring.md @@ -0,0 +1,58 @@ +--- +stage: chip +tags: [mlirtest, cmake, wiring, mlir_tests] +updated: 2026-09-08 +--- + +# MLIRTest 接线事实 + +## 这是什么 + +MLIR 验证面分两处,接线方式不同:**ball 侧** +`examples/balls//workloads/mlir_tests/` 由 +`buckyball_add_ball_workload_subdirs(mlir_tests)` 织入(registry 加球 = 自动进构建); +**chip 侧** `examples/chips//workloads/mlir_tests/` 由该目录 CMakeLists 自己的 +`add_subdirectory` 链接入。两处都靠 `add_buckyball_mlir_test( TARGET )` +宏产二进制;chip 侧还可能有本地 bespoke 生成器(`function(...)` 内在 +`BAREMETAL_BIN` 行把名字写死)。 + +## 不变量 / 契约 + +- 标准宏命名:`${BUCKYBALL_WORKLOAD_CHIP}-${ARG_TARGET}-mlirtest-${TEST_ID}-baremetal` + (`TEST_ID` = 源文件名前接 `BUCKYBALL_MLIR_TEST_PREFIX`;linux 后缀同款)。宏要求 + `BUCKYBALL_MLIR_TEST_PREFIX` 已 set、`BUCKYBALL_WORKLOAD_CHIP` 非空,缺一即构建期 + FATAL_ERROR。 +- chip 侧只判 **`add_subdirectory` 链真正接入**的组目录:链外的组目录的二进制根本 + 不构建,不存在「该列未列」的问题;既不判死也不判 fail。 +- 本地 bespoke 生成器:stem 由函数体自己写死,`BUCKYBALL_MLIR_TEST_PREFIX` **不再 + 叠加**——叠加会造出实物不存在的名字。 +- 结果面:清单该列未列 = 该 stem 构建出来但没人仿真(漏跑);组目录里没有任何生成器 + 调用点名的 `.mlir` = 根本不构建(死源,不是验证面);有调用但 stem 推不出来的 + (TARGET 是 `${VAR}` 插值、foreach 生成、本地函数体认不出)单独告警,不判死。 +- stem 推导的完整方法论(含逐条 grep 步骤)在 skill `chip-design-guide`; + 本文只记接线事实与位置。 + +## 活仓库现查 + +```bash +# chip 侧接入链(顶层的 add_subdirectory 连到哪些组) +grep -n 'add_subdirectory' $BB/examples/chips/toy/workloads/mlir_tests/CMakeLists.txt + +# chip 侧所有 .mlir 源(按组目录分) +find $BB/examples/chips/toy/workloads/mlir_tests -name '*.mlir' | sort + +# 标准宏定义(命名 + 前置要求) +sed -n '16,55p' $BB/bb-tests/workloads/src/MLIRTest/CMakeLists.txt + +# chip 侧宏调用与 BUCKYBALL_MLIR_TEST_PREFIX 声明的实际形态(标准派,pebble) +grep -rn 'BUCKYBALL_MLIR_TEST_PREFIX\|add_buckyball_mlir_test' $BB/examples/chips/pebble/workloads/mlir_tests --include=CMakeLists.txt | head + +# chip 侧 bespoke 生成器的实际形态(toy:function + 行首调用) +grep -rn 'function(add_\|add_linalg_conv2d_test' $BB/examples/chips/toy/workloads/mlir_tests --include=CMakeLists.txt | head + +# ball 侧 mlir_tests(某个 ball 的验证面) +find $BB/examples/balls -path '*/workloads/mlir_tests/*.mlir' | head + +# registry 挂 ball → mlir_tests 织入的宏(定义与调用点都在 CMakeLists.txt,不在 *.cmake) +grep -rn 'buckyball_add_ball_workload_subdirs' $BB/bb-tests/workloads --include=CMakeLists.txt --include='*.cmake' | grep -v '/build/' | head +``` diff --git a/knowledge/chip/model-binding.md b/knowledge/chip/model-binding.md new file mode 100644 index 0000000..9a636b9 --- /dev/null +++ b/knowledge/chip/model-binding.md @@ -0,0 +1,58 @@ +--- +stage: chip +tags: [model-binding, MODEL_LAYOUT, _MODELS, archs, layout] +updated: 2026-09-08 +--- + +# 模型绑定四处写集(活仓库现状) + +## 这是什么 + +bind 轮的写集横跨 bbdev 与 e2e 两个子仓 + 父仓一个普通文件,共四处。判据只认 +「检出树实物」:`chips_for_model()` 扫描 `archs/buckyball///` +目录决定 (chip, model) 是否合法,**除此之外没有任何自动发现**——四处写集少一处 +即红。本文记录四处的位置、键名约定与现查配方。 + +## 不变量 / 契约 + +- ① bbdev `api/steps/workload/01_build_event.step.py` 的 `MODEL_LAYOUT` dict: + 模型键 → layout 目录名。只认 `MODEL_LAYOUT` 一处(`MODEL_TARGETS` / + `MODEL_CMAKE` 已不存在);回归评估侧(`api/steps/regression/scripts/model_layout.py`) + 从这里动态 import 同一份表,单一事实源,不存在两份字面量漂移的面 + (workload 侧才是 `workload --build` 的闸门)。 +- ② e2e 子仓 `models/archs/buckyball///` 目录:键与 ① 的 layout + 名对应;白名单内 chip 参照 pebble 同名 layout,白名单外参照 poly(Gemma4/Qwen3) + 形态。 +- ③ e2e 子仓 `models/archs/buckyball/CMakeLists.txt` 三处条目(按 layout 名大写): + `set(BUCKYBALL__DIR …)`、`BUCKYBALL_ALL_MODELS` 白名单项、`if(MODEL_ …)` + wiring block。白名单缺项 = 传 `-DMODEL_=ON` 直接 FATAL_ERROR;wiring 缺项 = + layout 不被 add_subdirectory,ninja run 目标不存在。 +- ④ 父仓 `bb-tests/workloads/scripts/build.py` 的 `_MODELS` dict:模型键 → + `(cmake -D 值, ninja run 目标)`。它是父仓跟踪的**普通文件**,不随 gitlink 走; + 缺条目 = workload 步骤 raise unknown workload model。 +- bind 轮 `--model <模型键>` 声明行:整行一条、一个模型一行,键 = ①/④ 里的键名; + `[binding]` 只认这种行,命令序列里带的 `--model` 不算声明。 +- 哪些 chip 在**白名单内**(现有 layout 目录的芯片,含绑定向 `chips_for_model` + 可解析的集合)——以活仓库 layout 目录清单为准,见下方配方;**toy / multi-rocket + 零 layout**(给它们做首次绑定 = 上游未覆盖路径,要先过 archs CMakeLists 的两道闸)。 + +## 活仓库现查 + +```bash +# ① MODEL_LAYOUT 当前键值(bbdev 子仓;缺子仓时该路径不存在) +sed -n '35,52p' $BB/bbdev/api/steps/workload/01_build_event.step.py + +# ② 全部 (chip, layout) 目录现状(谁有 layout、toy 有没有) +find $BB/bb-tests/workloads/src/ModelTest/e2e/models/archs/buckyball \ + -mindepth 2 -maxdepth 2 -type d | sort + +# ③ archs CMakeLists 的白名单与 wiring 形态 +grep -n 'BUCKYBALL_ALL_MODELS\|if(MODEL_' \ + $BB/bb-tests/workloads/src/ModelTest/e2e/models/archs/buckyball/CMakeLists.txt | head + +# ④ 父仓 _MODELS 当前键值 +sed -n '11,30p' $BB/bb-tests/workloads/scripts/build.py + +# 回归侧的 MODEL_LAYOUT 是 import 来的(验证单源形态,应显示 import 而非字面量表) +grep -n 'MODEL_LAYOUT' $BB/bbdev/api/steps/regression/scripts/model_layout.py | head +``` diff --git a/knowledge/chip/regression-manifest.md b/knowledge/chip/regression-manifest.md new file mode 100644 index 0000000..6816334 --- /dev/null +++ b/knowledge/chip/regression-manifest.md @@ -0,0 +1,50 @@ +--- +stage: chip +tags: [regression, batch, manifest, stem, exclude] +updated: 2026-09-08 +--- + +# regression batch 清单(stem 命名规则见 ../ball/regression-tables.md) + +## 这是什么 + +chip 的回归验证面由 `regression/batch//workloads-.toml` 清单驱动: +`[workloads] search_path` 指定二进制相对根,`tests` 数组列出实际会仿真的 stem +列表。lane = bemu / verilator / p2e,variant = elf / pk(另见 `-rushB`、 +`-diff` 等,是否造由 chip 特性决定)。**chip 根本没有 `regression/` 目录 = 上游 +没注册这条 lane**——这是「未注册」与「注册了但漏跑」的分界,两侧不能混为一谈。 + +## 不变量 / 契约 + +- ctest / mlirtest 的 stem 命名规则(含 `` = `_target_name(core)` 推导、 + 产物后缀约定)见 [../ball/regression-tables.md](../ball/regression-tables.md) + ——单一事实源在那里,本文件不复制。 +- 清单里列了但 CMake 没有 = 陈旧;CMake 有但清单没有 = 漏跑(该 stem 构建出来但 + 没人仿真)。两条方向都要人工核对。 +- `exclude:` 行只出现在 **PR 证据清单**里(`exclude: — <理由>`,理由非空才 + 接受),batch TOML 本身不含排除语义——批清单不跑的做法是「不列进 tests」。 +- 现有 chip 的常驻排除(如某些 bank matadd / conv2d stem 带家族裁决理由)随 PR + 证据清单走,不在树里;要引用它们就用检索配方找当时该 chip 清单与 manifest。 + +## 活仓库现查 + +```bash +# 某 chip 全部 lane × variant 清单文件 +find $BB/examples/chips/toy/regression/batch -name 'workloads-*.toml' | sort + +# 全部 chip 的 regression 目录存在性(缺目录 = 该 lane 未注册) +find $BB/examples/chips -maxdepth 2 -name regression -type d + +# 某清单的 search_path 与 ctest stem 样例 +sed -n '1,20p' $BB/examples/chips/pebble/regression/batch/bemu/workloads-elf.toml + +# 某清单里 mlirtest 条目(空则 = 该 chip 清单一侧 mlirtest 零登记) +grep 'mlirtest' $BB/examples/chips/pebble/regression/batch/bemu/workloads-elf.toml | head + +# stem 命名规则的实物出处(CMake 宏怎么拼名字) +grep -n 'BUCKYBALL_WORKLOAD_CHIP}\|mlirtest' $BB/bb-tests/workloads/src/MLIRTest/CMakeLists.txt | head + +# ctest stem 出处(add_buckyball_ctests 宏与 BUCKYBALL_CTEST_TARGET 的约定) +sed -n '40,90p' $BB/bb-tests/workloads/src/CTest/CMakeLists.txt +grep -n 'BUCKYBALL_CTEST_TARGET' $BB/examples/chips/toy/workloads/CMakeLists.txt +``` diff --git a/knowledge/chip/verification-trace.md b/knowledge/chip/verification-trace.md new file mode 100644 index 0000000..e8a5fa8 --- /dev/null +++ b/knowledge/chip/verification-trace.md @@ -0,0 +1,41 @@ +--- +stage: chip +tags: [verification, trace, ndjson, log] +updated: 2026-09-08 +--- + +# 验证产物与 trace 格式 + +## 这是什么 + +CI 验证会话(verify-runner)执行 bbdev 命令后的产物落在 +`${repoPath}/log/<时间戳>-*-bemu-*/bdb.ndjson`——bemu 运行目录的逐事件 trace, +NDJSON 一行一个 JSON 对象。报告回贴里的分析摘要(probe analysis、pmc-evidence) +是它的加工产物;原始 trace 是定位修改点的据实出处。 + +## 不变量 / 契约 + +- 目录命名 = `<时间戳>---bemu-` 一类形态(同一次的 + verilator 运行另带 `-verilator-` 段);`log/` 下按运行目录分。 +- 行格式:每一行是一个完整 JSON 对象,带 `"type"` 字段,如 + `{"type":"itrace",…}` / `{"type":"mtrace",…}` / `{"type":"pmctrace",…}`; + **没有** `[ITRACE]` / `[MTRACE]` 这类标记行——不要把行尾字符串当字段。 +- trace 可能为空文件(0 字节 = 零事件流):读之前先看文件大小,空文件不是格式问题, + 是「该跑什么都没跑」的证据。 +- `span_cycles`(bemu 侧)是 ball 自身 `latency` 的累加和——拿 `latency` 与它 + 对账是恒等式,不能当成一项检验;独立测量 `latency` 的只有 `--pmctrace` 的 + elapsed(回贴的 `pmc-evidence` 行)。 + +## 活仓库现查 + +```bash +# 最新一条 bemu 运行目录与 trace 文件 +find $BB/log -maxdepth 1 -type d -name '*-bemu-*' | sort | tail -3 + +# 挑第一个非空 trace 看行形态(每行一个 JSON 事件对象) +f=$(find $BB/log -name bdb.ndjson -size +0c | head -1); head -c 400 "$f" + +# trace 的事件类型名单(哪些 "type" 出现过) +f=$(find $BB/log -name bdb.ndjson -size +0c | head -1) +grep -o '"type":"[a-z]*"' "$f" | sort | uniq -c +``` diff --git a/knowledge/shared/model-to-ball-pipeline.md b/knowledge/shared/model-to-ball-pipeline.md new file mode 100644 index 0000000..133829d --- /dev/null +++ b/knowledge/shared/model-to-ball-pipeline.md @@ -0,0 +1,111 @@ +--- +stage: shared +tags: [model-to-ball, pattern-chain, linalg-to-tile, tile-hook, bank-ssa, bind] +updated: 2026-09-09 +--- + +# 模型算子落到 ball 的四关 pattern 链 + +## 这是什么 + +「派生一个 ball」和「模型管线会把算子降到这个 ball 上」是两件事。模型图里的算子要 +真正落到 ball,需要一条四关 pattern 链全部在位,缺一关模型路径就不可达。这篇讲链 +的四个环节、ball 交付与模型落 ball 的边界,以及怎么在活树上逐关核实。结论来自 +phase9 SiLU 根源调研(rollout-evidence/phase9/silu-root-cause.md),那里对 SmolLM +实测过:管线为 silu 站点生成的 ball op 数是 0,断点在第一关「图侧识别」。 + +## 不变量 / 契约 + +**四关链(缺一关,模型路径不可达):** + +1. 图侧识别:`-convert-linalg-to-tile` 里注册了认出该算子的 pattern(写死的注册 + 清单,模板先例是 `ReluGenericLowering` 认 `max(x,0)` 形态的 linalg.generic)。 +2. Tile 方言有对应 op:`Tile.td` 里有 `tile_<算子>`。 +3. tile→ball lowering:ball 侧有 `LowerTileToBuckyball/*.cpp`(hook 生成器扫到该 + 目录就自动发 TILE_HOOK,无需手改注册表),core 侧 pass 里 populate 了对应 + pattern。 +4. bank-SSA 分片发射器:core 侧 `LowerBuckyball/` 下有把整站点 memref 按 ball + 契约切成调用序列的 `*ToBankSSAPatterns.cpp`,并在 core 的 populate 里注册。 + +**ball 交付 ≠ 模型落 ball。** ball 的交付终点 = 双 phase(c-bemu / rtl)+ +MLIRTest。MLIRTest 的 bank/ball 两层 `.mlir` 是手写调用形状,消费 ball 不需要 +pattern 链。模型落不落 ball 取决于上面四关,四关都在编译器侧(buddy-mlir midend +与 core compiler),在 ball 写集之外。ball 实现者不负责、也不应承诺模型路径。 +链不存在时 ball 照常交付,但 bind 轮的预期必须如实写「模型路径不可达(缺 +pattern 链)」,不能写成「模型将落到 ball」。 + +**「6144」是 bank 行数,不是代码行数。** 站点几何的换算:1×16×1536 fp32 = +24,576 元素,bank 行 = 16 B = 4 个 fp32 lane,24,576 ÷ 4 = 6,144 个 bank 行/站 +点。ball 契约 n ≤ 256(单 group = 64 行 × 4 lane),一个站点 = 96 次调用。没有 +任何地方会生成 6144 行代码;链补齐后一个站点产生的是约 96 ×(mvin + ball + +mvout)的 op 序列。 + +**分片发射机制已实证存在,爆炸不来自机制本身。** transpose 的分片发射器按编译期 +行列双循环把站点切块、每块发一组 mvin/transpose/mvout,机制是通的。phase8/phase9 +实测的百万行爆炸来自两点:transpose 站点拖动的数据量(百万级 host 常驻元素过 +24 KiB bank 池),以及非连续访存要求的逐元素 gather/scatter 打包循环。连续 +dense 逐元素算子(silu 类)两点都不沾:stride=1 直接 mvin/mvout,只搬激活张量。 + +**现状基线(用配方现查,别背):** 四关全通的只有 matmul / transpose / smatmul / +quant / conv 这条老链上的几家;relu 处于中间态——有识别 pattern 和 tile op, +tile→ball 没接线;silu / gelu / layernorm 的链不存在。GELU 比 SiLU 复杂、同样卡 +在第一关——落不落 ball 不取决于算子数学复杂度,只取决于有没有人按算子手写这条 +链。 + +## 活仓库现查 + +第一关:图侧识别 pattern 的注册清单(清单里没有该算子 = 链断在第一关)。 + +``` +sed -n '/populateLowerLinalgToTileConversionPatterns/,/^}/p' \ + $BB/compiler/thirdparty/buddy-mlir/midend/lib/Conversion/LowerLinalgToTile/LowerLinalgToTile.cpp +``` + +第二关:Tile 方言 op 全清单。 + +``` +grep -nE '^def [A-Za-z0-9_]+Op' \ + $BB/compiler/thirdparty/buddy-mlir/midend/include/Dialect/Tile/Tile.td +``` + +第二关快捷判据:查某个算子有没有 tile op(无输出 = 没有)。 + +``` +grep -in '<算子名>' \ + $BB/compiler/thirdparty/buddy-mlir/midend/include/Dialect/Tile/Tile.td +``` + +第三关:hook 注册表里的 TILE_HOOK 清单(生成物,构建过 pebble 才存在)。 + +``` +grep -nE 'BUCKYBALL_(TILE|BANK_SSA)_HOOK' \ + $BB/compiler/thirdparty/buddy-mlir/build/pebble/external_dialects/BuckyballBallLoweringHooks.inc +``` + +第三关源侧等价判据(构建树不在时用):ball 有没有 tile→ball lowering 源文件 +(无输出 = 没有)。 + +``` +find $BB/examples/balls//compiler -path '*LowerTileToBuckyball*' -name '*.cpp' +``` + +第四关:分片发射器枚举(清单里没有该算子的对应物 = 链断在第四关)。 + +``` +find $BB/examples/cores/pebble/compiler/src/Conversion/LowerBuckyball \ + -name '*ToBankSSAPatterns.cpp' -printf '%f\n' +``` + +第四关注册核对:core 的 populate 函数里注册了哪几家。 + +``` +grep -n 'populate.*ToBankSSAPatterns' \ + $BB/examples/cores/pebble/compiler/src/Conversion/LowerBuckyball/CoreBankSSALowering.cpp +``` + +分片发射先例实物(「一站点多调用」的模板,编译期双循环 + 每块一组 mvin/op/mvout): + +``` +sed -n '216,255p' \ + $BB/examples/cores/pebble/compiler/src/Conversion/LowerBuckyball/MemTransposeToBankSSAPatterns.cpp +``` diff --git a/knowledge/verify/checkyaml-structure.md b/knowledge/verify/checkyaml-structure.md new file mode 100644 index 0000000..b20bd4a --- /dev/null +++ b/knowledge/verify/checkyaml-structure.md @@ -0,0 +1,53 @@ +--- +stage: verify +tags: [buckyball, check.yaml, ci, 检索配方] +updated: 2026-09-08 +--- + +# check.yaml 的 job/stage 结构(现查配方) + +## 这是什么 + +buckyball 上游 CI 主工作流 `.github/workflows/check.yaml`($BB 活树)的结构速览与现查配方。 +verify-runner 的命令序列以其中的 chip-check job 为参照(见 plan-mapping.md),prompt/skill 里 +引用 check.yaml 时只准用文件名/job 名这类稳定锚点,行号与 pin 一律现查。 + +## 结构不变量(稳定事实) + +- 触发器:push/pull_request 到 main;权限 contents: read + checks: write;concurrency 组 + `buckyball-ci-check`。 +- job:`pre-commit`(runs-on: check)与 `chip-check`(矩阵 job,name = `${{ matrix.chip }}`, + needs: pre-commit,runs-on: check)。 +- chip-check 用 `strategy.matrix.include` 展开 5 个 chip(toy / pebble / goban / poly / + multi-rocket),每个条目带 4 个布尔开关:`enable_rushb`、`run_bemu_elf_tests`、 + `run_bemu_pk_tests`、`run_verilator_batch_tests`。 +- 各泳道步骤(非 rushB): + - Build compiler and workloads:`bbdev config --install` → `compiler --build` → + `workload --clean` → `workload --build`(都是 `'--chip ${{ matrix.chip }}'`)。 + - bemu ELF batch / bemu PK batch:各由对应 `run_*` 开关门控, + `bebop-bemu --batch '--chip … --test elf|pk-tests --clean-before'`。 + - verilator batch:由 `run_verilator_batch_tests` 门控,clean → verilog → build(`--jobs 16`)→ + batch elf-tests。 + - rushB batch:四开关全真才跑,且只在此段出现 verilator pk-tests。 +- 每个步骤都过 `ci_repo_lock.sh enter` 的仓库锁;junit 检测步骤的 glob 是 + `bebop/target/${{ matrix.chip }}/nextest/junit-bbdev-*.xml`。 + +## 活仓库现查 + +```sh +# chip-check job 全貌(矩阵 + 步骤) +sed -n '/^ chip-check:/,$p' $BB/.github/workflows/check.yaml + +# 某 chip 的矩阵开关(上例第一个条目) +sed -n '/chip-check:/,/^ env:/p' $BB/.github/workflows/check.yaml + +# verilator pk-tests 只出现在 rushB 段的证据 +grep -n "pk-tests" $BB/.github/workflows/check.yaml + +# 仓库锁脚本的实际调用 +grep -n "ci_repo_lock" $BB/.github/workflows/check.yaml +``` + +注:清单里「toy/pebble enable_rushb=true、goban/poly 全关、multi-rocket 只开 +run_verilator_batch_tests」这类具体值属于上游数据,会随上游变更,需要时用上面的配方现查, +不要当作不变量写进文档。 diff --git a/knowledge/verify/ci-workflow.md b/knowledge/verify/ci-workflow.md new file mode 100644 index 0000000..eb0d87b --- /dev/null +++ b/knowledge/verify/ci-workflow.md @@ -0,0 +1,84 @@ +--- +stage: verify +tags: [buckyball, ci, bb-verify, verdict-gate, INFRA, 检索配方] +updated: 2026-09-08 +--- + +# bb-verify.yml 机制说明(verdict-gate / 评论在场 / 只读门禁 / provision 豁免 / INFRA 回流) + +## 这是什么 + +CI 工作流 `packages/verify-runner/ci/bb-verify.yml`(fork/本机部署物料)的五段机制说明。每段:干什么、不变量、 +现查配方。配置模板见 `packages/verify-runner/ci/settings.ci.yaml`,机器接线见 +`packages/verify-runner/ci/runner-setup.md`(以上 `ci/` 物料均在 harness 仓的 `packages/verify-runner/` 下,非仓根)。 + +## verdict-gate(Run verify-runner 步骤内) + +- 流程:headless 会话跑完 → 从会话 stdout 首行解析 `^VERDICT: (PASS|FAIL)` → PASS 且会话 + exit 0 = 绿;FAIL = 红;解析不到 → 回退查本轮时间窗内 PR comments∪reviews 的首行, + 再没有 → 红(宁红不假绿)。 +- 不变量:PASS/FAIL 只由最终回答首行 `VERDICT:` 与 PR 评论承载;dsh 进程退出码只反映会话是否 + 正常完成,不作为结论。INFRA 首行不被任何正则当作结论(见下)。 + +```sh +grep -n "VERDICT" $DSH_PLUGIN/packages/verify-runner/ci/bb-verify.yml | head -30 +``` + +## 评论在场门禁(Gate: verdict present on the PR (no fake green)) + +- 干什么:会话绿了还不行——评论/review 两面(comments ∪ reviews)在这一轮时间窗内没有 + `^VERDICT: (PASS|FAIL)` 首行即红。防止「会话说 PASS 但没贴到 PR 上」的假绿。 +- 不变量:PASS 报告可能落在 review 而非 comment(`gh pr view --comments` 看不见 reviews), + 所以以 `--json comments,reviews` 两面为准。 + +```sh +sed -n '/name: "Gate: verdict present on the PR/,/^ - name: "Gate: persistent/p' \ + $DSH_PLUGIN/packages/verify-runner/ci/bb-verify.yml +``` + +## 只读门禁(Snapshot / Gate: persistent root untouched) + +- 干什么:会话开始前对持久化根做 tracked diff 快照,结束后逐字节比较——会话改过任何已跟踪 + 文件即红。落实「全程对 $BB 只读」。 + +```sh +grep -n "tracked\|diff --\|persistent root untouched" $DSH_PLUGIN/packages/verify-runner/ci/bb-verify.yml | head +``` + +## provision 豁免(provision_exempt) + +- 干什么:`compilerTouched=true` 时,若本轮门禁 plan 自己会重跑 compiler build,Provision 步把 + compiler 构建失败从「基建红」降级为「交门禁轮裁决」(set +e 捕获 rc + 日志注记),防止 + 「Provision 先红 → INFRA → 重发复现」的死循环;编译器写集不豁免(plan 不含 compiler build + 的那一支),宁红不假绿。 +- 判定处唯一:豁免组合表在 Deterministic verdict inputs 步,是 + `src/tools/bbdev-plan.ts` 的 `compilerPrerequisite()` 调用点的**镜像**——唯一事实源是 plan, + 镜像侧注释已指名;plan 增删前置组合必须同步本表。 +- 连带:豁免生效且编译器确实失败时,workload clean/build 同因跳过(same-flag-skip),避免把 + 门禁轮的裁决面预演成 Provision 红。 + +```sh +grep -n "provision_exempt\|compilerPrerequisite\|same-flag-skip" $DSH_PLUGIN/packages/verify-runner/ci/bb-verify.yml | head -20 +``` + +## INFRA 回流(Report failure to the PR + hosted report job) + +- 干什么:verify 作业内 4 步(Prepare / Deterministic verdict inputs / Provision / Stage + dsh-plugin)各自 tee 到 `$RUNNER_TEMP/steplogs/.log`;末尾回流步在 + `if: failure() && continue-on-error` 下,当本轮时间窗内**没有**真实结论 + (`^VERDICT: (PASS|FAIL)`)时,剥 ANSI 取首条真错误行 + 失败步骤名,贴首行 + `VERDICT: INFRA` 的评论(隐藏 marker 只含 `run=`,同 run 重入走 PATCH 幂等)。 +- 排它性:INFRA 只在基础设施失败时贴,不判 PR 内容;verdict-gate / 回退查询 / 评论在场门禁三处 + 正则只认 PASS|FAIL,`VERDICT: INFRA` 不被任何门禁当作结论——消费方见 INFRA 应重发 dispatch。 +- 至多一条:去重键 = run_id;机内回流步是权威归因人(拿到真错误行必覆盖既有条目),hosted + report 作业(ubuntu-latest,needs: verify,if: always())只在机内没贴上时独立贴,且「绝不把 + 已锚定的真错误行降级成占位串」两条写路径共用。 +- watchdog 侧不对称:`scripts/bb-verify-watchdog.sh` 的「completed 无结论」判据认 + PASS|FAIL|INFRA(INFRA 也算留痕),与 workflow 侧刻意不同,两侧正则不得向对方看齐。 + +```sh +sed -n '/name: Report failure to the PR/,/^ report:/p' $DSH_PLUGIN/packages/verify-runner/ci/bb-verify.yml +grep -n "completed\|INFRA" $DSH_PLUGIN/packages/verify-runner/scripts/bb-verify-watchdog.sh | head -12 +``` + +注:`$DSH_PLUGIN` = dsh-plugin 仓根(/home/ROXY/code/bb_work/dsh-plugin,工作区语境下直接可用)。 diff --git a/knowledge/verify/contract-clauses.md b/knowledge/verify/contract-clauses.md new file mode 100644 index 0000000..16648f0 --- /dev/null +++ b/knowledge/verify/contract-clauses.md @@ -0,0 +1,46 @@ +--- +stage: verify +tags: [buckyball, 契约, 分阶段验证, 分阶段交付] +updated: 2026-09-08 +--- + +# 契约条款清单的家(文档指针) + +## 这是什么 + +verify-runner 的判定块消费条目、阶段/相位白名单、判据口径的**规范文本**住在哪份文档里。 +本文件只当指针和索引用,不复制条款原文——条款的家是 docs/ 下的契约文档与代码本体 +(判定五脚本 + prompt.ts),任何一处改动以那份规范文本为准。 + +## 家在哪(稳定锚点) + +| 主题 | 规范文本位置 | +|---|---| +| 分阶段验证(CI 判定块与命令序列、§2.1 阶段识别 / §2.3 分层门禁、INFRA 语义、lane 登记表、单作业理由) | `dsh-plugin/docs/verify-runner-staged-verification.md` | +| 分阶段交付(写作/交付纪律、逐条机检口径) | `dsh-plugin/docs/phased-delivery.md` | +| 判定块消费条目(编号与上表 §2.1 对应) | `packages/verify-runner/src/prompt.ts`「CI 判定块消费(硬约束)」 | +| 相位白名单 / 声明行形态(`probe:`/`perf:`/`ball-expect`/`--model` 的语法门) | `packages/verify-runner/scripts/validate-manifest.mjs` 与 `manifest.mjs` | +| 绑定三源 ground truth 与豁免/覆盖判据 | `packages/verify-runner/scripts/binding-check.mjs` | +| stage 推断(ball 接线 carve-out、compilerTouched) | `packages/verify-runner/scripts/infer-stage.mjs` | +| 上轮 probe 取证检索(perf-gate 判据) | `packages/verify-runner/scripts/probe-loop-check.mjs` | + +## 不变量(稳定事实) + +- 判定块消费条目与《分阶段验证》《分阶段交付》同编号条目一一对应;prompt 是机检口径的常驻侧, + 契约文档是规范侧,两边同步改。 +- 条款计数类叙述(如「共 N 条」)是散文,不当作数字断言;要数条款就看文档标题结构 + (看 `grep -n "^### \|^## " docs/verify-runner-staged-verification.md`),不靠某次读数。 +- 家族条款(性能优化三轮段)在四个插件各有措辞差异,属有意为之:verify 侧按应当项表述, + coding 侧按自查闸门表述;不要统一措辞(见 prompt.ts probe 轮小节的迭代契约条)。 + +## 活仓库现查 + +```sh +# 两份契约文档的章节结构 +grep -n "^## \|^### " $DSH_PLUGIN/docs/verify-runner-staged-verification.md $DSH_PLUGIN/docs/phased-delivery.md + +# 判定脚本的判据条款(各脚本头注即判据清单) +sed -n '1,60p' $DSH_PLUGIN/packages/verify-runner/scripts/binding-check.mjs +``` + +注:$DSH_PLUGIN = dsh-plugin 仓根(/home/ROXY/code/bb_work/dsh-plugin,工作区语境下直接可用)。 diff --git a/knowledge/verify/plan-mapping.md b/knowledge/verify/plan-mapping.md new file mode 100644 index 0000000..f701cec --- /dev/null +++ b/knowledge/verify/plan-mapping.md @@ -0,0 +1,65 @@ +--- +stage: verify +tags: [buckyball, bbdev-plan, check.yaml, 检索配方, 决策日志] +updated: 2026-09-08 +--- + +# bbdev-plan 命令映射与 check.yaml 的对照(检索配方 + 决策记录) + +## 这是什么 + +`buckyball_bbdev_plan` 生成的命令序列与上游 `.github/workflows/check.yaml` 的 chip-check job +之间的对应关系,以及「如何核对这一映射」的检索配方。 + +## 决策记录(2026-09-08) + +**选择:保留静态映射(不 plan 时现读 check.yaml),只删行号注释与 pin;映射核对以检索配方 +进知识库。** 理由: + +- plan 的 stage×phase×layer 展开(skeleton/slices/integrate/bind、c-bemu/rtl、probe 成对步骤、 + compilerTouched 前置)是分阶段验证契约的构造,不在 check.yaml 里;现读即使可行也只覆盖 + 无 phase 基线一条腿,其余仍硬编码——「换源自动跟随」的收益覆盖不了成本。 +- chip-check 是 GitHub Actions 矩阵 job:YAML 嵌套 + `${{ matrix.* }}` 插值 + `if:` 条件表达式 + (含四开关合取),要现读就得内置一个 workflow-YAML 解释器(新抽象 + 大段脆弱解析),违背 + KISS 与「不堆 helper」。 +- lane 裁剪与 kernel 白名单已经在「从树实读」的路径上:batch 命令按 + `examples/chips//regression/batch//workloads-.toml` 的存在性裁剪, + KERNEL_MODELS 从 `$BB/bbdev` 源码现读(bbdev-plan.ts 的 `readKernelModels`)。这些才是会 + 随上游换源漂移的数据。 +- 原来「机检对齐」的载体(selftest-tools.mjs 对 check.yaml 字面逐字断言、contract-sync-check.mjs) + 已随基线对齐验证清除,映射的对齐语义降级为「契约 + 检索配方核对」,由人/agent 按需核对。 + +## 映射不变量(让核对有对象的稳定侧) + +- 基础链顺序与 chip-check 非 rushB 链一致:config install → compiler build → workload clean → + workload build → bemu elf batch;complete 层再叠加 bemu pk 批与 verilator + clean/verilog/build/elf 批。 +- 永不生成 verilator pk 批:上游非 rushB 链只到 elf-tests,pk-tests 只在 rushB 段,本验证面 + 两层都不进 rushB 空间(范围裁决,不是 lane 状态声明)。 +- batch 泳道按 toml 实物裁剪;跨 chip 串行由 CI 作业级保证(concurrency + flock)。 + +## 活仓库现查(核对配方) + +```sh +# 1) 看 chip-check 的矩阵开关与泳道步骤 +sed -n '/^ chip-check:/,$p' $BB/.github/workflows/check.yaml + +# 2) 看 plan 的生成代码(bbdev-plan.ts 在 dsh-plugin 仓) +grep -n "buildVerificationPlan\|batch(\|compilerPrerequisite\|modelCoverage" \ + $DSH_PLUGIN/packages/verify-runner/src/tools/bbdev-plan.ts + +# 3) 核对某 chip 的 lane toml 实物与 plan 的裁剪口径是否一致 +ls $BB/examples/chips//regression/batch/*/workloads-*.toml + +# 4) 核对 bind 腿的 kernel 白名单入口(plan 实读的文件) +grep -n "KERNEL_MODELS" $BB/bbdev/api/steps/kernel/01_build_event.step.py +``` + +## 已知镜像与遗留 + +- `STAGE_PHASES` / `PROBE_PHASES` 在 `src/tools/bbdev-plan.ts` 与 `scripts/manifest.mjs` 各有一份 + 字面拷贝(plan 是构建产物,不能 import CI 脚本)。原有两道机检门 + (contract-sync-check.mjs、selftest-deterministic.mjs 的代码常量门)已随改造删除,现为文档化 + 镜像:两处常量必须同步改——核对方法 = 逐项对比两处常量字面(或看 selftest 失败时先查这两处)。 +- CI 侧 provision 豁免组合表(ci/bb-verify.yml)是 plan 侧 `compilerPrerequisite()` 调用点的 + 镜像,唯一事实源是 plan;CI 运行时读不了插件代码,所以保留镜像并已注明(见 ci-workflow.md)。 diff --git a/knowledge/workload/build-py-models.md b/knowledge/workload/build-py-models.md new file mode 100644 index 0000000..ce8c445 --- /dev/null +++ b/knowledge/workload/build-py-models.md @@ -0,0 +1,49 @@ +--- +stage: workload +tags: [build.py, _MODELS, bind, recipe] +updated: 2026-09-08 +--- + +# build.py `_MODELS` 登记表现查 + +## 这是什么 + +父仓 `bb-tests/workloads/scripts/build.py` 的开头有一张 `_MODELS` 表:模型键 → +`(cmake 模型名, ninja 可执行 target)`,是 chip 侧模型注册的一源,bind 轮(chip-designer) +才改它。workload 轮对 `build.py` 零 diff。 + +## 不变量 / 契约 + +- `_MODELS: dict[str, tuple[str, str]]`:键为小写模型键,值为 + `(cmake_model, ninja_arg)`,例如 `"bertsmall": ("bertsmall", "buddy-buckyball-bertsmall-run")`。 +- 键名就是 `MODEL_LAYOUT` / `--model <键>` 声明行用的那个键。 +- 这张表属 bind 轮:workload 轮不登记(写进 `_MODELS` 即越界)。 +- 出现 `BUCKYBALL_MODEL` 选项 `string(TOUPPER ...)` 之类的调用点见 `_MODELS` 下方 + (`BUILD_AUTO_DETECT` / `MODEL` 参数),键不对时构建直接报错。 + +## 活仓库现查 + +- 表整体(含当前键数): + + ```bash + grep -n '_MODELS' -A 25 $BB/bb-tests/workloads/scripts/build.py + ``` + +- 某模型键是否已登记、对应 cmake 名与 target: + + ```bash + grep -n '"<模型键>"' $BB/bb-tests/workloads/scripts/build.py + ``` + +- 模型键集合(拿 `--model` 合法取值清单;`_MODELS` 的键后跟 `(`,`_RUSHB` 的键后跟 `{`,按此区分): + + ```bash + grep -n '_MODELS' -A 25 $BB/bb-tests/workloads/scripts/build.py \ + | grep -oE '"[a-z0-9-]+": \(' | tr -d '": (' + ``` + +- 表之外引用 `_MODELS` 的位置(调用语义): + + ```bash + grep -n '_MODELS' $BB/bb-tests/workloads/scripts/build.py + ``` diff --git a/knowledge/workload/gitignore-conventions.md b/knowledge/workload/gitignore-conventions.md new file mode 100644 index 0000000..2f652b2 --- /dev/null +++ b/knowledge/workload/gitignore-conventions.md @@ -0,0 +1,60 @@ +--- +stage: workload +tags: [e2e, gitignore, recipe] +updated: 2026-09-08 +--- + +# e2e 模型树 .gitignore 惯例现查 + +## 这是什么 + +模型目录把 importer 生成物挡在库外靠两层 `.gitignore`: +`models/models/.gitignore`(父级,盖住粗粒度生成物)+ 各模型目录自己的 +`.gitignore`(盖住该模型特有产物)。本文件给现查配方;哪些目录有、各目录 +写了什么都不固定,全部以活树为准。 + +## 不变量 / 契约 + +- importer 生成物(`output/`、`*.payload/`、`*.rax`、`*.pt` / `*.pth` 等)必须被 + ignore;模型目录特有的落盘物(`*.mlir`、`*.data` 等)靠目录自己那份盖。 +- 声明为入库的期望值来源(如 `reference/` 下的参考张量)不得被任何一层 + ignore 规则命中:命中即「以为交了实为未跟踪」。 +- 判定一个具体路径是否被忽略,用 git 自己的语义(`git check-ignore`), + 不要手工复刻匹配规则。 + +## 活仓库现查 + +`$M` = `$BB/bb-tests/workloads/src/ModelTest/e2e/models`。 + +- 哪些模型目录没有自己的 `.gitignore`: + + ```bash + for d in $M/models/*/; do [ -f "$d.gitignore" ] || basename "$d"; done + ``` + +- 父级规则内容: + + ```bash + cat $M/models/.gitignore + ``` + +- 各目录自带的规则汇总(看模型树惯用的模式): + + ```bash + grep -rh '^[^#[:space:]]' $M/models/*/.gitignore | sort | uniq -c | sort -rn | head -20 + ``` + +- 某路径是否被忽略、被哪条规则命中(在 e2e 子仓里跑;e2e 是独立 git 仓库, + `git check-ignore` 读的是它自己的 index/规则): + + ```bash + git -C $M/models check-ignore -v <相对 models/ 的路径> + ``` + + 退出码 0 = 被忽略(`-v` 显示命中规则与文件);非 0 = 未忽略。 + +- 某目录的期望值文件是否会被目录或父级规则吞掉(连同符号链接语义一并交给 git): + + ```bash + git -C $M/models check-ignore -v /<期望值相对路径> + ``` diff --git a/knowledge/workload/model-tree-and-registration.md b/knowledge/workload/model-tree-and-registration.md new file mode 100644 index 0000000..74cfe29 --- /dev/null +++ b/knowledge/workload/model-tree-and-registration.md @@ -0,0 +1,70 @@ +--- +stage: workload +tags: [e2e, models, cmake, registration, recipe] +updated: 2026-09-08 +--- + +# e2e 模型目录结构与注册点现查 + +## 这是什么 + +buckyball 的 ModelTest e2e 把每个模型放在 +`bb-tests/workloads/src/ModelTest/e2e/models/models//` 下,新 workload 必须: +新建该目录 + 在两处 CMake 文件里登记它。本文件给出现查配方,不抄现值 +(目录清单、旗标拼写、注册写法都会随上游变动;「截至某日有 N 个」这类统计 +请一律用配方现查)。 + +## 不变量 / 契约 + +- 模型目录固定挂在 `e2e/models/models/` 下;`e2e/models/` 下还有 `archs/`(chip 绑定,bind 轮才动)。 +- 两处注册点: + 1. `e2e/models/CMakeLists.txt` 的 **MODEL reset 列表**(`foreach(model_flag IN ITEMS ...)` 块,先全部 OFF 再按 `MODEL` 变量逐个 ON)。 + 2. `e2e/models/models/CMakeLists.txt` 的 **`set(MODEL__DIR ...)` + `if(MODEL_)` 守卫包住 `add_subdirectory()`**。 +- 模型旗标不总是裸大写目录名:目录 `MiniMaxH3FL2VA` 的旗标是 `MINIMAX_H3_FL2VA`(`set` 行、reset 列表、守卫三处一致)。判定标志形态请现查,别从目录名推。 +- 模型目录的 `CMakeLists.txt` 不产可执行文件;`*-run` target 在 `archs/` 侧,属 bind 轮。 + +## 活仓库现查 + +`$BB` = buckyball 仓根。一段路径写全: +`$BB/bb-tests/workloads/src/ModelTest/e2e/models`(下文简写 `$M`)。 + +- 现有模型目录清单: + + ```bash + ls $BB/bb-tests/workloads/src/ModelTest/e2e/models/models/ + ``` + +- 每个模型目录的字面形态(看有没有 importer / driver / specs/ / runner 插件): + + ```bash + for d in $BB/bb-tests/workloads/src/ModelTest/e2e/models/models/*/; do + echo "== $(basename "$d"): $(ls "$d" | tr '\n' ' ')" + done + ``` + +- reset 列表当前写法与旗标: + + ```bash + grep -n 'foreach(model_flag IN ITEMS' -A 30 \ + $BB/bb-tests/workloads/src/ModelTest/e2e/models/CMakeLists.txt + ``` + +- `models/models/CMakeLists.txt` 里某模型的登记三行(旗标拼写以现查为准): + + ```bash + grep -nE 'MODEL__DIR|if *\(MODEL_\)|add_subdirectory\(\)' \ + $BB/bb-tests/workloads/src/ModelTest/e2e/models/models/CMakeLists.txt + ``` + +- 全部 `set(MODEL_*_DIR ...)` 行(拿旗标对照表): + + ```bash + grep -n 'set(MODEL_[A-Z0-9_]*_DIR' \ + $BB/bb-tests/workloads/src/ModelTest/e2e/models/models/CMakeLists.txt + ``` + +- 全树 `add_subdirectory` 调用(确认某目录被登记过): + + ```bash + grep -rn 'add_subdirectory(' $BB/bb-tests/workloads/src/ModelTest/e2e/models/models/CMakeLists.txt + ``` diff --git a/review-ball/SKILL.md b/review-ball/SKILL.md new file mode 100644 index 0000000..c669f50 --- /dev/null +++ b/review-ball/SKILL.md @@ -0,0 +1,61 @@ +--- +name: review-ball +description: "Ball-stage pre-PR review checklist. Use when reviewing a ball-round diff (new ball under examples/balls/): ISA header macros, bemu golden model, balldomain TOML registration, MLIR dialect, Scala RTL wrapper, regression lists, funct7/collision knowledge queries." +--- + +# Review: ball stage + +Purpose: catch pre-submission problems in a ball-stage deliverable (`examples/balls//**` plus registration points in the target core's `configs/balldomains/*.toml`). Pure static review: parse the diff, read the PR-head checkout `$BB` read-only. Never build, never simulate, never write. + +Inputs: the git diff, the stage, the PR body when available. Run A→F in order, then the knowledge queries in the last section where a checklist item needs live-repo facts. Items not applicable are marked 未判; a recipe whose repo-side shape has structurally drifted → 需人工确认, not FAIL. + +Reference templates (read as needed): `examples/balls/relu/` (minimal ball: arch + configs + emu + compiler + ctests), `examples/balls/transpose/` (mlir_tests pair), `examples/balls/matadd/` (verify/ option), `examples/balls/gemmini/` (one file, many funct7s — legal precedent). + +## A. C header / ISA macros + +1. **Include order** in `workloads/isa/.h`: `` then `` (template relu.h shape). How: `sed -n '1,20p' $BB/examples/balls//workloads/isa/.h`. Report: FAIL naming a missing or reordered include. +2. **No funct7 numeric literals.** Only `BB_FUNC7()` mnemonic references; reject `#define X_FUNC7 50`, `BB_FUNC7(50)`, `funct7 = 50`, and a numeric last argument in `BUCKYBALL_INSTRUCTION_*` — the `[uUlL]*` suffix class still counts as numeric. How: `grep -nE '[A-Za-z0-9_]*FUNC7[A-Za-z0-9_]*[[:space:]]*(=[[:space:]]*)?(0x[0-9a-fA-F]+|[0-9]+)'` and `grep -nE 'BB_FUNC7[[:space:]]*\([[:space:]]*(0x[0-9a-fA-F]+|[0-9]+)'` and `grep -nE 'funct7[[:space:]]*[:=]'` over the ball's sources. Report: FAIL naming each hit. +3. **Macro body encoding.** `BUCKYBALL_INSTRUCTION_R_R` carries the three argument slots `BB_BANK0(bank_id) | BB_BANK1(group) | BB_ITER(iter)`; the slot constants must exist (see isa.h of `bb-tests/workloads/lib/bbhw/isa/`). How: read the macro body; `grep -n 'define BB_BANK0\|define BB_BANK1\|define BB_ITER' $BB/bb-tests/workloads/lib/bbhw/isa/*.h`. Report: FAIL naming the missing slot. +4. **ctest file size.** Each `workloads/ctests/*.c` is a single file of ≤100 lines (the build-time FATAL mirrors it) and functional code must not be moved into a `.h` to dodge the limit. How: `wc -l` each `.c`; `grep -n 'function' *.h` suspicion check. Report: FAIL naming an over-limit or a dodge. +5. **ctest registration.** Every `.c` is registered via `add_buckyball_ctests` in `workloads/ctests/CMakeLists.txt`. How: compare `ls *.c` against the registration list (`grep -n 'add_buckyball_ctests'`). Report: FAIL naming an unregistered test. + +## B. bemu golden model + +6. **`const BALL_CLASS`.** Exists in `emu/src/lib.rs` (or the `_.rs` module) and equals the `ballClass` of the target core's `ballIdMappings` row — string equality, no normalization. How: `grep -rn 'BALL_CLASS' $BB/examples/balls//emu/src/`; `grep -n 'ballClass' $BB/examples/cores//configs/balldomains/*.toml`. Report: FAIL on mismatch. +7. **`execute_known` / `cycles_after_issue` signatures.** Return `Option` — `None` means "not this instruction". How: `grep -nE 'fn (execute_known|cycles_after_issue)' $BB/examples/balls//emu/src/**/*.rs`. Report: FAIL on a non-Option signature. +8. **Instruction file referenced.** Each `emu/src/_.rs` is referenced from `lib.rs` via `#[path = "..."]`. How: `grep -n '#\[path' $BB/examples/balls//emu/src/lib.rs`; a shipped `NN_*.rs` without a reference → warn (dead file). Report: warn naming the dead file. +9. **No sentinel fallbacks in `exec`.** `.unwrap_or(` / `.unwrap_or_default(` / `Ok(None)` sentinels that swallow "not-a-match" semantics → warn; `unwrap_or_else(|| panic!(...))` is fine. How: `grep -nE 'unwrap_or(\(|_default)|Ok\(None\)' $BB/examples/balls//emu/src/**/*.rs`. Report: warn naming each; a branch that silently defaults a match → FAIL 需人工裁决 checked against 7. + +## C. balldomain TOML registration + +10. **Table arithmetic.** `ballNum` == `ballIdMappings` row count; ballIds consecutive from 0 with no holes; no duplicate `ballId`/`ballName`; no duplicate `funct7`/`mnemonic` within one `ballISA` (per core). How: extract with `grep -nE 'ballNum|ballId[[:space:]]*=|ballName[[:space:]]*=|mnemonic[[:space:]]*=|funct7[[:space:]]*='` and reconcile. Report: FAIL per violated rule. +11. **Cross-references.** Every `ballISA` row's `bid` names a registered `ballId`; every ball has ≥1 ISA row; each `config=` (after relative resolution from the balldomain file) exists; `inBW`/`outBW` positive. How: `grep -nE 'ballId[[:space:]]*=|bid[[:space:]]*=|config[[:space:]]*=|inBW|outBW'`; `test -f "$BB/"`. Report: FAIL naming each broken row. +12. **The one true registry.** This ball's rows must land in the registry file the core's aggregate config points at (`balldomain = "..."` in `examples/cores//configs/default.toml`) — no variant registry is selectable. How: `grep -n 'balldomain' $BB/examples/cores//configs/default.toml`, then confirm the diff touches exactly that registry. Report: FAIL naming a non-selected registry touched. +13. **Both tables present.** `ballIdMappings` and `ballISA` both appear in the file the ball registers into. How: `grep -nE 'ballIdMappings|ballISA'`. Report: FAIL naming the missing table. + +## D. MLIR dialect / pass + +14. **Dialect shape.** Exactly one `*.td` in `compiler/src/Dialect/Buckyball/`; `Transforms/LegalizeForLLVMExport.cpp` exists (the `_ball_compilers` build-dead-mirror). How: `find $BB/examples/balls//compiler/src/Dialect/Buckyball -type f`. Report: FAIL naming a second `.td` or a missing legalize file. +15. **No `Buckyball_IntrOpBase` inheritance.** The `*.td` must not inherit `Buckyball_IntrOpBase<"">` (it would generate unconditional `llvm::Intrinsic::riscv_bb_` references); the accepted shape is `CustomIntrOp` + `buckyball_target::getBuckyballFunct7("")` (relu/layernorm/int8add/smatmul precedents). How: `grep -n 'Buckyball_IntrOpBase\|CustomIntrOp\|getBuckyballFunct7' $BB/examples/balls//compiler/src/Dialect/Buckyball/**`. Report: FAIL naming the inheritance (they only build when the mnemonic exists in the frozen enum). +16. **MLIR funct7 discipline.** Same no-numeric-literal rule in `.mlir` sources — the `// CHECK` lines of the lit tests are assertions too. How: `grep -nE 'funct7[[:space:]]*[:=][[:space:]]*(0x[0-9a-fA-F]+|[0-9]+)' $BB/examples/balls//compiler/src/Dialect/Buckyball/**/*.mlir`. Report: FAIL naming each. +17. **Single-core wiring.** The ball's legalize sources appear in the core's `Transforms/CMakeLists.txt` list; in `LegalizeForLLVMExport.cpp`, `populateLegalizeForLLVMExportPatterns` and `configureLegalizeForExportTarget` each appear ≥2 times (declaration + call). How: first locate the core compiler tree (`find $BB/examples/cores//compiler -name 'LegalizeForLLVMExport.cpp' -o -name 'CMakeLists.txt'`), then `grep -rn ''` on the resolved paths. Report: FAIL naming the missing declaration/call. + +## E. Scala RTL + +18. **Wrapper class.** A wrapper class carrying all three: `HasBlink` trait, a `ballIdMappings` lookup, and `BlinkIO`. How: `grep -rln 'HasBlink' $BB/examples/balls//arch/src/main/scala/` and check each hit for the lookup and `BlinkIO`. Report: FAIL naming a class missing one. +19. **Package + class identity.** `package` + `class` equals the registered `ballClass` FQCN exactly (BBus reflection constructs via `(GlobalConfig)` — a runtime mismatch, surfaced as a dead ball). How: `grep -rn '^package\|^class' $BB/examples/balls//arch/src/main/scala/*.scala`; compare with `grep -n 'ballClass' $BB/examples/cores//configs/balldomains/*.toml`. Report: FAIL naming the mismatch. +20. **RTL hard-constraint self-check (knowledge, no general machine check).** The wrapper must satisfy the hard constraints: SRAM read = 1 cycle; `cmdReq.fire` latches ALL fields; FSM `idle→read→compute→write→complete→idle` maps to `status.idle/running`; explicit widths with `+&`; same-bank read/write that would corrupt source data must be gated; unconnected ports tied off. How: read the Scala wrapper and each FSM state; mark each sub-check with a verdict line — PASS / FAIL / 未判 (with reason). Report: FAIL naming the violated constraint. + +## F. Regression lists + +21. **ctest stems in both tables.** Each ctest stem appears as `--ctest--baremetal` (elf) and `-linux` (pk), where `` is the compiler target (`core.role` or `core.pkg`). How: `grep -rn 'ctest-' $BB/examples/chips//regression/batch/**/workloads-*.toml` and reconcile with the ball's `workloads/ctests/CMakeLists.txt`. Report: FAIL naming entries missing on either face. +22. **MLIRTest entries.** Each MLIRTest id (`_`) appears as `--mlirtest--baremetal` in the elf table (blocking); no `.mlir` = dead test (FAIL); the mlir_tests trio (`.mlir` + `_main.cpp` + the group's CMakeLists) is complete. How: `find $BB/examples/balls//workloads/mlir_tests -type f`; grep the chip regression lists. Report: FAIL per rule. +23. **Lane placement.** verilator lists only small tests; bank tests run only on bemu (compare with the precedence in existing chips' tables). How: `grep -rn 'bank' $BB/examples/chips//regression/batch/**/*.toml` and check lane placement. Report: warn / 需人工裁决 where the precedent is ambiguous — a lane reassignment must be reasoned, not silent. + +## Knowledge queries (only when an item above needs live facts) + +- **funct7 reserved set** (item 17-style collision checks): derive from the base macro files — `find $BB/bb-tests/workloads/lib/bbhw/isa -name '[0-9][0-9]_*.c' | sort` (the two-digit filename prefix is the funct7) — plus their `*_FUNC7` defines, `InitFunct` in `arch/src/main/scala/framework/balldomain/isa/BallISA.scala`, and the ISA table in `bbdev/api/steps/bebop/bemu/scripts/bemu_analysis.py`. Never carry the set from memory; report the derivation path with the answer. +- **ISA occupancy/free ranges**: use the `buckyball_isa_occupancy`-style free ranges if available; treat them as "not yet claimed", and always overlay the reserved set above. +- **Frozen intrinsic enum** (`llvm::Intrinsic::riscv_bb_*` validity): check `git submodule status` first (a `+` means uncommitted — 需人工裁决), then `grep -rn 'int_riscv_' $BB/compiler/thirdparty/buddy-mlir/llvm/llvm/include/llvm/IR/*.td` — the file list moves with the pin, so enumerate, don't assume. +- **Wiring precedents**: `grep -rn '' $BB/examples/cores/*/compiler/src/Dialect/Buckyball/Transforms/CMakeLists.txt` and core dispatch files — pebble's Transforms list is greppable live (`grep -n 'examples/balls/' $BB/examples/cores/pebble/compiler/src/Dialect/Buckyball/Transforms/CMakeLists.txt`), and matadd's legalize is wired from its own ball directory, not a core dialect dir. Follow the precedent, don't invent a new wiring. +- **Verifier semantics note**: `freeRanges` in an occupancy tool means "unclaimed", not "safe" — safe requires the reserved-set overlay. diff --git a/review-chip/SKILL.md b/review-chip/SKILL.md new file mode 100644 index 0000000..cb0ef99 --- /dev/null +++ b/review-chip/SKILL.md @@ -0,0 +1,62 @@ +--- +name: review-chip +description: "Chip-stage pre-PR code review checklist. Use when reviewing a chip-stage diff (skeleton/slices/integrate/bind rounds under examples/chips/) before PR submission: write-set boundary, TOML schema keys, reference existence, naming rules, batch coverage, manifest self-consistency, hygiene." +--- + +# Review: chip stage + +Purpose: catch pre-submission problems in a chip-stage deliverable (`examples/chips//**` plus the round's registration points). Pure static review: parse the diff, read the PR body, read the PR-head checkout `$BB` read-only. Never build, never simulate, never write. Internal self-consistency is what this checks — the tree must agree with itself; upstream agreement is not judged here. Path variables: `$BB` = the buckyball checkout, `$DSH_PLUGIN` = the dsh-plugin repo root. + +Inputs: the git diff, the stage, and the PR body when available (evidence manifest + change list). Run A→G in order. Items not applicable are marked 未判, never skipped. Domain judgment (operator shape predicates in `*.td`, physical capacity conclusions, performance evidence authenticity, ball implementation quality) is explicitly out of scope here. + +## A. Write-set boundary (diff level) + +1. **Allowed paths.** The diff may only touch `examples/chips//**`, the explicit registration points (added lines in the referenced cores' `configs/balldomains/*.toml`), and — for bind rounds only — the bbdev/e2e gitlink pointers with their companion files. How: `git -C $BB diff --name-only ` and classify. Report: FAIL naming each out-of-scope path. +2. **Forbidden paths.** `arch/src/main/scala/framework/**`, ball implementation trees (`examples/balls/**/arch/`, compiler passes, `*.td` files), and submodule content changes outside bind rounds: all zero-diff. Report: FAIL naming each. +3. **Bind-round gitlinks.** Target branch/URL in `.gitmodules` matches the gitlink pointers; each of the three submodules' write sets has a corresponding commit on its fork branch. How: `git -C $BB ls-tree HEAD ` against `.gitmodules`, then `git -C log`. Report: FAIL or 需人工裁决 per the evidence. + +## B. chip.toml / TOML schema keys + +4. **`configs/chip.toml`.** `[designs] include` present, value `designs/.toml` (design file named after the chip dir); `[sims]` present with `verilator` and `p2e` non-empty strings; any variant key (e.g. `rushB`) value's class name is defined on the Scala side (see item 11). How: `cat $BB/examples/chips//configs/chip.toml`. Report: FAIL naming the missing/invalid key, and explicitly note when a key is absent-but-needless (e.g. single-core chips) as 需人工裁决. +5. **`configs/designs/.toml`.** `[top] nTiles` present; `[[tiles]]` or `[tileTemplate]` at least one; `nTiles` equals the expanded count (`[[tiles]]` rows, or `[tileTemplate] count`); each tile entry has `include` resolving relative to the design file; `tile_id` values unique. How: `grep -nE '^\[|nTiles|^include|tile_id|count'` on the design file, then `test -f` each resolved include. Report: FAIL per violated rule. +6. **Tile files.** `[[cores]]` or `[coreTemplate]` at least one; every core `include` exists and sits under `examples/cores//configs/**`; `[sharedMem]` when present has boolean `enable` and positive-integer `entries`; `[coreTemplate] count` present and positive. How: same grep + resolve; `case-insensitive true/false` check on `enable`. Report: FAIL per violated rule. +7. **No silent defaults.** A `[sims]` key that maps to nothing (see item 11) or a config key the Scala side never reads is a silent default — judged via 11 rather than duplicated here. + +## C. Reference consistency (existence) + +8. **Include chain.** chip.toml → design → tile → core config, every `include` existing at its resolved path; the core's `configs/default.toml` five domain references (`balldomain`, `memdomain`, `frontend`, `gpdomain`, `core`) each resolve to an existing file. How: walk the chain with `test -f "$BB/"`; `grep -E '^(balldomain|memdomain|frontend|gpdomain|core) =' /configs/default.toml`. Report: FAIL naming the first broken link. +9. **balldomain registry rows (for every touched core balldomain file).** `ballIdMappings` and `ballISA` both present; each mapping row has `ballId`/`ballName`/`ballClass`; each ISA row has `mnemonic`/`funct7`/`bid`; every `bid` refers to a registered `ballId`; no duplicate `ballId`, `ballName`, or `(mnemonic, funct7)` pair within the file; `ballNum` equals the mapping row count and ballIds are consecutive from 0; every `config=` resolves to an existing file; `inBW`/`outBW` positive. How: `grep -nE 'ballNum|ballId|ballName|ballClass|mnemonic|funct7|bid|config=|inBW|outBW' ` and reconcile. Report: FAIL per violated rule. +10. **`CustomConfigs.scala`.** Every `WithBuckyballTiles("")` path, after stripping a leading `../`, lands inside `examples/chips//`; the `chip.pb` reference points at this chip's generated artifact. How: `grep -n 'WithBuckyballTiles' $BB/examples/chips//arch/src/main/scala/CustomConfigs.scala`, resolve each path. Report: FAIL naming each path that escapes the chip dir. +11. **[sims] ↔ Scala classes.** Every `[sims]` key's configuration class (e.g. `BuckyballVerilatorConfig`, `P2EConfig`, variant classes) exists in that chip's `arch/src/main/scala/sims/`, and its name is globally unique across the repo. How: `grep -rn "class " $BB --include=*.scala` — global hits must be exactly 1 and the file must sit under `examples/chips//arch/src/main/scala/sims/`. Report: FAIL on 0 or >1 hits. +12. **Batch manifest search paths.** Every `[workloads] search_path` in the chip's `regression/batch/**/workloads-*.toml` resolves to an existing directory under the chip tree. How: `grep -rn 'search_path' ${BB}/examples/chips//regression/` then `test -d`. Report: FAIL naming each missing dir. + +## D. Naming rules (mechanical) + +13. **Name triangle.** Chip directory name == design file name == the `` PascalCase inside `BuckyballConfig`. How: compare basenames and the PascalCase form (`${chip_dir}` → `Buckyball${PascalCase}Config` via `grep -rn "class Buckyball.*Config" examples/chips//arch`). Report: FAIL on mismatch. +14. **Workload build target and ctest registration.** `workloads/CMakeLists.txt` defines a `chip-workloads-build` target; ctest registration (`add_buckyball_ctests(...)` or the per-chip equivalent in `workloads/ctests/CMakeLists.txt`) takes an explicit list — no `file(GLOB ...)`. How: `grep -nE 'chip-workloads-build|add_buckyball_ctests|GLOB' examples/chips//workloads/**/CMakeLists.txt`. Report: FAIL naming a glob registration. +15. **emu package identity.** For multi-core chips: `[package] name` = `bebop-chip-` and `[[bin]] name` matches it in `emu/Cargo.toml`; `emu/src/main.rs` differs from the goban template only in log strings; relative `bebop-bemu` dependencies inside the workspace `has` are correct. How: `grep -nE '^(name|members)' emu/Cargo.toml`; `sed 's/"[^"]*log[^"]*"//g'`-style sanitized diff against `examples/chips/goban/emu/src/main.rs`. Report: FAIL on package/bin mismatch or non-log drift; 需人工裁决 otherwise. +16. **mlirtest stems (current-tree judgment).** `BUCKYBALL_MLIR_TEST_PREFIX` matches the group directory name; the literal `` of each `add_buckyball_mlir_test( TARGET )` has a corresponding `.mlir`; a local bespoke generator spells its stem literally in the function body without re-adding the prefix; only groups reachable via the `add_subdirectory` chain are judged. How: `grep -rnE 'BUCKYBALL_MLIR_TEST_PREFIX|add_buckyball_mlir_test' examples/chips//workloads/mlir_tests/` and walk the chain. Report: FAIL on literal mismatch, notice group directories off-chain as 未判. +17. **funct7 reserved-set collision.** New registry entries whose `funct7` value falls in the reserved set are rejected. Derive the current set instead of trusting memory: `grep -n 'InitFunct' $BB/arch/src/main/scala/framework/balldomain/isa/BallISA.scala`; `find $BB/bb-tests/workloads/lib/bbhw/isa -name '[0-9][0-9]_*.c' | sort` (two-digit filename prefix = funct7) and their `*_FUNC7` definitions; the ISA table in `bbdev/api/steps/bebop/bemu/scripts/bemu_analysis.py`. Report: FAIL naming the colliding value and the reserved entry it collides with. + +## E. Batch coverage (mechanical cross-checks) + +18. **ctest stems ↔ batch lists.** Each stem `--ctest--{baremetal,linux}` (`` = `_target_name(core)` = `core.role or core.pkg`, never the core or chip dir name — canonical rule in `knowledge/ball/regression-tables.md`) appears in the CMake registration, in the `add_buckyball_ctests` list, and in the batch `[workloads] tests` arrays — bidirectionally: listed-but-no-CMake means stale, CMake-but-not-listed means it never runs. How: `grep -rn 'ctest-' examples/chips//regression/batch/**/*.toml` and reconcile with `workloads/ctests/CMakeLists.txt`. Report: FAIL on stale entries, FAIL/disagree on missing ones. +19. **mlirtest stems ↔ batch lists.** Same cross-check for the two faces: ball-side registry + chip-side `mlir_tests` ↔ batch lists. A chip without a `regression/` directory means the lane is unregistered — report 未判 with that reason, never assume it as a failure. How: `find examples/chips//regression -name 'workloads-*.toml'`; if none, 未判. +20. **Lane × suffix completeness.** The three lanes (bemu/verilator/p2e) × two suffixes (elf/pk) copies are all present; exemptions (chip-specific lane omissions) must be stated explicitly in the report, never silently granted. How: list `regression/batch/*/workloads-*.toml` basenames and compare against the 3×2 grid minus stated exemptions. Report: FAIL naming each missing copy. + +## F. Manifest self-consistency (arithmetic and format) + +21. **Field rules.** `chip:` mandatory, non-empty, equals the directory name; `stage: chip`; `phase:` ∈ {skeleton, slices, integrate, bind}; `round:` a positive integer when written. How: field lines are whole-line declarations with optional decoration and trailing inline `#` comments stripped. Report: FAIL on each violation. +22. **Probe/perf/model declaration rules.** `--model` declaration lines are whole-line (`--model `, one per line), keys ∈ the declared model set; `probe:`/`perf:` only in a phase that consumes them (`skeleton`/`slices`/`integrate` must declare neither — the plan generates no probe step; `rtl` perf self-produces evidence via `--pmctrace`; `c-bemu` and no-phase perf need a same-stem `probe:` line). When a CI-captured `pr-context.json` exists, run `node $DSH_PLUGIN/packages/verify-runner/scripts/validate-manifest.mjs --context pr-context.json --repo-root $BB` and report its PRE-FAIL lines. Report: FAIL per rule. +23. **`capacity:` block arithmetic.** `peakBanks == Σ(concurrent × cols)` over the non-excluded rows; `cols` ∈ [1,32]; `concurrent` a positive integer; every `exclude` entry has a non-empty reason; a fully-excluded block judges nothing — say so explicitly. How: extract the block and check each row. Report: FAIL on arithmetic or out-of-range values; note on all-excluded. +24. **`exclude:` line shape.** Each line carries the `— <理由>` separator with non-empty reason; the stem must match this round's actual stem set (derived from CMake) — a typoed stem is a FAIL. How: `grep -n 'exclude:'` in the manifest, reconcile stems against item 18/19 sets. Report: FAIL naming the stem with its CMake-derived correct form. +25. **Evidence ↔ diff cross-check.** Files/tests declared in the evidence list must appear in the diff; declared-but-unchanged → warn (not fail). Report: warn naming each. +26. **ball-expect / model-lowering claims vs the pattern chain.** When the body declares a `ball-expect:` line for a model-run stem, or states that a model operator lowers to a ball, verify the four-gate pattern chain exists for that operator/ball (recipes in `knowledge/shared/model-to-ball-pipeline.md`: linalg→tile pattern registry, Tile dialect op list, TILE_HOOK registry — a generated artifact; without a build tree use the source-side `find` on `LowerTileToBuckyball` instead — and the bank-SSA emitter enumeration). Chain missing while the body claims model lowering = a false claim; the ball may still be legitimately delivered at the MLIRTest layer, which is not a failure. Report: FAIL naming the unbacked claim and the missing gate; 未判 when no recipe can run. + +## G. Hygiene (low priority) + +27. **Leftovers.** No `console.log`/debug residue, no `log/`/`.dsh/` directories in the diff; batch TOML entries are plain directory names (no interpolated variables); `chip.toml`/design files carry no inline `#` comments. How: `grep -nE 'console\.log|debugger'` on new code; scan diff paths. Report: warn per item, FAIL on a `.dsh/` or `log/` path in the diff. + +## Out of scope + +Operator shape predicates (needs `*.td` semantics), D1–D5 physical capacity conclusions, performance/PPA evidence authenticity (CI probe verdicts), and ball implementation quality (ball stage) — all belong to skills or CI, not this checklist. diff --git a/review-verify/SKILL.md b/review-verify/SKILL.md new file mode 100644 index 0000000..4281eb7 --- /dev/null +++ b/review-verify/SKILL.md @@ -0,0 +1,54 @@ +--- +name: review-verify +description: "Verify-stage pre-PR review checklist. Use when reviewing verify-stage products before PR submission: the evidence manifest, PR-body evidence block, and VERDICT reply text (not the CI). Schema rules, evidence consistency, VERDICT format, evidence-line lint, perf delta, slices gate, hygiene." +--- + +# Review: verify stage + +Purpose: catch pre-submission problems in the verify stage's artifacts — the evidence manifest in the PR body (fields `stage`/`chip`/`phase`/`round`/`probe`/`perf`/`ball-expect`/`--model`), the evidence lines in the PR reply (comment or review), and the VERDICT report itself. This is a static text review: no bbdev run, no tree mutation, no VERDICT production. The CI's own scripts are the reference implementation — the deterministic gates live in `$DSH_PLUGIN/packages/verify-runner/scripts/` (`validate-manifest.mjs`, `manifest.mjs`, `binding-check.mjs`, `slices-verify.mjs`, `probe-loop-check.mjs`, `infer-stage.mjs`); when a CI-captured `pr-context.json` is available (`gh pr view --json body,headRefOid,comments,reviews`), running those scripts is the strongest form of the check. Port their rules; never weaken them. Path variables below: `$BB` = the buckyball checkout (PR head), `$DSH_PLUGIN` = the dsh-plugin repo root. + +Inputs: the diff, the stage, the PR body, and the reply texts (comments ∪ reviews). Run 1→10 in order; each verdict line names the artifact and the facts it was derived from. Items not applicable are marked 未判 with the reason. + +## 1. Manifest schema rules + +`stage:` ∈ {workload, ball, chip} (mandatory, first field); `chip:` mandatory (no default-toy assumption) and the directory exists in the checkout (`examples/chips/`) — a same-named `examples/cores/` entry is a core, not a chip; `phase:` ∈ the stage's legal set (ball: c-bemu|rtl; chip: skeleton|slices|integrate|bind; workload: none); `round:` a positive integer when written. Field lines are whole-line declarations (line start + optional bullet/backtick, trailing inline `#` comment stripped), probe: `probe: <分钟>` (integer minutes, `分钟`/`min` suffix tolerated), perf: `perf: ` (one token), `ball-expect: [,…]` (uppercase underscore mnemonics, comma-separated), `--model ` one key per whole line (prose mentions and fenced command examples are NOT declarations). Any ``-style unfilled placeholder is the 「清单模板未填」 verdict on its own. How: `node $DSH_PLUGIN/packages/verify-runner/scripts/validate-manifest.mjs --context pr-context.json --repo-root $BB` when the capture exists; otherwise grep the body line-by-line with the DECOR anchor ``^\s*(?:[-*]\s*)?`?`` (the `DECOR` constant in `manifest.mjs`) before the field name. Report: FAIL with the offending line. + +## 2. Evidence self-consistency (cross-face) + +Stage inference (widest stage of the round's declared stages) vs the declared `stage:` — conflict → note; model write set vs `--model` declarations: a model key claimed in `--model` lines must be backed by a real write (diff path under `bb-tests/workloads/src/ModelTest` or `bbdev` pointer moving with a `MODEL_LAYOUT` mention) or by one of the declared registration points — a declaration without a write (or a write without a declaration) → FAIL; probe/perf phase whitelist: only `c-bemu`, `bind` and the no-phase baseline consume probes (a baseline round with no `--model` lines runs no probe at all — probe/perf there is 「不落地」), `rtl` perf self-produces `pmc-evidence` via `--pmctrace` and needs no probe line, `skeleton`/`slices`/`integrate` round probes are dead. How: `node $DSH_PLUGIN/packages/verify-runner/scripts/binding-check.mjs --context pr-context.json --repo-root $BB` + `$DSH_PLUGIN/packages/verify-runner/scripts/infer-stage.mjs --context pr-context.json` when captures exist; otherwise reconcile diff paths with the manifest fields. Report: FAIL per rule; 需人工裁决 when the write set cannot be established. + +## 3. VERDICT reply format contract + +First line matches `^VERDICT: (PASS|FAIL)`; a `head sha:` line exists and equals `headRefOid` (40 hex chars, exact case, no abbreviation); the verdict block records stage/phase/layer/round as declared; a FAIL carries the four elements — the command verbatim, the log tail, the suspected cause, and the JUnit facts; a bind-round PASS must carry the literal string 「功能收敛未证,需 complete 层或更长预算补全跑」. How: test the first line with the regex, extract the sha line, check the four elements' presence in the FAIL body. Report: FAIL naming each missing element. + +## 4. Evidence-line lint (four strict forms) + +Accepted forms (line-anchored, key names and field order strict, decoration tolerated): `probe-evidence: cycles=`; `/` prefix variant; `cycles=none (instrument-not-applicable)` sentinel; `pmc-evidence: … calls= elapsed_avg= elapsed_max= elapsed_min=`. One round, one instrument: an `rtl` round must not carry probe-evidence lines and vice versa (rtl = pmc instrument, c-bemu/no-phase = probe instrument). A line that *tries* to be evidence but fails the shape is named, not dropped. How: grep each reply body for `probe-evidence`/`pmc-evidence` lines and compare against the round's phase. Report: FAIL naming each malformed or misplaced line. + +## 5. perf round delta obligation + +A round declaring `perf:` owes a same-instrument delta in the same reply — `cycles: (Δ …)` or `elapsed_avg: …` per instrument; no delta → FAIL「性能结论无证据」; a word-salad claim — 「明显变快」/「符合预期的取舍」/ any no-number framing — is named; a previous-round sentinel (instrument-not-applicable) means this round has no comparison base and must recite the not-applicable clause instead of claiming a baseline. How: `node $DSH_PLUGIN/packages/verify-runner/scripts/probe-loop-check.mjs --context pr-context.json` (with capture) or grep the reply for the delta pattern and for the blacklist words. Report: FAIL on missing delta, note baseline/sentinel cases. + +## 6. slices-gate evidence prerequisite + +An `integrate` round claiming 「上一轮 slices 已过」 needs a prior PASS reply that declares its own `phase: slices` on a DECOR-anchored line and whose recorded head sha matches the current PR head; without it the claim is unsupported. How: `node $DSH_PLUGIN/packages/verify-runner/scripts/slices-verify.mjs --context pr-context.json` (comments ∪ reviews, both faces) or manual search for `VERDICT: PASS` + `phase: slices` declaration + `head sha:` in the same reply. Report: FAIL on missing evidence; note when the gate is N/A. + +## 7. Reply-face facts + +The verdict report lands in comments ∪ reviews (a PASS as a review is invisible to a comments-only scan — check both); the first line is matchable by `^VERDICT: (PASS|FAIL)` (INFRA-class exclusion must be stated); more than one repost of the same verdict → flag (2+ duplicates); marker idempotency is run-only. How: list both faces, dedupe first lines, count. Report: warn per finding. + +## 8. No-execution / no-rewrite assertion + +The report's command list replays `bbdev-plan`'s output for the same (stage, phase, layer, chip, stems, models, probes, perf, compilerTouched) — command names, ops, and args must not be hand-assembled; no placeholder residue (`<[A-Z][A-Z0-9-]*:[^>]*>`); no command outside the existing whitelist. How: compare the report's commands against the plan capture (or against `src/tools/bbdev-plan.ts`'s builder when no capture exists); `grep -nE '<[A-Z][A-Z0-9-]*:[^>]*>'` on the reply. Report: FAIL naming each deviation or residue. + +## 9. Read-only / no-fallback statement lint + +Fallback phrasing — 「缺省 toy」, 「退回到」, 「用最新一个」, any "default to X" without a declared basis — is named; `skippedLanes`/`skippedProbes` entries must be recorded with a reason and matched against the round's plans. How: grep the reply for the fallback words and check every skip entry's reason. Report: warn naming each phrase, FAIL on an unexplained skip. + +## 10. Baseline-reference residue + +`check.yaml`/`regression.yml` line numbers, fork drill PR numbers, and the pinned shas must not appear in prompt text, replies, or manifests — replacing them with knowledge-base retrieval or deleting them is the fix. How: `grep -nE 'check\.yaml:[0-9]+|regression\.yml:[0-9]+|9bb40565|90560b4|6e389513|8f73458|7cb39e5'` on the artifacts. Report: FAIL (must-fix residue) naming each occurrence. (The sha list itself is a residue landmark, not a live pin — verify against the actual residue, not the list.) + +## Out of scope + +The CI verdict itself (whether the round actually passed — CI decides that), run logs, and build results: this checklist reviews the artifacts' internal consistency and contract adherence only. diff --git a/review-workload/SKILL.md b/review-workload/SKILL.md new file mode 100644 index 0000000..c485789 --- /dev/null +++ b/review-workload/SKILL.md @@ -0,0 +1,37 @@ +--- +name: review-workload +description: "Workload-stage pre-PR review checklist. Use when reviewing a workload-round diff (initial ModelTest e2e model adaptation): write-set containment, gitlink consistency, manifest fields, model-dir completeness, CMake registrations, expected-value tracking, annotation rules." +--- + +# Review: workload stage + +Purpose: catch pre-submission problems in a workload-stage deliverable — one ModelTest e2e model directory (`bb-tests/workloads/src/ModelTest/e2e/models/models//`), its two registration points, and the parent PR. Pure static review: parse the diff, read the PR body, read the PR-head checkout `$BB` read-only. Never build, never simulate, never write. Path variables: `$BB` = the buckyball checkout, `$DSH_PLUGIN` = the dsh-plugin repo root. + +Inputs: the git diff (gitlink changes appear as a pointer line in the parent diff), the stage, and the PR body when the caller has it (evidence manifest under the 「改了哪些文件」 marker or a `## Changes` heading). + +Run A→C in order. Items that do not apply are marked 未判 (not judged), never skipped silently. If a repository-side shape the recipe anchors on has changed structurally, report 需人工确认 (needs human adjudication) instead of FAIL — that is repo drift, not an author error. + +## A. Range and pointers (diff level) + +1. **Write-set containment.** Allowed diff paths: the e2e gitlink pointer (`bb-tests/workloads/src/ModelTest/e2e`), `bb-tests/workloads/src/ModelTest/e2e/models/CMakeLists.txt`, `bb-tests/workloads/src/ModelTest/e2e/models/models/CMakeLists.txt`, and `bb-tests/workloads/src/ModelTest/e2e/models/models//`. How: `git -C $BB diff --name-only ` for the whole PR and classify each path (a gitlink shows only as its path in the parent diff; inspect the submodule for what it points to). Zero-diff requirement: `bbdev/**` (incl. `MODEL_LAYOUT` in `bbdev/api/steps/workload/01_build_event.step.py`), `bb-tests/workloads/scripts/build.py` (`_MODELS`), `bb-tests/workloads/src/ModelTest/e2e/models/archs/buckyball/**`, `scripts/**`. Report: FAIL naming each out-of-scope path. +2. **Gitlink consistency.** Parent gitlink equals the submodule branch tip; the submodule branch contains latest main; its commit set is exactly this round's write set (no extra rounds, no subsequent-stage assets). How: `git -C $BB ls-tree HEAD bb-tests/workloads/src/ModelTest/e2e` vs `git -C rev-parse HEAD`; `git -C merge-base --is-ancestor main HEAD`; `git -C log --oneline main..HEAD`. Report: FAIL on a tip mismatch, on extra commits (name them), or on a branch not based on current main. +3. **Manifest pre-check.** `stage: workload` present; `chip:` present and non-empty; no `phase:` / `probe:` / `perf:` / `ball-expect:` lines (workload stage has no phase dimension, probes have no execution carrier); no `--model` declaration line (an unbound model is not this round's subject); `round:` a positive integer when written; each field line is a whole-line declaration (optional bullet/backtick decoration, trailing inline `#` comment tolerated). How: read the PR body; when a CI-captured `pr-context.json` is available (`gh pr view --json body,headRefOid,comments,reviews`), run `node $DSH_PLUGIN/packages/verify-runner/scripts/validate-manifest.mjs --context pr-context.json --repo-root $BB` and report every PRE-FAIL line. Report: FAIL with the offending line. + +## B. Artifact completeness + +4. **Model directory essentials.** The directory must carry, at top level: an importer (`*.py`), a driver (`*-main.cpp`), `CMakeLists.txt`, `.gitignore`, `HANDOFF.md`. How: `find $BB/bb-tests/workloads/src/ModelTest/e2e/models/models/ -maxdepth 1 -type f`. Report: FAIL naming each missing kind. +5. **HANDOFF sections and reproduce command.** Five headings present, matched as markdown headings: `Artifacts`, `Canonical Reference`, `Local Run`, `Build Binding`, `Known Limitation`; the reproduce command appears in the text with whitespace folded. How: `grep -nE '^#+ *(Artifacts|Canonical Reference|Local Run|Build Binding|Known Limitation)' /HANDOFF.md`; compare the command after collapsing each side's whitespace runs to one space. Report: FAIL naming missing headings or the missing command. +6. **The two CMake registration points.** In `models/models/CMakeLists.txt`: a `set(MODEL__DIR ...)` entry and an `if (MODEL_)` guard wrapping `add_subdirectory()`, the flag matching the directory name after normalization (lowercase, strip non-alphanumerics); in `models/CMakeLists.txt`: the new flag in the MODEL reset list. How: `sed -n '1,40p' ` and compare flags by the normalization rule. Structural change in the CMake shape → 需人工确认, not FAIL. +7. **Expected-value source.** Declared source resolves to a path inside the model directory (reject `..` traversal), the file exists, and: declared tracked → no `.gitignore` rule at `/.gitignore` or `models/models/.gitignore` claims it (`git -C $BB check-ignore -v ` or read the two files; a rule hits when the path equals the rule body or a prefix-segment glob matches); declared untracked → HANDOFF states the value is generated by the reproduce command. Report: FAIL on traversal, missing file, claimed-by-ignore, or a missing regeneration statement. +8. **Generated artifacts must not reach the diff.** Importer outputs (`*.mlir`, `*.data`, `*.payload/`, `output/`) appearing as diff paths (or as added files) mean the commit escaped the ignore rules — a `.gitignore` rule at the directory level must already cover them. Report: FAIL naming the file plus the rule that should have covered it, or the missing rule. + +## C. Form and annotation + +9. **Expected-value encoding form.** The value must be encoded as either a fail-hard driver (a `constexpr`-style expected constant in `*-main.cpp` with the mismatch branch `return 1`) or a reference script in the directory (the `python3 -ppl.py --weights ` shape). How: `grep -nE 'constexpr|return 1' /*-main.cpp`; list `*.py` next to the driver. Neither form present → 需人工确认 (the model may legitimately use a third shape), never silently accepted. +10. **Team-extra form annotation.** When the directory carries `--jit-check`, a `pytorch--*.py --check` companion, a `reference/_manifest.json`, or a `.rax` package (the `buddy-cli` host-CPU path), HANDOFF.md must explicitly mark the form as a team addition. How: `grep -rnE 'jit-check|--check|manifest\.json|\.rax' `; then `grep -n '团队附加' /HANDOFF.md`. Report: FAIL when a form appears without the annotation. +11. **No executable target.** `models/models//CMakeLists.txt` must not call `add_executable` (run executables live on the `archs/` side; this stage is model-side only). How: `grep -n 'add_executable' /CMakeLists.txt`. Report: FAIL naming the target. + +## Notes + +- Stage parameterization: in a workload round, `MODEL_LAYOUT` / `_MODELS` / `archs/buckyball/**` are **zero-diff** (item 1); their consistency is a bind-round concern and belongs to that round's review. +- All facts outside the diff are verified read-only; when a fact cannot be established (submodule not checked out, CI capture missing), report 需人工裁决 with what you could and could not see. diff --git a/workload-integration-guide/SKILL.md b/workload-integration-guide/SKILL.md new file mode 100644 index 0000000..5819fe7 --- /dev/null +++ b/workload-integration-guide/SKILL.md @@ -0,0 +1,108 @@ +--- +name: workload-integration-guide +description: "Workload-stage model integration for Buckyball ModelTest e2e: model-directory files, the two CMake registration points, .rax+buddy-cli vs offline run pathways, expected values, environment prerequisites, HANDOFF sections, gitlink delivery. Use when you add, adapt, import, or audit a workload." +--- + +# Workload integration guide + +The workload stage turns a HuggingFace model into +`bb-tests/workloads/src/ModelTest/e2e/models/models//` plus its two registration +entries. Workflow discipline (stage boundary, step order, manifest fields, ACCEPT +gate) is enforced by the harness plugin's playbook; this skill carries the +knowledge behind it. + +Live-tree facts (which models exist, exact CMake flag spellings, .gitignore +conventions, `build.py` registry state) come from the `bb-knowledge` skill's +workload topics — treat anything not re-derived from the tree as stale. + +## Deliverable anatomy + +Create `/` under `e2e/models/models/` with: + +- `import-*.py` — traces the upstream model, exports MLIR plus weight files. A host-CPU JIT check (`--jit-check`-style switch) is a team-added shape, not an upstream one. +- `*-main.cpp` — runs the imported graph and hits a hard-coded expected value, exiting non-zero on mismatch. +- `CMakeLists.txt` — build binding. It must not declare an executable: `*-run` targets live in `archs/` and belong to the later binding stage. +- `.gitignore` — keeps importer artifacts out of git. The parent `models/models/.gitignore` already covers coarse generated paths; per-directory rules cover the rest. +- `HANDOFF.md` — the handoff contract with five fixed sections (names below). +- Optional `README.md` — human-facing usage; follow an existing model's README shape (see `Whisper/README.md`) and keep the expected output visible. + +Directory extras: `quant/` and `trace/` are the quantization and cycle-trace stages of the same model — read them, never copy. `specs/`, `*Runner*.cpp`, `codegen/` and `include/` belong to the `.rax` pathway described below. + +## Registration + +Two files must mention the new model: + +1. `e2e/models/CMakeLists.txt` — the MODEL reset list (`foreach(model_flag IN ITEMS ...)` block). +2. `e2e/models/models/CMakeLists.txt` — `set(MODEL__DIR ...)` plus an `if (MODEL_)` guard wrapping `add_subdirectory()`. + +The flag is not always the bare uppercased directory name (e.g. the directory +`MiniMaxH3FL2VA` registers as `MINIMAX_H3_FL2VA`), so read the existing entries +and derive the flag from them instead of assuming. + +## Run pathways + +Pick one of the two legitimate host runs per model shape: + +- `.rax` + `buddy-cli` (preferred, chip-agnostic host CPU): the directory carries `specs/.json`, a runner plugin (`*Runner.cpp` / `*RunnerPlugin.cpp`) and the codegen hook. Packaging happens in buddy-mlir through `tools/buddy-codegen/build_model.py --spec --build-dir `, producing a `.rax` that `buddy-cli --model .rax` loads and executes on the host. Record the packaging command and its repository in HANDOFF when you use this path. +- Offline compare: models without a chip-agnostic executable path run the original implementation, or feed the exported weights back into it (`python3 -ppl.py --weights ` style), and compare against the expected value. + +Which existing models take which path is a live-tree fact: a model with `specs/` +plus `*Runner*.cpp` is packaged-shaped; a model whose importer only emits MLIR +plus weight files is offline-compare-shaped. + +## Environment + +Everything runs inside `nix develop` at the buckyball repo root. The shell must +start from the repo root — the `sourceme.sh` presence check fails anywhere else, +and the shellHook assigns `$BB_ROOT` there. Before importing, confirm: + +- buddy-mlir is built: `sourceme.sh` injects `PYTHONPATH` and `BUDDY_MLIR_BUILD_DIR`, and `e2e/models/CMakeLists.txt` FATAL_ERRORs when `BUDDY_MLIR_BUILD_DIR` is absent. +- `torch` / `transformers` versions are not pinned anywhere upstream — record the actually used versions in HANDOFF. +- HuggingFace is reachable. If not, set `HF_ENDPOINT` to a mirror; private models need `HF_TOKEN` in the launch environment (the model-info tool reports the 401). + +Tokenizer: commit a `vocab.txt` inside the model directory and read it from the +C++ side with `Text::tokenizeBert(vocabDir, )` (the Bert +driver is the precedent) — no third-party tokenizer. + +## Expected value + +Primary criterion: a hard-coded discrete expectation with fail-hard — the driver +computes an argmax-class conclusion, compares against a `constexpr` expectation, +and exits non-zero on mismatch. For MLM / generative models without a single +discrete conclusion: the driver prints the argmax landing point and a bundled +offline reference script (e.g. `python3 -ppl.py --weights `) emits +the reference metric. + +Element-wise tolerance comparison is not the workload-stage criterion — it +belongs to the quant/trace compare tools. A tolerance may appear as an auxiliary +gate inside the offline script, never as the conclusion. + +Team-added shapes upstream does not have — `--jit-check` switches, +`pytorch--*.py --check` checkers, `reference/_manifest.json` — must be +labeled in HANDOFF as team-added, not presented as upstream form. + +## HANDOFF.md sections + +`HANDOFF.md` lives at `/HANDOFF.md`, for reviewers and later stages: + +- Artifacts — files this workload produces. +- Canonical Reference — where the expected value comes from (HF weights / original implementation plus the producing command), the expected value itself, and the reproduce command. +- Local Run — device (CPU/GPU), the chosen run command, elapsed time. +- Build Binding — configure/build commands used, if any. +- Known Limitation — known limits and uncovered items. + +Every assertion cites a command output or a file path. The expected value must be +literal in the document: a reader never runs anything to know what "correct" is. + +## Delivery + +Multi-submodule delivery: the write set goes to a feature branch of the e2e +submodule (buddy-examples fork); the parent-repo (buckyball fork) PR carries that +submodule's gitlink — a parent-side pointer to one submodule commit +(`.gitmodules` declares the path's url/branch). Model files only enter the +submodule; the parent-side diff is just the pointer moving. + +Parent-side write rules: always carry the e2e gitlink; carry the bbdev gitlink +only when bbdev `MODEL_LAYOUT` changed (not at this stage); `build.py::_MODELS` +entries belong to the binding stage. The branch is based on newest main and +contains only this workload's write set.