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..e92718e --- /dev/null +++ b/.github/workflows/rtl.yml @@ -0,0 +1,79 @@ +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 + + # 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 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 SIM_BUILD=sim_build/systolic_array + + - 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 SIM_BUILD=sim_build/top 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" 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 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 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 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" + } + ] + } + ] +}