From 7a0742f47b90ff9337c1bb7f334627354a449eca Mon Sep 17 00:00:00 2001 From: deaneeth Date: Fri, 5 Jun 2026 21:21:01 +0530 Subject: [PATCH 1/7] ci(rtl): add RTL CI workflow with Verilator 5.036 and cocotb test suites Adds .github/workflows/rtl.yml, triggered on push/PR to rtl/** or sim/**. Ubuntu 24.04 apt ships Verilator 5.020, but cocotb 2.x requires >= 5.036. Build Verilator v5.036 from source on first run and cache the install prefix by version tag so subsequent runs skip the ~5 min build step. Steps: - Lint RTL with `verilator --lint-only -Wall rtl/*.sv` - Run `pytest sim/golden.py -q` (numpy golden reference) - cocotb test_pe, test_systolic_array, test_top via make (WAVES=0 for speed) Removes .github/workflows/.gitkeep placeholder now that real files exist. --- .github/workflows/.gitkeep | 0 .github/workflows/rtl.yml | 76 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) delete mode 100644 .github/workflows/.gitkeep create mode 100644 .github/workflows/rtl.yml diff --git a/.github/workflows/.gitkeep b/.github/workflows/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/.github/workflows/rtl.yml b/.github/workflows/rtl.yml new file mode 100644 index 0000000..3b78719 --- /dev/null +++ b/.github/workflows/rtl.yml @@ -0,0 +1,76 @@ +name: RTL CI + +on: + push: + paths: + - 'rtl/**' + - 'sim/**' + - '.github/workflows/rtl.yml' + pull_request: + paths: + - 'rtl/**' + - 'sim/**' + - '.github/workflows/rtl.yml' + +jobs: + rtl-ci: + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + # cocotb 2.x requires Verilator >= 5.036; the ubuntu-24.04 apt package + # is only 5.020, so we build from source and cache by version tag. + - name: Cache Verilator build + id: cache-verilator + uses: actions/cache@v4 + with: + path: ~/verilator-install + key: verilator-v5.036-ubuntu-24.04 + + - name: Build Verilator v5.036 from source + if: steps.cache-verilator.outputs.cache-hit != 'true' + run: | + sudo apt-get update -qq + sudo apt-get install -y autoconf flex bison libfl2 libfl-dev help2man perl + git clone --depth 1 --branch v5.036 https://github.com/verilator/verilator.git /tmp/verilator + cd /tmp/verilator + autoconf + ./configure --prefix="$HOME/verilator-install" + make -j$(nproc) + make install + + - name: Add Verilator to PATH + run: echo "$HOME/verilator-install/bin" >> $GITHUB_PATH + + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Python deps + run: pip install cocotb numpy pytest + + - name: Lint RTL + run: verilator --lint-only -Wall rtl/*.sv + + - name: Golden model tests + run: pytest sim/golden.py -q + + - name: cocotb — PE + working-directory: sim + run: make MODULE=test_pe TOPLEVEL=pe WAVES=0 + + - name: cocotb — Systolic Array + working-directory: sim + run: | + make MODULE=test_systolic_array TOPLEVEL=systolic_array \ + VERILOG_SOURCES="../rtl/pe.sv ../rtl/systolic_array.sv" \ + WAVES=0 + + - name: cocotb — Top (full matmul vs golden) + working-directory: sim + run: | + make MODULE=test_top TOPLEVEL=tiny_tpu_top \ + VERILOG_SOURCES="../rtl/pe.sv ../rtl/systolic_array.sv \ + ../rtl/controller.sv ../rtl/tiny_tpu_top.sv" \ + WAVES=0 From 637fb448e3c2bccfb164f8f45f34bab7df94c89b Mon Sep 17 00:00:00 2001 From: deaneeth Date: Fri, 5 Jun 2026 21:21:27 +0530 Subject: [PATCH 2/7] ci(web): add web CI workflow with pnpm store caching Adds .github/workflows/web.yml, triggered on push/PR to web/**. Uses pnpm/action-setup@v4 (pnpm 11) + actions/setup-node@v4 (Node 22) with `cache: pnpm` pointing at web/pnpm-lock.yaml to avoid full reinstalls on unchanged dependencies. Runs in order: pnpm install --frozen-lockfile, pnpm lint, pnpm typecheck, pnpm build. All three must pass; build failure surfaces SSR/WASM import errors that wouldn't otherwise be caught locally. --- .github/workflows/web.yml | 44 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/web.yml diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml new file mode 100644 index 0000000..6db9bce --- /dev/null +++ b/.github/workflows/web.yml @@ -0,0 +1,44 @@ +name: Web CI + +on: + push: + paths: + - 'web/**' + - '.github/workflows/web.yml' + pull_request: + paths: + - 'web/**' + - '.github/workflows/web.yml' + +jobs: + web-ci: + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + with: + version: '11' + + - uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'pnpm' + cache-dependency-path: web/pnpm-lock.yaml + + - name: Install dependencies + working-directory: web + run: pnpm install --frozen-lockfile + + - name: Lint + working-directory: web + run: pnpm lint + + - name: Type check + working-directory: web + run: pnpm typecheck + + - name: Build + working-directory: web + run: pnpm build From 66b998574a24eb5acbaab8e72b453755efbcdf04 Mon Sep 17 00:00:00 2001 From: deaneeth Date: Fri, 5 Jun 2026 21:21:52 +0530 Subject: [PATCH 3/7] ci(wasm): add WASM build CI workflow with emsdk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds .github/workflows/wasm.yml, triggered on push/PR to rtl/** or wasm/**. Installs Verilator 5.020 from apt (sufficient for the WASM build path — cocotb's version gate only applies to the simulation Makefile, not the em++ compilation step) and Emscripten via mymindstorm/setup-emsdk@v14. Runs wasm/build.sh and asserts both web/public/tiny_tpu.mjs and web/public/tiny_tpu.wasm are produced. Does not commit artifacts from CI; they must be committed manually after local rebuilds. --- .github/workflows/wasm.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/wasm.yml diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml new file mode 100644 index 0000000..b0049dd --- /dev/null +++ b/.github/workflows/wasm.yml @@ -0,0 +1,37 @@ +name: WASM Build + +on: + push: + paths: + - 'rtl/**' + - 'wasm/**' + - '.github/workflows/wasm.yml' + pull_request: + paths: + - 'rtl/**' + - 'wasm/**' + - '.github/workflows/wasm.yml' + +jobs: + wasm-build: + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - name: Install Verilator and build deps + run: | + sudo apt-get update + sudo apt-get install -y verilator build-essential + + - name: Set up Emscripten + uses: mymindstorm/setup-emsdk@v14 + + - name: Build WASM + run: bash wasm/build.sh + + - name: Assert artifacts produced + run: | + test -f web/public/tiny_tpu.mjs || (echo "ERROR: tiny_tpu.mjs not produced" && exit 1) + test -f web/public/tiny_tpu.wasm || (echo "ERROR: tiny_tpu.wasm not produced" && exit 1) + echo "WASM artifacts verified: $(du -sh web/public/tiny_tpu.wasm | cut -f1) wasm" From e1988f56754adc77e35446cd1a444e4ba38b75d3 Mon Sep 17 00:00:00 2001 From: deaneeth Date: Fri, 5 Jun 2026 21:22:09 +0530 Subject: [PATCH 4/7] docs(ci): add CI status badge row to README header Adds a second badge row beneath the tech-stack badges with live status links for the three new GitHub Actions workflows: RTL CI, Web CI, and WASM Build. Badges link directly to the workflow run list so viewers can inspect recent results without leaving the README. --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 825471c..b6177c2 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,12 @@ TypeScript strict

+

+ RTL CI + Web CI + WASM Build +

+

Open Live Visualizer From 77617ce37ed1e59b1dee962cb42c96c493553055 Mon Sep 17 00:00:00 2001 From: deaneeth Date: Fri, 5 Jun 2026 21:22:36 +0530 Subject: [PATCH 5/7] chore(deploy): add vercel.json with WASM MIME type and cache headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vercel may serve .wasm files as text/html without an explicit header rule, which causes the browser to reject the module with a MIME type error and shows a blank visualizer. The headers block pins Content-Type to application/wasm for tiny_tpu.wasm and application/javascript for tiny_tpu.mjs, ensuring correct browser parsing in production. Also sets Cache-Control: immutable on both artifacts — they are content- addressed by the WASM build process so long-lived caching is safe. vercel.json is placed inside web/ (the configured Vercel root directory). --- web/vercel.json | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 web/vercel.json diff --git a/web/vercel.json b/web/vercel.json new file mode 100644 index 0000000..c406c49 --- /dev/null +++ b/web/vercel.json @@ -0,0 +1,30 @@ +{ + "headers": [ + { + "source": "/tiny_tpu.wasm", + "headers": [ + { + "key": "Content-Type", + "value": "application/wasm" + }, + { + "key": "Cache-Control", + "value": "public, max-age=31536000, immutable" + } + ] + }, + { + "source": "/tiny_tpu.mjs", + "headers": [ + { + "key": "Content-Type", + "value": "application/javascript; charset=utf-8" + }, + { + "key": "Cache-Control", + "value": "public, max-age=31536000, immutable" + } + ] + } + ] +} From 15747c022be5793fa8a83ac8fe7e40d6cddb74e3 Mon Sep 17 00:00:00 2001 From: deaneeth Date: Fri, 5 Jun 2026 21:23:02 +0530 Subject: [PATCH 6/7] fix(lint): fix ESLint errors in gen-og-image.mjs Two issues in the OG image generation script broke `pnpm lint`: 1. Unused variable: `fill` was computed in peCell() but the SVG template later switched to inline hardcoded hex values. Removed the dead declaration so no-unused-vars is satisfied. 2. Undeclared globals: `console` and `Buffer` are Node.js globals, but the ESLint config only injected browser + es2022 globals for .ts/.tsx files. Added a separate config block for scripts/**/*.mjs with globals.node so these built-ins are recognised without any eslint-disable comments. `pnpm lint`, `pnpm typecheck`, and `pnpm build` all pass after this fix. --- web/eslint.config.js | 9 +++++++++ web/scripts/gen-og-image.mjs | 5 ----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/web/eslint.config.js b/web/eslint.config.js index d65fbb3..647ded7 100644 --- a/web/eslint.config.js +++ b/web/eslint.config.js @@ -39,6 +39,15 @@ export default [ react: { version: "detect" }, }, }, + { + files: ["scripts/**/*.mjs", "scripts/**/*.js"], + languageOptions: { + globals: { + ...globals.node, + ...globals.es2022, + }, + }, + }, { ignores: ["dist/", ".astro/", "node_modules/", "public/"], }, diff --git a/web/scripts/gen-og-image.mjs b/web/scripts/gen-og-image.mjs index 9538829..268711d 100644 --- a/web/scripts/gen-og-image.mjs +++ b/web/scripts/gen-og-image.mjs @@ -38,11 +38,6 @@ function peCell(row, col) { const y = GRID_Y + row * (CELL + CELL_GAP); const isDiag = row === col; const isLoading = row === col + 1; - const fill = isDiag - ? `color-mix(in oklch, ${LIME} 9%, ${SURFACE})` - : isLoading - ? SURFACE - : SURFACE; const stroke = isDiag ? LIME : isLoading From bf805463d2375fe7f38aff1eb9f36158428b02dc Mon Sep 17 00:00:00 2001 From: deaneeth Date: Fri, 5 Jun 2026 21:54:44 +0530 Subject: [PATCH 7/7] fix(ci): isolate cocotb sim_build dirs to prevent stale toplevel reuse cocotb does not detect when TOPLEVEL changes between sequential make runs sharing the same sim_build/ directory. The PE test compiled sim_build/Vtop for module `pe`; the systolic array test then reused that binary and crashed at runtime with "root handle systolic_array != pe". Fix: pass SIM_BUILD=sim_build/ to each make invocation so every test suite compiles into its own isolated directory. --- .github/workflows/rtl.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rtl.yml b/.github/workflows/rtl.yml index 3b78719..e92718e 100644 --- a/.github/workflows/rtl.yml +++ b/.github/workflows/rtl.yml @@ -56,16 +56,19 @@ jobs: - name: Golden model tests run: pytest sim/golden.py -q + # Each suite gets its own SIM_BUILD directory. cocotb does not detect a + # TOPLEVEL change across runs sharing the same sim_build/ — it reuses the + # previous binary, which causes "root handle not found" at runtime. - name: cocotb — PE working-directory: sim - run: make MODULE=test_pe TOPLEVEL=pe WAVES=0 + run: make MODULE=test_pe TOPLEVEL=pe WAVES=0 SIM_BUILD=sim_build/pe - name: cocotb — Systolic Array working-directory: sim run: | make MODULE=test_systolic_array TOPLEVEL=systolic_array \ VERILOG_SOURCES="../rtl/pe.sv ../rtl/systolic_array.sv" \ - WAVES=0 + WAVES=0 SIM_BUILD=sim_build/systolic_array - name: cocotb — Top (full matmul vs golden) working-directory: sim @@ -73,4 +76,4 @@ jobs: make MODULE=test_top TOPLEVEL=tiny_tpu_top \ VERILOG_SOURCES="../rtl/pe.sv ../rtl/systolic_array.sv \ ../rtl/controller.sv ../rtl/tiny_tpu_top.sv" \ - WAVES=0 + WAVES=0 SIM_BUILD=sim_build/top