From d8d14bff0261555c160b9402ae916a99a7a4694b Mon Sep 17 00:00:00 2001 From: Rob Taylor Date: Wed, 4 Mar 2026 22:42:27 +0000 Subject: [PATCH] =?UTF-8?q?Rename=20Loom=20=E2=86=92=20Jacquard=20across?= =?UTF-8?q?=20codebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The project was renamed from Loom to Jacquard but many references to the old name remained in scripts, CI, docs, and test files. This updates all occurrences across 27 files: - Python scripts: function/variable names, CLI flags, docstrings, output labels - CI workflow: file paths, variable names, job names, display text - Docs: all 6 markdown files with Loom references - Test scripts: shell scripts, Verilog comments, SDF vendor fields, VCD headers - Docker: image name loom-cvc → jacquard-cvc CLI backward compatibility preserved: --loom-vcd and --loom-timing-vcd still accepted as aliases in compare_timing.py and compare_simulation.py. Co-developed-by: Claude Code v2.1.50 (claude-opus-4-6) --- .github/workflows/ci.yml | 40 +++--- docs/cosim-timing-support.md | 12 +- docs/simulation-architecture.md | 6 +- docs/timing-simulation.md | 12 +- docs/timing-validation.md | 28 ++-- scripts/chipflow_harness/README.md | 4 +- scripts/compare_timing.py | 116 ++++++++-------- tests/mcu_soc/cvc/compare_simulation.py | 126 +++++++++--------- tests/mcu_soc/cvc/convert_stimulus.py | 6 +- tests/mcu_soc/cvc/gen_cell_models.py | 2 +- tests/mcu_soc/cvc/run_cvc.sh | 4 +- tests/mcu_soc/cvc/stimulus_gen.v | 2 +- tests/mcu_soc/cvc/stimulus_gen_new.v | 2 +- tests/mcu_soc/cvc/strip_sdf_checks.py | 2 +- tests/mcu_soc/cvc/tb_cvc.v | 8 +- tests/timing_test/cvc/Dockerfile | 2 +- tests/timing_test/cvc/run_cvc.sh | 12 +- .../inv_chain_pnr/inv_chain_stimulus.vcd | 2 +- tests/timing_test/inv_chain_pnr/tb_cvc.v | 2 +- .../multi_depth/multi_depth_stimulus.vcd | 2 +- .../multi_depth/run_cvc_multi_depth.sh | 4 +- tests/timing_test/multi_depth/tb_cvc.v | 2 +- tests/timing_test/sky130_timing/Makefile | 2 +- tests/timing_test/sky130_timing/README.md | 8 +- .../sky130_timing/gen_liberty_sdf.py | 2 +- tests/timing_test/sky130_timing/inv_chain.sdf | 2 +- .../timing_test/sky130_timing/logic_cone.sdf | 2 +- 27 files changed, 206 insertions(+), 206 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed3fa1d..232f01f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -143,7 +143,7 @@ jobs: cargo run --release --features metal --bin jacquard -- sim \ tests/timing_test/inv_chain_pnr/inv_chain.v \ tests/timing_test/inv_chain_pnr/inv_chain_stimulus.vcd \ - tests/timing_test/inv_chain_pnr/loom_timed_output.vcd \ + tests/timing_test/inv_chain_pnr/jacquard_timed_output.vcd \ 1 \ --sdf tests/timing_test/inv_chain_pnr/inv_chain_test_ps.sdf \ --sdf-corner typ \ @@ -158,7 +158,7 @@ jobs: path: | tests/timing_test/ci_output.vcd tests/timing_test/ci_xprop_output.vcd - tests/timing_test/inv_chain_pnr/loom_timed_output.vcd + tests/timing_test/inv_chain_pnr/jacquard_timed_output.vcd metal_timing.txt metal_xprop.txt metal_timed.txt @@ -540,7 +540,7 @@ jobs: --sdf tests/mcu_soc/data/6_final_stripped.sdf \ --sdf-corner typ \ --stimulus-vcd tests/mcu_soc/stimulus.vcd \ - --timing-vcd tests/mcu_soc/loom_timed_mcu.vcd \ + --timing-vcd tests/mcu_soc/jacquard_timed_mcu.vcd \ 2>&1 | tee cosim_stimulus.txt - name: Replay stimulus (non-timed, for CVC comparison) @@ -550,7 +550,7 @@ jobs: cargo run --release --features metal --bin jacquard -- sim \ tests/mcu_soc/data/6_final.v \ tests/mcu_soc/stimulus.vcd \ - tests/mcu_soc/loom_replay_mcu.vcd \ + tests/mcu_soc/jacquard_replay_mcu.vcd \ 1 \ --top-module top \ --max-cycles 10000 \ @@ -589,8 +589,8 @@ jobs: metal_mcu_replay.txt tests/mcu_soc/sim_config.json tests/mcu_soc/stimulus.vcd - tests/mcu_soc/loom_replay_mcu.vcd - tests/mcu_soc/loom_timed_mcu.vcd + tests/mcu_soc/jacquard_replay_mcu.vcd + tests/mcu_soc/jacquard_timed_mcu.vcd # Build documentation (cargo doc + mdbook) and deploy to GitHub Pages docs: @@ -742,9 +742,9 @@ jobs: tests/timing_test/inv_chain_pnr/cvc_output.log tests/timing_test/inv_chain_pnr/cvc_inv_chain_output.vcd - # Compare timing results between CVC (event-driven) and Loom (GPU) + # Compare timing results between CVC (event-driven) and Jacquard (GPU) timing-comparison: - name: Timing Comparison (CVC vs Loom) + name: Timing Comparison (CVC vs Jacquard) runs-on: ubuntu-latest needs: [metal, cvc-reference] if: always() && needs.metal.result == 'success' && needs.cvc-reference.result == 'success' @@ -770,7 +770,7 @@ jobs: uv run scripts/compare_timing.py \ --cvc-log cvc-results/tests/timing_test/inv_chain_pnr/cvc_output.log \ --cvc-vcd cvc-results/tests/timing_test/inv_chain_pnr/cvc_inv_chain_output.vcd \ - --loom-vcd metal-results/tests/timing_test/inv_chain_pnr/loom_timed_output.vcd \ + --jacquard-vcd metal-results/tests/timing_test/inv_chain_pnr/jacquard_timed_output.vcd \ --clock-period-ps 10000 \ --clock-signal CLK \ --output-signal Q \ @@ -781,7 +781,7 @@ jobs: if: always() run: | { - echo "## Timing Comparison (CVC vs Loom)" + echo "## Timing Comparison (CVC vs Jacquard)" echo "" echo "\`\`\`" cat comparison.txt 2>/dev/null || echo "No comparison output" @@ -894,7 +894,7 @@ jobs: tests/mcu_soc/cvc/cvc_sim.log tests/mcu_soc/cvc/cvc_output.vcd - # Compare MCU SoC results between CVC (event-driven) and Loom (GPU) + # Compare MCU SoC results between CVC (event-driven) and Jacquard (GPU) mcu-soc-comparison: name: MCU SoC Functional Comparison runs-on: ubuntu-latest @@ -917,25 +917,25 @@ jobs: name: mcu-soc-cvc-results path: cvc-results/ - - name: Compare outputs (non-timed Loom vs CVC) + - name: Compare outputs (non-timed Jacquard vs CVC) run: | - LOOM_VCD="metal-results/tests/mcu_soc/loom_replay_mcu.vcd" + JACQUARD_VCD="metal-results/tests/mcu_soc/jacquard_replay_mcu.vcd" CVC_VCD="cvc-results/cvc_output.vcd" - if [ ! -f "$LOOM_VCD" ]; then - echo "SKIP: Loom replay VCD not found" | tee mcu_comparison.txt + if [ ! -f "$JACQUARD_VCD" ]; then + echo "SKIP: Jacquard replay VCD not found" | tee mcu_comparison.txt exit 0 fi if [ ! -f "$CVC_VCD" ]; then echo "SKIP: CVC output VCD not found (CVC simulation may have failed)" | tee mcu_comparison.txt exit 0 fi - LOOM_TIMING_VCD="metal-results/tests/mcu_soc/loom_timed_mcu.vcd" + JACQUARD_TIMING_VCD="metal-results/tests/mcu_soc/jacquard_timed_mcu.vcd" TIMING_ARGS="" - if [ -f "$LOOM_TIMING_VCD" ]; then - TIMING_ARGS="--loom-timing-vcd $LOOM_TIMING_VCD" + if [ -f "$JACQUARD_TIMING_VCD" ]; then + TIMING_ARGS="--jacquard-timing-vcd $JACQUARD_TIMING_VCD" fi uv run tests/mcu_soc/cvc/compare_simulation.py \ - "$LOOM_VCD" "$CVC_VCD" \ + "$JACQUARD_VCD" "$CVC_VCD" \ --skip-cycles 5 \ --num-cycles 10000 \ --skip-bits 0-5 \ @@ -947,7 +947,7 @@ jobs: if: always() run: | { - echo "## MCU SoC Simulation Comparison (CVC vs Loom)" + echo "## MCU SoC Simulation Comparison (CVC vs Jacquard)" echo "" echo "\`\`\`" cat mcu_comparison.txt 2>/dev/null || echo "No comparison output" diff --git a/docs/cosim-timing-support.md b/docs/cosim-timing-support.md index 3677611..d20e0cc 100644 --- a/docs/cosim-timing-support.md +++ b/docs/cosim-timing-support.md @@ -2,17 +2,17 @@ **Status**: Implementation plan for Goal step 8 (final step) -**Objective**: Enable arrival time readback in cosim mode so timing-annotated VCD can be produced without a separate `loom sim` replay. Completes timing validation feature parity with `loom sim`. +**Objective**: Enable arrival time readback in cosim mode so timing-annotated VCD can be produced without a separate `jacquard sim` replay. Completes timing validation feature parity with `jacquard sim`. ## Current State -### loom sim ✅ (Complete) +### jacquard sim ✅ (Complete) - Metal: `--timing-vcd` fully functional with arrival time readback - CUDA/HIP: In progress (step 7 - kernel FFI bindings) - Produces timing-annotated VCD with arrival times for all signals - Validated against CVC reference simulator -### loom cosim ❌ (No timing support) +### jacquard cosim ❌ (No timing support) - Supports co-simulation with external testbenches (via Verilog VCD) - **Does NOT support** `--timing-vcd` flag currently - CPU-GPU synchronized stepping; peripheral models run on CPU @@ -23,16 +23,16 @@ **Current workflow** (suboptimal): ```bash # Step 1: Run cosim to get functional outputs -loom cosim --input stimulus.vcd --output functional.vcd +jacquard cosim --input stimulus.vcd --output functional.vcd # Step 2: Run again with timing to get arrival times (slow!) -loom sim --input stimulus.vcd --output timed.vcd --sdf design.sdf --timing-vcd +jacquard sim --input stimulus.vcd --output timed.vcd --sdf design.sdf --timing-vcd ``` **Desired workflow** (step 8): ```bash # Single command produces both functional + timing outputs -loom cosim --input stimulus.vcd --output timed.vcd \ +jacquard cosim --input stimulus.vcd --output timed.vcd \ --sdf design.sdf --timing-vcd ``` diff --git a/docs/simulation-architecture.md b/docs/simulation-architecture.md index b26d14b..efe10b0 100644 --- a/docs/simulation-architecture.md +++ b/docs/simulation-architecture.md @@ -283,7 +283,7 @@ WARN (GATESIM_VCDI_MISSING_PI) Primary input port (HierName(), "reset", None) no ### 3. No Latch or Asynchronous Sequential Logic Support -**Issue**: Loom only supports edge-triggered D flip-flops (DFFs) as sequential elements. Latch-based designs (SR latches, transparent latches, master-slave latch pairs) and asynchronous sequential logic are not supported. +**Issue**: Jacquard only supports edge-triggered D flip-flops (DFFs) as sequential elements. Latch-based designs (SR latches, transparent latches, master-slave latch pairs) and asynchronous sequential logic are not supported. **Impact**: Designs using latches will either: - Fail during AIG conversion (unrecognized cell type) @@ -291,7 +291,7 @@ WARN (GATESIM_VCDI_MISSING_PI) Primary input port (HierName(), "reset", None) no **What this means in practice**: - Gate-level netlists must be synthesized to a DFF-only cell library (AIGPDK or SKY130) -- CVC's built-in test suite (`tests_and_examples/install.test/`) uses NAND-latch flip-flops (e.g., `dfpsetd.v`, `sdfia04.v`) and cannot be used as Loom reference tests +- CVC's built-in test suite (`tests_and_examples/install.test/`) uses NAND-latch flip-flops (e.g., `dfpsetd.v`, `sdfia04.v`) and cannot be used as Jacquard reference tests - Self-timed designs with internal clock generation (e.g., CVC's `das_lfsr` benchmark) are also unsupported **What would be needed to support latches**: @@ -304,7 +304,7 @@ WARN (GATESIM_VCDI_MISSING_PI) Primary input port (HierName(), "reset", None) no **Complexity estimate**: Moderate-to-high. The main challenge is the evaluation model change — DFF-only simulation is a clean "capture at edge" model, while latches require iterative evaluation within clock phases. -**Status**: Not planned. Loom targets synthesis flows that produce DFF-only netlists. +**Status**: Not planned. Jacquard targets synthesis flows that produce DFF-only netlists. ### 4. Format String Preservation **Issue**: Yosys synthesis may not preserve `gem_format` attributes diff --git a/docs/timing-simulation.md b/docs/timing-simulation.md index a629ccf..d4b901f 100644 --- a/docs/timing-simulation.md +++ b/docs/timing-simulation.md @@ -290,7 +290,7 @@ This is feasible but significantly increases memory pressure and computation. ## Conservative Timing Model: Sources of Overestimation -Loom's GPU timing is intentionally conservative — it may over-estimate arrival times +Jacquard's GPU timing is intentionally conservative — it may over-estimate arrival times but will never under-estimate them. This is important for setup violation detection: false positives are safe, false negatives would miss real bugs. @@ -309,7 +309,7 @@ delay = max(gate_delays[pin].rise_ps, gate_delays[pin].fall_ps) **Impact**: For the SKY130 inv_chain test (16 inverters), rise delays average ~10ps larger than fall delays. In a real inverter chain, transitions alternate (rise→fall→rise), -so half the cells use the smaller fall delay. Loom uses the larger rise delay for all. +so half the cells use the smaller fall delay. Jacquard uses the larger rise delay for all. **Measured**: 80ps overestimate on 1235ps (6.5%) for 16 inverters with ~10ps rise/fall asymmetry per cell. @@ -317,7 +317,7 @@ asymmetry per cell. ### Source 2: max wire delay across all input pins For multi-input cells (AND gates, MUXes), INTERCONNECT delays to different input pins -may differ significantly. Loom takes the maximum across all input pins: +may differ significantly. Jacquard takes the maximum across all input pins: ```rust // wire_delays_per_cell: dest_cellid → max(all input wire delays) @@ -326,7 +326,7 @@ entry.fall_ps = entry.fall_ps.max(ic.delay.fall_ps); ``` **Impact**: If an AND gate has input A arriving via a 10ps wire and input B via a -200ps wire, Loom assigns 200ps to the cell regardless of which input is on the +200ps wire, Jacquard assigns 200ps to the cell regardless of which input is on the critical path. An event-driven simulator would correctly propagate the 10ps arrival on input A independently. @@ -336,7 +336,7 @@ delays to multi-input cells. ### Source 3: max arrival across 32 packed signals per thread -Each thread position holds 32 independent Boolean signals. Loom tracks one arrival +Each thread position holds 32 independent Boolean signals. Jacquard tracks one arrival per thread position (the maximum across all 32 signals): ``` @@ -373,7 +373,7 @@ The inv_chain design (2 DFFs + 16 SKY130 inverters) was validated against CVC ``` CVC: clk_to_q=350ps chain=885ps total=1235ps (transition-accurate) -Loom: clk_to_q=350ps chain=973ps total=1323ps (conservative max) +Jacquard: clk_to_q=350ps chain=973ps total=1323ps (conservative max) Difference: 88ps (7.1% overestimate) ``` diff --git a/docs/timing-validation.md b/docs/timing-validation.md index b9a2a94..cd30370 100644 --- a/docs/timing-validation.md +++ b/docs/timing-validation.md @@ -24,7 +24,7 @@ GEM's timing simulation (`--timing-vcd` and `--enable-timing` flags) must be val ```bash # Example: MCU SoC functional comparison uv run tests/mcu_soc/cvc/compare_outputs.py \ - loom_output.vcd cvc_output.vcd \ + jacquard_output.vcd cvc_output.vcd \ --skip-cycles 5 # Skip first 5 cycles (reset/initialization) ``` @@ -75,7 +75,7 @@ cargo run -r --features metal --bin jacquard -- sim \ ``` **Expected results**: -- Loom Q arrival ≈ CVC total_delay (within ±5%) +- Jacquard Q arrival ≈ CVC total_delay (within ±5%) - Both simulators show monotonic delay increase with each inverter stage ### MCU SoC post-layout (Complex Case) @@ -95,11 +95,11 @@ uv run tests/mcu_soc/cvc/strip_sdf_checks.py \ tests/mcu_soc/data/6_final.sdf \ tests/mcu_soc/data/6_final_stripped.sdf -# 2. Generate Loom timing VCD +# 2. Generate Jacquard timing VCD cargo run -r --features metal --bin jacquard -- sim \ tests/mcu_soc/data/6_final.v \ tests/mcu_soc/stimulus.vcd \ - tests/mcu_soc/loom_timed_mcu.vcd 1 \ + tests/mcu_soc/jacquard_timed_mcu.vcd 1 \ --sdf tests/mcu_soc/data/6_final_stripped.sdf \ --sdf-corner typ \ --timing-vcd \ @@ -114,14 +114,14 @@ cvc64 +typdelays tests/mcu_soc/cvc/tb_cvc.v \ # 4. Compare functional outputs uv run tests/mcu_soc/cvc/compare_outputs.py \ - tests/mcu_soc/loom_timed_mcu.vcd \ + tests/mcu_soc/jacquard_timed_mcu.vcd \ tests/mcu_soc/cvc/cvc_output.vcd \ --skip-cycles 5 ``` **Expected results**: - Functional output: Exact match (or documented difference with explanation) -- Arrival times: Loom values ≥ CVC due to conservative path accumulation +- Arrival times: Jacquard values ≥ CVC due to conservative path accumulation - CI: Comparison completes without errors ### Pre-layout Library Timing @@ -151,19 +151,19 @@ python3 gen_liberty_sdf.py logic_cone.v cvc64 +typdelays tb_inv_chain.v inv_chain.v 2>&1 | tee cvc.log ./cvcsim -# Run Loom GPU simulation +# Run Jacquard GPU simulation cargo run -r --features metal --bin jacquard -- sim \ - inv_chain.v stimulus.vcd loom_output.vcd 1 \ + inv_chain.v stimulus.vcd jacquard_output.vcd 1 \ --sdf inv_chain.sdf \ --timing-vcd # Compare outputs -uv run ../../mcu_soc/cvc/compare_outputs.py loom_output.vcd cvc_output.vcd +uv run ../../mcu_soc/cvc/compare_outputs.py jacquard_output.vcd cvc_output.vcd ``` **Expected results**: - Functional output: Exact match (logic correctness) -- Arrival times: Loom ≥ CVC (conservative accumulation expected) +- Arrival times: Jacquard ≥ CVC (conservative accumulation expected) - No SDF parsing errors or malformed delays **Purpose**: Pre-layout tests catch timing issues early without P&R turnaround (30+ min). Library-only delays provide floor (lower bound); post-layout adds routing parasitics for final validation. @@ -174,9 +174,9 @@ uv run ../../mcu_soc/cvc/compare_outputs.py loom_output.vcd cvc_output.vcd The main CI pipeline (`.github/workflows/ci.yml`) includes: -1. **mcu-soc-metal job**: Generates Loom timing VCD +1. **mcu-soc-metal job**: Generates Jacquard timing VCD - Includes SDF stripping step (strip_sdf_checks.py) - - Produces loom_timed_mcu.vcd with arrival time annotations + - Produces jacquard_timed_mcu.vcd with arrival time annotations 2. **mcu-soc-cvc job**: Generates CVC reference output - Uses stripped SDF (6_final_nocheck.sdf) @@ -237,7 +237,7 @@ Post-layout designs include routing delays and P&R context: **Why**: Boomerang architecture evaluates in hierarchical stages. To know Q arrival, you sum delays from all stages. -**Mitigation**: Compare Loom Q arrival against CVC RESULT: total_delay (if available), or accept that arrival times differ but functional output matches. +**Mitigation**: Compare Jacquard Q arrival against CVC RESULT: total_delay (if available), or accept that arrival times differ but functional output matches. ### 2. SDF Parser Robustness @@ -274,7 +274,7 @@ Post-layout designs include routing delays and P&R context: - Compare first 5-10 cycles after reset - Verify reset logic is synchronized -4. **Compare against Loom non-timed version**: +4. **Compare against Jacquard non-timed version**: ```bash # Run without timing VCD cargo run -r --features metal --bin jacquard -- sim \ diff --git a/scripts/chipflow_harness/README.md b/scripts/chipflow_harness/README.md index 0ecf12e..3f36ad5 100644 --- a/scripts/chipflow_harness/README.md +++ b/scripts/chipflow_harness/README.md @@ -5,7 +5,7 @@ VCD stimulus generator for ChipFlow post-synthesis simulation using GEM. ## Overview This tool converts ChipFlow's `input.json` test format into VCD waveforms suitable -for gate-level simulation with Loom. +for gate-level simulation with Jacquard. ## Installation @@ -122,7 +122,7 @@ uv run --extra dev pytest tests/ -v │ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ -│ netlist.v │───►│ loom sim │───►│ events.json │ +│ netlist.v │───►│ jacquard sim│───►│ events.json │ │ │ │ / cosim │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ ``` diff --git a/scripts/compare_timing.py b/scripts/compare_timing.py index 08a22b1..7631d9a 100644 --- a/scripts/compare_timing.py +++ b/scripts/compare_timing.py @@ -2,27 +2,27 @@ # requires-python = ">=3.10" # dependencies = [] # /// -"""Compare timing results between CVC (event-driven) and Loom (GPU) simulators. +"""Compare timing results between CVC (event-driven) and Jacquard (GPU) simulators. -Parses CVC's RESULT: lines and Loom's timed VCD to compare signal arrival -times. The primary comparison is Loom's Q arrival (full path from CLK edge +Parses CVC's RESULT: lines and Jacquard's timed VCD to compare signal arrival +times. The primary comparison is Jacquard's Q arrival (full path from CLK edge through combo logic to output register Q) vs CVC's total_delay RESULT (CLK -> dff_out.D path measured by the CVC testbench). Timing model differences: - CVC VCD: Q transitions at CLK + dff_out_CLK_to_Q (~360ps) because CVC is - event-driven and models DFF capture/output separately. - Loom VCD: Q transitions at CLK + full_combo_path (~1323ps) because Loom - propagates arrival times through the entire combinational path. + CVC VCD: Q transitions at CLK + dff_out_CLK_to_Q (~360ps) because CVC is + event-driven and models DFF capture/output separately. + Jacquard VCD: Q transitions at CLK + full_combo_path (~1323ps) because Jacquard + propagates arrival times through the entire combinational path. -So the meaningful comparison is Loom Q arrival vs CVC total_delay, NOT -Loom Q arrival vs CVC Q arrival from VCD. +So the meaningful comparison is Jacquard Q arrival vs CVC total_delay, NOT +Jacquard Q arrival vs CVC Q arrival from VCD. Usage: uv run scripts/compare_timing.py \ --cvc-log cvc_output.log \ --cvc-vcd cvc_inv_chain_output.vcd \ - --loom-vcd loom_timed_output.vcd \ + --jacquard-vcd jacquard_timed_output.vcd \ --clock-period-ps 10000 \ --clock-signal CLK \ --output-signal Q @@ -302,10 +302,10 @@ def measure_arrivals_no_clock( @dataclass class MetricComparison: - """One comparison between a CVC reference value and Loom measured value.""" + """One comparison between a CVC reference value and Jacquard measured value.""" name: str cvc_ps: int - loom_ps: int + jacquard_ps: int diff_ps: int diff_pct: float status: str # PASS, WARN, FAIL @@ -319,9 +319,9 @@ def compute_status( ) -> str: """Determine PASS/WARN/FAIL status for a timing comparison.""" if diff_ps < 0 and abs(diff_pct) > max_optimistic_pct: - return "FAIL" # Loom is optimistic (underestimates delay) + return "FAIL" # Jacquard is optimistic (underestimates delay) if diff_pct > max_conservative_pct: - return "WARN" # Loom is too conservative + return "WARN" # Jacquard is too conservative return "PASS" @@ -329,13 +329,13 @@ def format_report( cvc_results: dict[str, int], metric_comparisons: list[MetricComparison], cvc_vcd_arrivals: list[tuple[int, int, str]], - loom_vcd_arrivals: list[tuple[int, int, str]], + jacquard_vcd_arrivals: list[tuple[int, int, str]], clock_signal: str, output_signal: str, ) -> str: """Format the comparison report.""" lines: list[str] = [] - lines.append("=== Timing Comparison: CVC vs Loom (inv_chain_pnr) ===") + lines.append("=== Timing Comparison: CVC vs Jacquard (inv_chain_pnr) ===") lines.append("") # CVC reference values @@ -349,16 +349,16 @@ def format_report( lines.append("") # Primary comparison: structural metrics - lines.append("Primary Comparison (Loom Q arrival vs CVC total_delay):") - lines.append(" Loom's timed VCD propagates the full combo path delay to Q,") - lines.append(" so Loom's Q arrival corresponds to CVC's total_delay metric.") + lines.append("Primary Comparison (Jacquard Q arrival vs CVC total_delay):") + lines.append(" Jacquard's timed VCD propagates the full combo path delay to Q,") + lines.append(" so Jacquard's Q arrival corresponds to CVC's total_delay metric.") lines.append("") if metric_comparisons: - lines.append(f" | {'Metric':>20} | {'CVC (ps)':>8} | {'Loom (ps)':>9} | {'Diff (ps)':>9} | {'Diff (%)':>8} | {'Status':>6} |") - lines.append(f" |{'-'*22}|{'-'*10}|{'-'*11}|{'-'*11}|{'-'*10}|{'-'*8}|") + lines.append(f" | {'Metric':>20} | {'CVC (ps)':>8} | {'Jacquard (ps)':>13} | {'Diff (ps)':>9} | {'Diff (%)':>8} | {'Status':>6} |") + lines.append(f" |{'-'*22}|{'-'*10}|{'-'*15}|{'-'*11}|{'-'*10}|{'-'*8}|") for mc in metric_comparisons: lines.append( - f" | {mc.name:>20} | {mc.cvc_ps:>8} | {mc.loom_ps:>9} " + f" | {mc.name:>20} | {mc.cvc_ps:>8} | {mc.jacquard_ps:>13} " f"| {mc.diff_ps:>+9d} | {mc.diff_pct:>+7.1f}% | {mc.status:>6} |" ) else: @@ -370,14 +370,14 @@ def format_report( if cvc_vcd_arrivals: # Deduplicate to show unique arrival values cvc_unique = sorted(set(a for _, a, _ in cvc_vcd_arrivals)) - lines.append(f" CVC (dff_out CLK->Q only): {cvc_unique} ps") + lines.append(f" CVC (dff_out CLK->Q only): {cvc_unique} ps") else: lines.append(" CVC: (no arrivals measured)") - if loom_vcd_arrivals: - loom_unique = sorted(set(a for _, a, _ in loom_vcd_arrivals)) - lines.append(f" Loom (full combo path): {loom_unique} ps") + if jacquard_vcd_arrivals: + jq_unique = sorted(set(a for _, a, _ in jacquard_vcd_arrivals)) + lines.append(f" Jacquard (full combo path): {jq_unique} ps") else: - lines.append(" Loom: (no arrivals measured)") + lines.append(" Jacquard: (no arrivals measured)") lines.append("") # Not yet comparable @@ -385,9 +385,9 @@ def format_report( clk_to_q = cvc_results.get("clk_to_q") chain = cvc_results.get("chain_delay") if clk_to_q is not None: - lines.append(f" clk_to_q (dff_in CLK->Q): CVC={clk_to_q}ps, Loom=N/A") + lines.append(f" clk_to_q (dff_in CLK->Q): CVC={clk_to_q}ps, Jacquard=N/A") if chain is not None: - lines.append(f" chain_delay (q1->c[15]): CVC={chain}ps, Loom=N/A") + lines.append(f" chain_delay (q1->c[15]): CVC={chain}ps, Jacquard=N/A") lines.append("") # Overall result @@ -415,13 +415,13 @@ def format_report( # --------------------------------------------------------------------------- def main() -> int: - parser = argparse.ArgumentParser(description="Compare CVC vs Loom timing results") + parser = argparse.ArgumentParser(description="Compare CVC vs Jacquard timing results") parser.add_argument("--cvc-log", type=Path, required=True, help="CVC stdout log with RESULT: lines") parser.add_argument("--cvc-vcd", type=Path, required=True, help="CVC output VCD") - parser.add_argument("--loom-vcd", type=Path, required=True, - help="Loom --timing-vcd output") + parser.add_argument("--jacquard-vcd", "--loom-vcd", type=Path, required=True, + help="Jacquard --timing-vcd output") parser.add_argument("--clock-period-ps", type=int, required=True, help="Clock period in picoseconds") parser.add_argument("--clock-signal", default="CLK", @@ -442,12 +442,12 @@ def main() -> int: # Parse VCDs cvc_vcd = parse_vcd(args.cvc_vcd) - loom_vcd = parse_vcd(args.loom_vcd) + jq_vcd = parse_vcd(args.jacquard_vcd) log.info("CVC VCD: %d signals, timescale=%.0f ps", len(cvc_vcd.signals), cvc_vcd.timescale_ps) - log.info("Loom VCD: %d signals, timescale=%.0f ps", - len(loom_vcd.signals), loom_vcd.timescale_ps) + log.info("Jacquard VCD: %d signals, timescale=%.0f ps", + len(jq_vcd.signals), jq_vcd.timescale_ps) # Measure arrivals from VCDs cvc_clock = find_signal(cvc_vcd, args.clock_signal) @@ -459,38 +459,38 @@ def main() -> int: cvc_arrivals = measure_arrivals_no_clock( cvc_vcd, args.output_signal, args.clock_period_ps) - loom_clock = find_signal(loom_vcd, args.clock_signal) - if loom_clock: - loom_arrivals = measure_arrivals( - loom_vcd, args.clock_signal, args.output_signal, args.clock_period_ps) + jq_clock = find_signal(jq_vcd, args.clock_signal) + if jq_clock: + jq_arrivals = measure_arrivals( + jq_vcd, args.clock_signal, args.output_signal, args.clock_period_ps) else: - log.info("Loom VCD has no clock signal; inferring edges from period") - loom_arrivals = measure_arrivals_no_clock( - loom_vcd, args.output_signal, args.clock_period_ps) + log.info("Jacquard VCD has no clock signal; inferring edges from period") + jq_arrivals = measure_arrivals_no_clock( + jq_vcd, args.output_signal, args.clock_period_ps) log.info("CVC VCD Q arrivals: %s", cvc_arrivals) - log.info("Loom VCD Q arrivals: %s", loom_arrivals) + log.info("Jacquard VCD Q arrivals: %s", jq_arrivals) - # Primary comparison: Loom's steady-state Q arrival vs CVC total_delay - # Loom's Q arrival includes the full combo path, matching CVC's total_delay. + # Primary comparison: Jacquard's steady-state Q arrival vs CVC total_delay + # Jacquard's Q arrival includes the full combo path, matching CVC's total_delay. metric_comparisons: list[MetricComparison] = [] - # Get Loom's steady-state arrival (skip cycle 0 which may be initial state) - loom_steady = [a for c, a, _ in loom_arrivals if c > 0] - if not loom_steady: - loom_steady = [a for _, a, _ in loom_arrivals] + # Get Jacquard's steady-state arrival (skip cycle 0 which may be initial state) + jq_steady = [a for c, a, _ in jq_arrivals if c > 0] + if not jq_steady: + jq_steady = [a for _, a, _ in jq_arrivals] - if loom_steady and "total_delay" in cvc_results: - # Use the most common (modal) Loom arrival as the representative value - loom_representative = max(set(loom_steady), key=loom_steady.count) + if jq_steady and "total_delay" in cvc_results: + # Use the most common (modal) Jacquard arrival as the representative value + jq_representative = max(set(jq_steady), key=jq_steady.count) cvc_total = cvc_results["total_delay"] - diff_ps = loom_representative - cvc_total + diff_ps = jq_representative - cvc_total diff_pct = (diff_ps / cvc_total * 100) if cvc_total > 0 else 0.0 metric_comparisons.append(MetricComparison( name="Q arrival (full path)", cvc_ps=cvc_total, - loom_ps=loom_representative, + jacquard_ps=jq_representative, diff_ps=diff_ps, diff_pct=diff_pct, status=compute_status(diff_ps, diff_pct, @@ -499,7 +499,7 @@ def main() -> int: # Report report = format_report( - cvc_results, metric_comparisons, cvc_arrivals, loom_arrivals, + cvc_results, metric_comparisons, cvc_arrivals, jq_arrivals, args.clock_signal, args.output_signal) print(report) @@ -507,9 +507,9 @@ def main() -> int: if args.output_json: json_data = { "cvc_results": cvc_results, - "loom_vcd_arrivals": [ + "jacquard_vcd_arrivals": [ {"cycle": c, "arrival_ps": a, "value": v} - for c, a, v in loom_arrivals + for c, a, v in jq_arrivals ], "cvc_vcd_arrivals": [ {"cycle": c, "arrival_ps": a, "value": v} @@ -519,7 +519,7 @@ def main() -> int: { "name": mc.name, "cvc_ps": mc.cvc_ps, - "loom_ps": mc.loom_ps, + "jacquard_ps": mc.jacquard_ps, "diff_ps": mc.diff_ps, "diff_pct": mc.diff_pct, "status": mc.status, diff --git a/tests/mcu_soc/cvc/compare_simulation.py b/tests/mcu_soc/cvc/compare_simulation.py index f33687a..b8c8736 100644 --- a/tests/mcu_soc/cvc/compare_simulation.py +++ b/tests/mcu_soc/cvc/compare_simulation.py @@ -2,14 +2,14 @@ # requires-python = ">=3.10" # dependencies = [] # /// -"""Compare Loom and CVC simulation outputs for MCU SoC validation. +"""Compare Jacquard and CVC simulation outputs for MCU SoC validation. Functional comparison: Reads both VCDs, extracts gpio_out signals at each clock edge, and reports differences. Handles format differences: - - Loom: individual 1-bit signals with multi-char VCD codes (e.g., %-) + - Jacquard: individual 1-bit signals with multi-char VCD codes (e.g., %-) - CVC: 44-bit bus gpio_out[43:0] with potential X values -Timing comparison (optional): When --loom-timing-vcd is provided, compares +Timing comparison (optional): When --jacquard-timing-vcd is provided, compares sub-cycle arrival times between Jacquard and CVC, reporting statistics and identifying timing-critical transitions near clock edges. @@ -18,8 +18,8 @@ back to gpio_out[N] indices. Usage: - python3 compare_simulation.py [--skip-cycles N] [--config ] [--skip-bits 0-5] - python3 compare_simulation.py --loom-timing-vcd [...] + python3 compare_simulation.py [--skip-cycles N] [--config ] [--skip-bits 0-5] + python3 compare_simulation.py --jacquard-timing-vcd [...] """ import json @@ -53,14 +53,14 @@ def build_output_port_mapping(config_path: Path) -> dict[str, int]: return mapping -def parse_loom_vcd( +def parse_jacquard_vcd( path: Path, width: int = 44, output_port_map: dict[str, int] | None = None, ) -> VCDResult: - """Parse Loom VCD and return gpio_out value changes + last timestamp. + """Parse Jacquard VCD and return gpio_out value changes + last timestamp. - Loom VCD has individual 1-bit signals. In traditional mode: + Jacquard VCD has individual 1-bit signals. In traditional mode: $var wire 1 %- gpio_out[1] $end In port-mapped mode (Jacquard internal names): $var wire 1 %- io$soc_gpio_0_gpio$o [0] $end @@ -184,13 +184,13 @@ class BitTransition: arrival_ps: int # offset from preceding rising clock edge -def parse_loom_timing_transitions( +def parse_jacquard_timing_transitions( path: Path, clock_period: int, width: int = 44, output_port_map: dict[str, int] | None = None, ) -> list[BitTransition]: - """Parse Loom timing VCD into per-bit transitions with arrival offsets.""" + """Parse Jacquard timing VCD into per-bit transitions with arrival offsets.""" code_to_bit: dict[str, int] = {} in_header = True transitions: list[BitTransition] = [] @@ -316,14 +316,14 @@ def parse_cvc_timing_transitions( def run_timing_comparison( - loom_transitions: list[BitTransition], + jacquard_transitions: list[BitTransition], cvc_transitions: list[BitTransition], clock_period: int, skip_cycles: int, num_cycles: int, skip_bits: set[int], ) -> None: - """Compare timing between Loom and CVC transitions, print report.""" + """Compare timing between Jacquard and CVC transitions, print report.""" def group_by_cycle_bit( transitions: list[BitTransition], @@ -340,20 +340,20 @@ def group_by_cycle_bit( result[key] = t.arrival_ps return result - loom_grouped = group_by_cycle_bit(loom_transitions) + jq_grouped = group_by_cycle_bit(jacquard_transitions) cvc_grouped = group_by_cycle_bit(cvc_transitions) - common_keys = set(loom_grouped.keys()) & set(cvc_grouped.keys()) - loom_only = set(loom_grouped.keys()) - set(cvc_grouped.keys()) - cvc_only = set(cvc_grouped.keys()) - set(loom_grouped.keys()) + common_keys = set(jq_grouped.keys()) & set(cvc_grouped.keys()) + jq_only = set(jq_grouped.keys()) - set(cvc_grouped.keys()) + cvc_only = set(cvc_grouped.keys()) - set(jq_grouped.keys()) print(f"\n{'='*60}") print("Timing Comparison Report") print(f"{'='*60}") - print(f" Loom transitions (filtered): {len(loom_grouped)}") - print(f" CVC transitions (filtered): {len(cvc_grouped)}") - print(f" Common (cycle,bit) pairs: {len(common_keys)}") - print(f" Loom-only transitions: {len(loom_only)}") + print(f" Jacquard transitions (filtered): {len(jq_grouped)}") + print(f" CVC transitions (filtered): {len(cvc_grouped)}") + print(f" Common (cycle,bit) pairs: {len(common_keys)}") + print(f" Jacquard-only transitions: {len(jq_only)}") print(f" CVC-only transitions: {len(cvc_only)}") if not common_keys: @@ -361,18 +361,18 @@ def group_by_cycle_bit( print(f"{'='*60}") return - # Compute differences: (cycle, bit, cvc_arrival, loom_arrival, diff) + # Compute differences: (cycle, bit, cvc_arrival, jq_arrival, diff) diffs: list[tuple[int, int, int, int, int]] = [] for key in sorted(common_keys): cycle, bit = key cvc_arr = cvc_grouped[key] - loom_arr = loom_grouped[key] - diff = loom_arr - cvc_arr - diffs.append((cycle, bit, cvc_arr, loom_arr, diff)) + jq_arr = jq_grouped[key] + diff = jq_arr - cvc_arr + diffs.append((cycle, bit, cvc_arr, jq_arr, diff)) abs_diffs = [abs(d[4]) for d in diffs] - print(f"\n Arrival Time Differences (Loom - CVC):") + print(f"\n Arrival Time Differences (Jacquard - CVC):") print(f" Mean: {mean(abs_diffs):,.0f} ps") print(f" Median: {median(abs_diffs):,.0f} ps") print(f" Max: {max(abs_diffs):,.0f} ps") @@ -402,32 +402,32 @@ def group_by_cycle_bit( # Top discrepancies diffs_sorted = sorted(diffs, key=lambda d: abs(d[4]), reverse=True) print(f"\n Top 10 Largest Discrepancies:") - print(f" {'Cycle':>7} {'Bit':>4} {'CVC(ps)':>10} {'Loom(ps)':>10} {'Diff(ps)':>10} {'%clk':>6}") - for cycle, bit, cvc_arr, loom_arr, diff in diffs_sorted[:10]: + print(f" {'Cycle':>7} {'Bit':>4} {'CVC(ps)':>10} {'Jqrd(ps)':>10} {'Diff(ps)':>10} {'%clk':>6}") + for cycle, bit, cvc_arr, jq_arr, diff in diffs_sorted[:10]: pct = 100.0 * abs(diff) / clock_period - print(f" {cycle:>7} {bit:>4} {cvc_arr:>10,} {loom_arr:>10,} {diff:>+10,} {pct:>5.1f}%") + print(f" {cycle:>7} {bit:>4} {cvc_arr:>10,} {jq_arr:>10,} {diff:>+10,} {pct:>5.1f}%") # Timing-critical analysis near_edge_threshold = 0.8 * clock_period timing_critical: list[tuple[int, int, int, int, str]] = [] - for cycle, bit, cvc_arr, loom_arr, diff in diffs: + for cycle, bit, cvc_arr, jq_arr, diff in diffs: cvc_near = cvc_arr > near_edge_threshold - loom_near = loom_arr > near_edge_threshold - if cvc_near != loom_near: - if loom_near and not cvc_near: - reason = "Loom late (near next edge), CVC safe" + jq_near = jq_arr > near_edge_threshold + if cvc_near != jq_near: + if jq_near and not cvc_near: + reason = "Jacquard late (near next edge), CVC safe" else: - reason = "CVC late (near next edge), Loom safe" - timing_critical.append((cycle, bit, cvc_arr, loom_arr, reason)) + reason = "CVC late (near next edge), Jacquard safe" + timing_critical.append((cycle, bit, cvc_arr, jq_arr, reason)) # Check for transitions captured in different cycles edge_crossings: list[tuple[int, int, int, int]] = [] - for cycle, bit, cvc_arr, loom_arr, diff in diffs: + for cycle, bit, cvc_arr, jq_arr, diff in diffs: cvc_same = cvc_arr < clock_period - loom_same = loom_arr < clock_period - if cvc_same != loom_same: - edge_crossings.append((cycle, bit, cvc_arr, loom_arr)) + jq_same = jq_arr < clock_period + if cvc_same != jq_same: + edge_crossings.append((cycle, bit, cvc_arr, jq_arr)) print(f"\n Timing-Critical Analysis:") print(f" Near-edge threshold: {near_edge_threshold:,.0f} ps " @@ -436,9 +436,9 @@ def group_by_cycle_bit( f"{len(timing_critical)}") if timing_critical: - print(f"\n {'Cycle':>7} {'Bit':>4} {'CVC(ps)':>10} {'Loom(ps)':>10} Issue") - for cycle, bit, cvc_arr, loom_arr, reason in timing_critical[:20]: - print(f" {cycle:>7} {bit:>4} {cvc_arr:>10,} {loom_arr:>10,} " + print(f"\n {'Cycle':>7} {'Bit':>4} {'CVC(ps)':>10} {'Jqrd(ps)':>10} Issue") + for cycle, bit, cvc_arr, jq_arr, reason in timing_critical[:20]: + print(f" {cycle:>7} {bit:>4} {cvc_arr:>10,} {jq_arr:>10,} " f"{reason}") if len(timing_critical) > 20: print(f" ... ({len(timing_critical) - 20} more)") @@ -446,9 +446,9 @@ def group_by_cycle_bit( if edge_crossings: print(f"\n Clock edge crossings (different cycle capture): " f"{len(edge_crossings)}") - print(f" {'Cycle':>7} {'Bit':>4} {'CVC(ps)':>10} {'Loom(ps)':>10}") - for cycle, bit, cvc_arr, loom_arr in edge_crossings[:10]: - print(f" {cycle:>7} {bit:>4} {cvc_arr:>10,} {loom_arr:>10,}") + print(f" {'Cycle':>7} {'Bit':>4} {'CVC(ps)':>10} {'Jqrd(ps)':>10}") + for cycle, bit, cvc_arr, jq_arr in edge_crossings[:10]: + print(f" {cycle:>7} {bit:>4} {cvc_arr:>10,} {jq_arr:>10,}") if len(edge_crossings) > 10: print(f" ... ({len(edge_crossings) - 10} more)") else: @@ -465,7 +465,7 @@ def main() -> None: config_path: Path | None = None num_cycles_override: int | None = None skip_bits: set[int] = set() - loom_timing_vcd: Path | None = None + jacquard_timing_vcd: Path | None = None cvc_timing_vcd: Path | None = None positional: list[str] = [] @@ -489,8 +489,8 @@ def main() -> None: else: skip_bits.add(int(part)) i += 2 - elif args[i] == "--loom-timing-vcd" and i + 1 < len(args): - loom_timing_vcd = Path(args[i + 1]) + elif args[i] in ("--jacquard-timing-vcd", "--loom-timing-vcd") and i + 1 < len(args): + jacquard_timing_vcd = Path(args[i + 1]) i += 2 elif args[i] == "--cvc-timing-vcd" and i + 1 < len(args): cvc_timing_vcd = Path(args[i + 1]) @@ -501,13 +501,13 @@ def main() -> None: if len(positional) < 2: print( - f"Usage: {sys.argv[0]} [--skip-cycles N] " + f"Usage: {sys.argv[0]} [--skip-cycles N] " f"[--config ] [--num-cycles N] [--skip-bits 0-5]", file=sys.stderr, ) sys.exit(1) - loom_path = Path(positional[0]) + jacquard_path = Path(positional[0]) cvc_path = Path(positional[1]) output_port_map: dict[str, int] | None = None @@ -517,10 +517,10 @@ def main() -> None: clock_period = 40000 # ps - print(f"Parsing Loom VCD: {loom_path}") - loom_result = parse_loom_vcd(loom_path, output_port_map=output_port_map) - loom_changes = loom_result.changes - print(f" {len(loom_changes)} gpio_out value changes, last_time={loom_result.last_time}ps") + print(f"Parsing Jacquard VCD: {jacquard_path}") + jq_result = parse_jacquard_vcd(jacquard_path, output_port_map=output_port_map) + jq_changes = jq_result.changes + print(f" {len(jq_changes)} gpio_out value changes, last_time={jq_result.last_time}ps") print(f"Parsing CVC VCD: {cvc_path}") cvc_result = parse_cvc_vcd(cvc_path) @@ -534,7 +534,7 @@ def main() -> None: print(f" Using explicit cycle count: {num_cycles}") else: # Use the minimum of both last timestamps as the comparison range - max_time = min(loom_result.last_time, cvc_result.last_time) + max_time = min(jq_result.last_time, cvc_result.last_time) num_cycles = max_time // clock_period + 1 # Build per-cycle values by interpolating from change lists @@ -553,7 +553,7 @@ def build_cycle_values( values[cycle] = current_val return values - loom_values = build_cycle_values(loom_changes, num_cycles) + jq_values = build_cycle_values(jq_changes, num_cycles) cvc_values = build_cycle_values(cvc_changes, num_cycles) # Build comparison mask (exclude skip_bits) @@ -569,7 +569,7 @@ def build_cycle_values( first_mismatch = None for cycle in range(skip_cycles, num_cycles): - lv = loom_values[cycle] & compare_mask + lv = jq_values[cycle] & compare_mask cv = cvc_values[cycle] & compare_mask if lv == cv: matches += 1 @@ -580,7 +580,7 @@ def build_cycle_values( diff_bits = [i for i in range(44) if diff & (1 << i) and i not in skip_bits] t = cycle * clock_period print(f"\n MISMATCH at cycle {cycle} (t={t}ps):") - print(f" Loom: 0x{lv:011x}") + print(f" Jacquard: 0x{lv:011x}") print(f" CVC: 0x{cv:011x}") print(f" Diff bits: {diff_bits}") if first_mismatch is None: @@ -603,13 +603,13 @@ def build_cycle_values( print(f"{'='*60}") # --- Timing comparison (optional, informational only) --- - if loom_timing_vcd: + if jacquard_timing_vcd: # Default CVC timing VCD to the same functional CVC VCD cvc_timing_path = cvc_timing_vcd if cvc_timing_vcd else cvc_path - print(f"\nParsing Loom timing VCD: {loom_timing_vcd}") - loom_timing = parse_loom_timing_transitions( - loom_timing_vcd, clock_period, output_port_map=output_port_map, + print(f"\nParsing Jacquard timing VCD: {jacquard_timing_vcd}") + jq_timing = parse_jacquard_timing_transitions( + jacquard_timing_vcd, clock_period, output_port_map=output_port_map, ) print(f"Parsing CVC timing VCD: {cvc_timing_path}") @@ -618,7 +618,7 @@ def build_cycle_values( ) run_timing_comparison( - loom_timing, cvc_timing, clock_period, + jq_timing, cvc_timing, clock_period, skip_cycles, num_cycles, skip_bits, ) diff --git a/tests/mcu_soc/cvc/convert_stimulus.py b/tests/mcu_soc/cvc/convert_stimulus.py index 470de2e..6880dff 100644 --- a/tests/mcu_soc/cvc/convert_stimulus.py +++ b/tests/mcu_soc/cvc/convert_stimulus.py @@ -2,9 +2,9 @@ # requires-python = ">=3.10" # dependencies = [] # /// -"""Convert a Loom stimulus VCD to Verilog timed assignments for CVC. +"""Convert a Jacquard stimulus VCD to Verilog timed assignments for CVC. -Reads the stimulus VCD (generated by `loom cosim --stimulus-vcd`) and produces +Reads the stimulus VCD (generated by `jacquard cosim --stimulus-vcd`) and produces a Verilog include file with delay-based `initial begin ... end` blocks that drive the DUT ports. @@ -168,7 +168,7 @@ def generate_verilog( scalar_ports.add(port_name) with open(output_path, 'w') as f: - f.write("// Auto-generated stimulus from Loom cosim VCD\n") + f.write("// Auto-generated stimulus from Jacquard cosim VCD\n") f.write(f"// Source: stimulus.vcd\n") f.write(f"// Signals: {len(id_to_name)}, Events: {len(events)}\n") f.write(f"// Ports: {sorted(port_widths.keys())} + {sorted(scalar_ports)}\n\n") diff --git a/tests/mcu_soc/cvc/gen_cell_models.py b/tests/mcu_soc/cvc/gen_cell_models.py index c2c7667..f38b50a 100644 --- a/tests/mcu_soc/cvc/gen_cell_models.py +++ b/tests/mcu_soc/cvc/gen_cell_models.py @@ -210,7 +210,7 @@ def read_udp(udp_dir_name: str) -> str | None: udp_text = match.group(1) - # Initialize DFF UDPs to 0 (matching Loom's 0-initialization). + # Initialize DFF UDPs to 0 (matching Jacquard's 0-initialization). # Without this, CVC starts all DFF outputs at X and X-propagation # prevents the design from functioning during comparison. udp_text = re.sub( diff --git a/tests/mcu_soc/cvc/run_cvc.sh b/tests/mcu_soc/cvc/run_cvc.sh index 177c12b..043569d 100644 --- a/tests/mcu_soc/cvc/run_cvc.sh +++ b/tests/mcu_soc/cvc/run_cvc.sh @@ -6,7 +6,7 @@ # # Prerequisites: # 1. Generate stimulus VCD: -# cargo run -r --features metal --bin loom -- cosim \ +# cargo run -r --features metal --bin jacquard -- cosim \ # tests/mcu_soc/data/6_final.v \ # --config tests/mcu_soc/sim_config_sky130.json \ # --top-module openframe_project_wrapper \ @@ -32,7 +32,7 @@ REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" DATA_DIR="$REPO_ROOT/tests/mcu_soc/data" CVC_DIR="$SCRIPT_DIR" OUTPUT_DIR="$CVC_DIR/output" -IMAGE_NAME="loom-cvc" +IMAGE_NAME="jacquard-cvc" mkdir -p "$OUTPUT_DIR" diff --git a/tests/mcu_soc/cvc/stimulus_gen.v b/tests/mcu_soc/cvc/stimulus_gen.v index ccf335e..81ec7d3 100644 --- a/tests/mcu_soc/cvc/stimulus_gen.v +++ b/tests/mcu_soc/cvc/stimulus_gen.v @@ -1,4 +1,4 @@ -// Auto-generated stimulus from Loom cosim VCD +// Auto-generated stimulus from Jacquard cosim VCD // Source: stimulus.vcd // Signals: 301, Events: 2001 // Ports: ['gpio_in', 'gpio_in_h', 'gpio_loopback_one', 'gpio_loopback_zero', 'mask_rev'] + ['por_l', 'porb_h', 'porb_l', 'resetb_h', 'resetb_l'] diff --git a/tests/mcu_soc/cvc/stimulus_gen_new.v b/tests/mcu_soc/cvc/stimulus_gen_new.v index 8ac9c8f..cb3abf1 100644 --- a/tests/mcu_soc/cvc/stimulus_gen_new.v +++ b/tests/mcu_soc/cvc/stimulus_gen_new.v @@ -1,4 +1,4 @@ -// Auto-generated stimulus from Loom cosim VCD +// Auto-generated stimulus from Jacquard cosim VCD // Source: stimulus.vcd // Signals: 19, Events: 20001 // Ports: ['gpio_in'] + [] diff --git a/tests/mcu_soc/cvc/strip_sdf_checks.py b/tests/mcu_soc/cvc/strip_sdf_checks.py index 41fd389..fcf4b2c 100644 --- a/tests/mcu_soc/cvc/strip_sdf_checks.py +++ b/tests/mcu_soc/cvc/strip_sdf_checks.py @@ -6,7 +6,7 @@ CVC requires matching specify-block timing checks for every SDF TIMINGCHECK entry, and has trouble with escaped port names in INTERCONNECT entries. -For initial Loom vs CVC waveform comparison, IOPATH delays suffice. +For initial Jacquard vs CVC waveform comparison, IOPATH delays suffice. Strips: - TIMINGCHECK blocks (no matching specify checks) diff --git a/tests/mcu_soc/cvc/tb_cvc.v b/tests/mcu_soc/cvc/tb_cvc.v index e73b180..3b0dcdb 100644 --- a/tests/mcu_soc/cvc/tb_cvc.v +++ b/tests/mcu_soc/cvc/tb_cvc.v @@ -1,17 +1,17 @@ // CVC SDF-annotated testbench for MCU SoC timing validation. // -// Replays stimulus captured from Loom cosim and compares against CVC's +// Replays stimulus captured from Jacquard cosim and compares against CVC's // event-driven SDF simulation as a reference. // // Setup: -// 1. Generate stimulus: loom cosim ... --stimulus-vcd stimulus.vcd +// 1. Generate stimulus: jacquard cosim ... --stimulus-vcd stimulus.vcd // 2. Convert: uv run convert_stimulus.py stimulus.vcd stimulus_gen.v // 3. Generate cell models: uv run gen_cell_models.py // 4. Run CVC: // cvc64 +typdelays tb_cvc.v sky130_cells.v 6_final.v && ./cvcsim // // Outputs: -// cvc_output.vcd — GPIO output waveforms for comparison with Loom +// cvc_output.vcd — GPIO output waveforms for comparison with Jacquard `timescale 1ps/1ps @@ -107,7 +107,7 @@ module tb_cvc; mask_rev = 32'h0; end - // ---- Stimulus (generated from Loom cosim VCD) ---- + // ---- Stimulus (generated from Jacquard cosim VCD) ---- `include "stimulus_gen.v" endmodule diff --git a/tests/timing_test/cvc/Dockerfile b/tests/timing_test/cvc/Dockerfile index a2f674a..5cc8146 100644 --- a/tests/timing_test/cvc/Dockerfile +++ b/tests/timing_test/cvc/Dockerfile @@ -1,5 +1,5 @@ # CVC (open-src-cvc) Verilog simulator for SDF timing validation. -# Build: docker build --platform linux/amd64 -t loom-cvc tests/timing_test/cvc +# Build: docker build --platform linux/amd64 -t jacquard-cvc tests/timing_test/cvc # # CVC compiles Verilog to native machine code, so the runtime image # needs gcc and binutils in addition to the cvc64 binary. diff --git a/tests/timing_test/cvc/run_cvc.sh b/tests/timing_test/cvc/run_cvc.sh index c1a040a..6700c56 100644 --- a/tests/timing_test/cvc/run_cvc.sh +++ b/tests/timing_test/cvc/run_cvc.sh @@ -6,7 +6,7 @@ # # Builds the CVC Docker image (cached after first run), then runs the # inv_chain testbench with SDF back-annotation. Compares the reported -# total delay against Loom's expected 1323ps. +# total delay against Jacquard's expected 1323ps. # # Outputs: # tests/timing_test/cvc/output/cvc_output.log (stdout from CVC sim) @@ -18,7 +18,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" INV_CHAIN_DIR="$REPO_ROOT/tests/timing_test/inv_chain_pnr" OUTPUT_DIR="$SCRIPT_DIR/output" -IMAGE_NAME="loom-cvc" +IMAGE_NAME="jacquard-cvc" mkdir -p "$OUTPUT_DIR" @@ -60,17 +60,17 @@ if grep -q "RESULT: total_delay=" "$OUTPUT_DIR/cvc_output.log"; then CVC_CHAIN=$(grep "RESULT: chain_delay=" "$OUTPUT_DIR/cvc_output.log" | sed 's/.*=//') LOOM_TOTAL=1323 echo "CVC: clk_to_q=${CVC_CLK_TO_Q}ps chain=${CVC_CHAIN}ps total=${CVC_TOTAL}ps" - echo "Loom: clk_to_q=350ps chain=973ps total=${LOOM_TOTAL}ps" + echo "Jacquard: clk_to_q=350ps chain=973ps total=${LOOM_TOTAL}ps" echo "" - # Loom uses max(rise, fall) per cell — a conservative approximation since + # Jacquard uses max(rise, fall) per cell — a conservative approximation since # the GPU kernel processes 32 packed signals and can't track per-signal # transition direction. CVC tracks actual rise/fall transitions. # Expected overestimate: 8 inverters × 10ps IOPATH + 8 wires × 1ps = 88ps. DIFF=$((LOOM_TOTAL - CVC_TOTAL)) - echo "Difference: ${DIFF}ps (Loom conservative overestimate)" + echo "Difference: ${DIFF}ps (Jacquard conservative overestimate)" if [ "$DIFF" -ge 0 ] && [ "$DIFF" -le 200 ]; then - echo "PASS: Loom within expected conservative bound" + echo "PASS: Jacquard within expected conservative bound" else echo "FAIL: Unexpected difference (expected 0-200ps overestimate)" exit 1 diff --git a/tests/timing_test/inv_chain_pnr/inv_chain_stimulus.vcd b/tests/timing_test/inv_chain_pnr/inv_chain_stimulus.vcd index b26c561..c3eab95 100644 --- a/tests/timing_test/inv_chain_pnr/inv_chain_stimulus.vcd +++ b/tests/timing_test/inv_chain_pnr/inv_chain_stimulus.vcd @@ -2,7 +2,7 @@ $date Fri Feb 28 00:00:00 2026 $end $version - Loom test stimulus + Jacquard test stimulus $end $timescale 1ps diff --git a/tests/timing_test/inv_chain_pnr/tb_cvc.v b/tests/timing_test/inv_chain_pnr/tb_cvc.v index e37ae5d..aa01faa 100644 --- a/tests/timing_test/inv_chain_pnr/tb_cvc.v +++ b/tests/timing_test/inv_chain_pnr/tb_cvc.v @@ -83,7 +83,7 @@ module tb_cvc; forever #5000 CLK = ~CLK; end - // Stimulus: matches the pattern used by inv_chain_stimulus.vcd for Loom + // Stimulus: matches the pattern used by inv_chain_stimulus.vcd for Jacquard // Cycle 0: D=0 latched // Cycle 1: D=1 latched (set D=1 shortly after cycle 0 clock edge) // Cycle 2: D=0 latched (set D=0 shortly after cycle 1 clock edge) diff --git a/tests/timing_test/multi_depth/multi_depth_stimulus.vcd b/tests/timing_test/multi_depth/multi_depth_stimulus.vcd index c7cf75b..ebcf500 100644 --- a/tests/timing_test/multi_depth/multi_depth_stimulus.vcd +++ b/tests/timing_test/multi_depth/multi_depth_stimulus.vcd @@ -2,7 +2,7 @@ $date Thu Feb 27 00:00:00 2026 $end $version - Loom test stimulus + Jacquard test stimulus $end $timescale 1ps diff --git a/tests/timing_test/multi_depth/run_cvc_multi_depth.sh b/tests/timing_test/multi_depth/run_cvc_multi_depth.sh index bd776e3..fac8edf 100644 --- a/tests/timing_test/multi_depth/run_cvc_multi_depth.sh +++ b/tests/timing_test/multi_depth/run_cvc_multi_depth.sh @@ -6,7 +6,7 @@ # # Builds the CVC Docker image (cached after first run), then runs the # multi_depth testbench with SDF back-annotation. Reports per-group -# arrival times for comparison against Loom's timing simulation. +# arrival times for comparison against Jacquard's timing simulation. # # Outputs: # tests/timing_test/multi_depth/cvc_output.log (stdout from CVC sim) @@ -18,7 +18,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" MULTI_DEPTH_DIR="$SCRIPT_DIR" CVC_DIR="$REPO_ROOT/tests/timing_test/cvc" -IMAGE_NAME="loom-cvc" +IMAGE_NAME="jacquard-cvc" # Build the CVC image if not present (reuses same Dockerfile as inv_chain) if ! docker image inspect "$IMAGE_NAME" > /dev/null 2>&1; then diff --git a/tests/timing_test/multi_depth/tb_cvc.v b/tests/timing_test/multi_depth/tb_cvc.v index e5fe0e5..ccf2910 100644 --- a/tests/timing_test/multi_depth/tb_cvc.v +++ b/tests/timing_test/multi_depth/tb_cvc.v @@ -66,7 +66,7 @@ module tb_cvc; .out(out) ); - // VCD output for comparison with Loom + // VCD output for comparison with Jacquard initial begin $dumpfile("cvc_multi_depth_output.vcd"); $dumpvars(0, uut); diff --git a/tests/timing_test/sky130_timing/Makefile b/tests/timing_test/sky130_timing/Makefile index 13d12c5..3c2e690 100644 --- a/tests/timing_test/sky130_timing/Makefile +++ b/tests/timing_test/sky130_timing/Makefile @@ -5,7 +5,7 @@ all: inv_chain.v.gv logic_cone.v.gv inv_chain.sdf logic_cone.sdf -# Convert Verilog to AIG graph format for loom +# Convert Verilog to AIG graph format for Jacquard %.v.gv: %.v @echo "Converting $< to AIG..." cargo run -r --bin jacquard -- map $< > $@ 2>&1 || { \ diff --git a/tests/timing_test/sky130_timing/README.md b/tests/timing_test/sky130_timing/README.md index a88efb8..3bb4b7e 100644 --- a/tests/timing_test/sky130_timing/README.md +++ b/tests/timing_test/sky130_timing/README.md @@ -61,7 +61,7 @@ only combinational path delays and setup/hold times from library timing models. ### Run with CVC ```sh -# Run with CVC (requires open-src-cvc Docker image: loom-cvc) +# Run with CVC (requires open-src-cvc Docker image: jacquard-cvc) cvc64 +typdelays tb_inv_chain.v inv_chain.v ./cvcsim @@ -69,13 +69,13 @@ cvc64 +typdelays tb_logic_cone.v logic_cone.v ./cvcsim ``` -### Compare Loom vs CVC +### Compare Jacquard vs CVC -Use the comparison script in the parent directory to validate that Loom's +Use the comparison script in the parent directory to validate that Jacquard's GPU timing simulation matches CVC's reference timing: ```sh -bash ../inv_chain_pnr/../compare_timing.py cvc_output.vcd loom_output.vcd +bash ../inv_chain_pnr/../compare_timing.py cvc_output.vcd jacquard_output.vcd ``` ## Files diff --git a/tests/timing_test/sky130_timing/gen_liberty_sdf.py b/tests/timing_test/sky130_timing/gen_liberty_sdf.py index 7c93834..4475763 100644 --- a/tests/timing_test/sky130_timing/gen_liberty_sdf.py +++ b/tests/timing_test/sky130_timing/gen_liberty_sdf.py @@ -75,7 +75,7 @@ def gen_sdf_header(design_name): return f"""(SDFVERSION "3.0") (DESIGN "{design_name}") (DATE "{design_name} pre-layout Liberty-only SDF") -(VENDOR "Loom") +(VENDOR "Jacquard") (PROGRAM "gen_liberty_sdf.py") (VERSION "1.0") (HIERARCHY "{design_name}") diff --git a/tests/timing_test/sky130_timing/inv_chain.sdf b/tests/timing_test/sky130_timing/inv_chain.sdf index 847e414..a54bb70 100644 --- a/tests/timing_test/sky130_timing/inv_chain.sdf +++ b/tests/timing_test/sky130_timing/inv_chain.sdf @@ -1,7 +1,7 @@ (SDFVERSION "3.0") (DESIGN "inv_chain") (DATE "inv_chain pre-layout Liberty-only SDF") -(VENDOR "Loom") +(VENDOR "Jacquard") (PROGRAM "gen_liberty_sdf.py") (VERSION "1.0") (HIERARCHY "inv_chain") diff --git a/tests/timing_test/sky130_timing/logic_cone.sdf b/tests/timing_test/sky130_timing/logic_cone.sdf index a2e6477..5fff0f0 100644 --- a/tests/timing_test/sky130_timing/logic_cone.sdf +++ b/tests/timing_test/sky130_timing/logic_cone.sdf @@ -1,7 +1,7 @@ (SDFVERSION "3.0") (DESIGN "logic_cone") (DATE "logic_cone pre-layout Liberty-only SDF") -(VENDOR "Loom") +(VENDOR "Jacquard") (PROGRAM "gen_liberty_sdf.py") (VERSION "1.0") (HIERARCHY "logic_cone")