Skip to content
LAM
Read Home Blog
Make Projects HTML Tools Games
Touch grass Notes Resume Links
Home Blog HTML Projects
Tools Games Notes Resume Links
Back Lab 1 Guide • Half Adder → Full Adder → 4‑bit Incrementer/Adder • Digital + Verilog + GTKWave Electronics
Download Open
Show description 2,401 chars · Electronics

Lab 1 Guide • Half Adder → Full Adder → 4‑bit Incrementer/Adder • Digital + Verilog + GTKWave

Lab 1 Guide • Half Adder → Full Adder → 4‑bit Incrementer/Adder • Digital + Verilog + GTKWave








Lab 1 — Half Adder • Full Adder • 4‑bit Incrementer • 4‑bit Adder

dark‑ASCII pro guide





Overview
Files & Roles
Toolchain
Task 1‑1
Task 1‑2
Task 1‑3
Task 1‑4
Testing & Stimulus
Pitfalls
Zip Checklist
Video Script
FAQ








Overview

This one‑pager is a complete walkthrough for building, exporting, simulating, and verifying the Lab 1 circuits in Digital → Verilog → GTKWave. It covers the logic (half/full adders), bus wiring with splitters/mergers, the role of *_top.v test benches, stimulus text files, iVerilog commands, wave inspection, edge‑case tests (signed/unsigned overflow), and a ready‑to‑use video script. Dark ASCII vibes included.

Quick win: Keep all files inside a single Lab1/ folder. Digital subcircuits must be discoverable from the current project directory; saving early avoids the “custom component not visible” gotcha.






File Types & What They Do


*.dig — Your Digital schematics (source of truth for the logic).

*.v — Verilog exports of your schematics (your DUT: Design‑Under‑Test).

*_top.v — Test benches that instantiate your DUT, feed inputs, and check outputs.

*_stim.txt — Stimulus/expected values consumed by the test benches.

*_waves.vcd — Waveform dumps for GTKWave visualization.





Directory Layout (recommended)


Lab1/

Lab1/
├─ half_adder.dig
├─ half_adder.v
├─ half_adder_top.v
├─ half_adder_stim.txt
│
├─ incrementer.dig
├─ incrementer.v
├─ incrementer_top.v
│
├─ full_adder.dig
├─ full_adder.v
├─ full_adder_top.v
├─ full_adder_stim.txt
│
├─ four_bit_adder.dig
├─ four_bit_adder.v
├─ four_bit_adder_top.v
├─ four_bit_adder_stim.txt
│
├─ screenshots/ (optional)
└─ my_answers.pdf (report)



Include the *_top.v and *_stim.txt files in your zip so the grader can re‑run your sims 1:1.







Toolchain & Commands



iVerilog Build + Run

Copyiverilog -o half_adder.exe half_adder.v half_adder_top.v
./half_adder.exe # Windows: vvp half_adder.exe

iverilog -o incrementer.exe incrementer.v incrementer_top.v
./incrementer.exe

iverilog -o full_adder.exe full_adder.v full_adder_top.v
./full_adder.exe

iverilog -o four_bit_adder.exe four_bit_adder.v four_bit_adder_top.v
./four_bit_adder.exe



GTKWave

Copygtkwave half_adder_waves.vcd
# or: …

Lab 1 Guide • Half Adder → Full Adder → 4‑bit Incrementer/Adder • Digital + Verilog + GTKWave

21,319 bytes · HTML source
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Lab 1 Guide • Half Adder → Full Adder → 4‑bit Incrementer/Adder • Digital + Verilog + GTKWave</title>
<style>
  :root{
    --bg:#0a0b0f;           /* abyss */
    --panel:#0f1117;        /* deep slate */
    --muted:#8a8f98;        /* iron */
    --text:#dfe7ef;         /* ice */
    --accent:#7efcf6;       /* neon cyan */
    --accent2:#c084fc;      /* neon violet */
    --ok:#a7f3d0;           /* mint */
    --warn:#fde68a;         /* gold */
    --bad:#fca5a5;          /* soft red */
  }
  *{box-sizing:border-box}
  html,body{height:100%}
  body{
    margin:0;
    font: 16px/1.6 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
    color:var(--text);
    background:radial-gradient(1200px 1200px at 80% -20%, #18202c 0%, #0c0f15 40%, var(--bg) 70% 100%);
    overflow-x:hidden;
  }
  /* ASCII matrix rain background */
  canvas#asciiRain{position:fixed;inset:0;z-index:-2;filter:opacity(.14) contrast(120%)}
  /* Subtle scanline */
  .scanline{position:fixed;inset:0;background:repeating-linear-gradient( to bottom, rgba(255,255,255,.02) 0 2px, transparent 2px 4px );mix-blend-mode:soft-light;pointer-events:none;z-index:-1}

  a{color:var(--accent);text-decoration:none}
  a:hover{color:#b0fff9;text-shadow:0 0 6px #67fff5}

  .container{max-width:1100px;margin:0 auto;padding:28px}
  header{
    position:sticky;top:0;z-index:5;
    background:linear-gradient(180deg, rgba(15,17,23,.92), rgba(15,17,23,.65));
    backdrop-filter: blur(6px);
    border-bottom:1px solid rgba(126,252,246,.15);
  }
  .title{
    display:flex;gap:18px;align-items:center;justify-content:space-between;flex-wrap:wrap
  }
  .title h1{margin:10px 0;font-size: clamp(20px, 3.2vw, 34px);letter-spacing:.5px}
  .chip{border:1px solid rgba(126,252,246,.25);padding:6px 10px;border-radius:10px;color:var(--accent);background:rgba(126,252,246,.08)}

  nav.toc{margin:18px 0 8px;display:flex;flex-wrap:wrap;gap:10px}
  nav.toc a{padding:6px 10px;border:1px solid rgba(192,132,252,.2);border-radius:8px;color:var(--accent2);background:rgba(192,132,252,.08)}

  section{margin:28px 0;padding:22px;background:linear-gradient(180deg, rgba(18,20,28,.8), rgba(10,12,18,.7));border:1px solid rgba(126,252,246,.12);border-radius:16px;box-shadow:0 0 0 1px rgba(126,252,246,.04) inset, 0 20px 60px rgba(0,0,0,.35)}
  section h2{margin-top:0;font-size: clamp(18px, 2.4vw, 26px)}
  h3{margin:18px 0 8px;font-size: clamp(16px, 2vw, 22px)}
  p{margin:8px 0;color:#dfebff}
  .subtle{color:var(--muted)}

  .grid{display:grid;gap:16px}
  @media(min-width:900px){.grid.cols-2{grid-template-columns:1fr 1fr}}

  .card{padding:16px;border:1px solid rgba(126,252,246,.12);background:rgba(12,16,22,.6);border-radius:12px}

  pre,code{font: 13.5px/1.5 ui-monospace,Consolas,Menlo,monospace}
  pre{position:relative;background:#0c1118;border:1px solid rgba(126,252,246,.2);padding:14px 14px 16px;border-radius:12px;overflow:auto}
  pre .copy{position:absolute;top:8px;right:8px;font-size:12px;padding:4px 8px;border:1px solid rgba(126,252,246,.35);border-radius:8px;background:rgba(126,252,246,.08);color:var(--accent);cursor:pointer}
  code.inline{padding:2px 6px;background:#0c1118;border:1px solid rgba(126,252,246,.2);border-radius:6px}

  .kbd{display:inline-block;padding:2px 6px;margin:0 2px;border:1px solid rgba(223,231,239,.25);border-bottom-width:3px;border-radius:6px;background:rgba(255,255,255,.04)}

  .callout{border-left:3px solid var(--accent);padding:12px 14px;background:linear-gradient(90deg, rgba(126,252,246,.08), transparent);border-radius:8px}
  .ok{color:var(--ok)}.warn{color:var(--warn)}.bad{color:var(--bad)}

  .ascii-box{border:1px solid rgba(126,252,246,.2);border-radius:12px;overflow:hidden}
  .ascii-head{background:linear-gradient(180deg, rgba(126,252,246,.12), rgba(126,252,246,.04));padding:10px 12px;color:var(--accent)}
  .ascii-body{padding:12px;font-size:13.5px;white-space:pre;overflow:auto;color:#9dd9d6}

  footer{padding:32px 0;color:var(--muted);text-align:center}
  .glow{box-shadow:0 0 20px rgba(126,252,246,.18)}
  .pulse{animation:pulse 2.2s infinite}
  @keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(126,252,246,.22)}50%{box-shadow:0 0 0 10px rgba(126,252,246,0)}}

  .badge{display:inline-flex;gap:8px;align-items:center}
  .badge .dot{width:8px;height:8px;background:var(--accent);border-radius:999px;box-shadow:0 0 8px var(--accent)}

  .small{font-size:12.5px}
  .table{width:100%;border-collapse:separate;border-spacing:0}
  .table th,.table td{border-bottom:1px dashed rgba(126,252,246,.18);padding:10px 8px;text-align:left}
  .table th{color:#b9f8f4}
</style>
</head>
<body>
<canvas id="asciiRain"></canvas>
<div class="scanline"></div>
<header>
  <div class="container title">
    <h1>Lab 1 — Half Adder • Full Adder • 4‑bit Incrementer • 4‑bit Adder</h1>
    <div class="badge chip"><span class="dot"></span> dark‑ASCII pro guide</div>
  </div>
  <div class="container">
    <nav class="toc">
      <a href="#overview">Overview</a>
      <a href="#files">Files & Roles</a>
      <a href="#toolchain">Toolchain</a>
      <a href="#task11">Task 1‑1</a>
      <a href="#task12">Task 1‑2</a>
      <a href="#task13">Task 1‑3</a>
      <a href="#task14">Task 1‑4</a>
      <a href="#testing">Testing & Stimulus</a>
      <a href="#pitfalls">Pitfalls</a>
      <a href="#zip">Zip Checklist</a>
      <a href="#video">Video Script</a>
      <a href="#faq">FAQ</a>
    </nav>
  </div>
</header>

<main class="container">
  <section id="overview" class="glow">
    <h2>Overview</h2>
    <p>This one‑pager is a complete walkthrough for building, exporting, simulating, and verifying the Lab 1 circuits in <span class="chip">Digital → Verilog → GTKWave</span>. It covers the logic (half/full adders), bus wiring with splitters/mergers, the role of <code class="inline">*_top.v</code> test benches, stimulus text files, iVerilog commands, wave inspection, edge‑case tests (signed/unsigned overflow), and a ready‑to‑use video script. Dark ASCII vibes included.</p>
    <div class="callout small"><strong>Quick win:</strong> Keep all files inside a single <code class="inline">Lab1/</code> folder. Digital subcircuits must be discoverable from the current project directory; saving early avoids the “custom component not visible” gotcha.</div>
  </section>

  <section id="files" class="grid cols-2">
    <div class="card">
      <h3>File Types & What They Do</h3>
      <ul>
        <li><code class="inline">*.dig</code> — Your Digital schematics (source of truth for the logic).</li>
        <li><code class="inline">*.v</code> — Verilog exports of your schematics (your DUT: Design‑Under‑Test).</li>
        <li><code class="inline">*_top.v</code> — Test benches that instantiate your DUT, feed inputs, and check outputs.</li>
        <li><code class="inline">*_stim.txt</code> — Stimulus/expected values consumed by the test benches.</li>
        <li><code class="inline">*_waves.vcd</code> — Waveform dumps for GTKWave visualization.</li>
      </ul>
    </div>
    <div class="card">
      <h3>Directory Layout (recommended)</h3>
      <div class="ascii-box">
        <div class="ascii-head">Lab1/</div>
        <div class="ascii-body">Lab1/
├─ half_adder.dig
├─ half_adder.v
├─ half_adder_top.v
├─ half_adder_stim.txt
│
├─ incrementer.dig
├─ incrementer.v
├─ incrementer_top.v
│
├─ full_adder.dig
├─ full_adder.v
├─ full_adder_top.v
├─ full_adder_stim.txt
│
├─ four_bit_adder.dig
├─ four_bit_adder.v
├─ four_bit_adder_top.v
├─ four_bit_adder_stim.txt
│
├─ screenshots/            (optional)
└─ my_answers.pdf          (report)</div>
      </div>
      <p class="small subtle">Include the <code class="inline">*_top.v</code> and <code class="inline">*_stim.txt</code> files in your zip so the grader can re‑run your sims 1:1.</p>
    </div>
  </section>

  <section id="toolchain">
    <h2>Toolchain & Commands</h2>
    <div class="grid cols-2">
      <div class="card">
        <h3>iVerilog Build + Run</h3>
        <pre><button class="copy" data-copy="iverilog -o half_adder.exe half_adder.v half_adder_top.v\n./half_adder.exe">Copy</button>iverilog -o half_adder.exe half_adder.v half_adder_top.v
./half_adder.exe   # Windows: vvp half_adder.exe

iverilog -o incrementer.exe incrementer.v incrementer_top.v
./incrementer.exe

iverilog -o full_adder.exe full_adder.v full_adder_top.v
./full_adder.exe

iverilog -o four_bit_adder.exe four_bit_adder.v four_bit_adder_top.v
./four_bit_adder.exe</pre>
      </div>
      <div class="card">
        <h3>GTKWave</h3>
        <pre><button class="copy" data-copy="gtkwave half_adder_waves.vcd">Copy</button>gtkwave half_adder_waves.vcd
# or: open GTKWave app → File → Open New Tab → select *_waves.vcd</pre>
        <p class="small subtle">Pro tip: expand the top‑level module, add only DUT I/Os (e.g., <code class="inline">a, b, cin, sum, cout, y, cry, overfl</code>) to keep waves clean.</p>
      </div>
    </div>
  </section>

  <section id="task11">
    <h2>Task 1‑1 • 1‑Bit Half Adder</h2>
    <div class="grid cols-2">
      <div class="card">
        <h3>Logic</h3>
        <p><strong>sum =</strong> A ⊕ B, <strong>cry =</strong> A · B</p>
        <table class="table small">
          <thead><tr><th>A</th><th>B</th><th>cry</th><th>sum</th></tr></thead>
          <tbody>
            <tr><td>0</td><td>0</td><td>0</td><td>0</td></tr>
            <tr><td>0</td><td>1</td><td>0</td><td>1</td></tr>
            <tr><td>1</td><td>0</td><td>0</td><td>1</td></tr>
            <tr><td>1</td><td>1</td><td>1</td><td>0</td></tr>
          </tbody>
        </table>
      </div>
      <div class="card">
        <h3>Export & Sim</h3>
        <ol class="small">
          <li>Save schematic as <code class="inline">half_adder.dig</code>.</li>
          <li>Export Verilog → <code class="inline">half_adder.v</code>.</li>
          <li>Run iVerilog with <code class="inline">half_adder_top.v</code> and open <code class="inline">half_adder_waves.vcd</code>.</li>
        </ol>
        <div class="callout small">If GTKWave shows mismatches, re‑check pin names <em>exactly</em> (e.g., <code class="inline">cry</code> vs <code class="inline">carry</code>).</div>
      </div>
    </div>
  </section>

  <section id="task12">
    <h2>Task 1‑2 • 4‑Bit Incrementer</h2>
    <div class="grid cols-2">
      <div class="card">
        <h3>Design</h3>
        <p>Build from four half adders. Use splitters/mergers for 4‑bit <code class="inline">a</code> → <code class="inline">y</code>, controlled by <code class="inline">inc</code>. When <code class="inline">inc=0</code>, pass‑through; when <code class="inline">inc=1</code>, add 1 (propagate carries).</p>
      </div>
      <div class="card">
        <h3>Sim Check</h3>
        <ul class="small">
          <li>For <code class="inline">a=0x5, inc=0</code> ⇒ <code class="inline">y=0x5</code>, <code class="inline">cry=0</code>.</li>
          <li>For <code class="inline">a=0xF, inc=1</code> ⇒ <code class="inline">y=0x0</code>, <code class="inline">cry=1</code>.</li>
        </ul>
      </div>
    </div>
  </section>

  <section id="task13">
    <h2>Task 1‑3 • 1‑Bit Full Adder</h2>
    <div class="grid cols-2">
      <div class="card">
        <h3>Logic</h3>
        <p><strong>sum =</strong> A ⊕ B ⊕ Cin</p>
        <p><strong>cout =</strong> majority(A,B,Cin) = A·B + A·Cin + B·Cin</p>
        <p class="small subtle">Digital hint: set XOR and OR to 3 inputs in properties.</p>
      </div>
      <div class="card">
        <h3>Stim Bits (full_adder_stim.txt)</h3>
        <div class="small">Bit map: <code class="inline">[7:6 unused][5 cout][4 sum][3 unused][2 cin][1 a][0 b]</code></div>
      </div>
    </div>
  </section>

  <section id="task14">
    <h2>Task 1‑4 • 4‑Bit Full Adder</h2>
    <div class="grid cols-2">
      <div class="card">
        <h3>Design</h3>
        <p>Cascade four 1‑bit full adders, split/merge 4‑bit buses for <code class="inline">a</code> and <code class="inline">b</code>. Outputs: <code class="inline">y[3:0]</code>, <code class="inline">cout</code> (unsigned carry out), <code class="inline">overfl</code> (signed overflow).</p>
        <div class="callout small"><strong>Signed vs Unsigned:</strong> 4‑bit unsigned is 0..15; two’s‑complement signed is −8..+7. Hardware is identical; interpretation changes how you read <code class="inline">cout</code> vs <code class="inline">overfl</code>.</div>
      </div>
      <div class="card">
        <h3>Classic Edge Cases</h3>
        <ul class="small">
          <li><em>Unsigned overflow</em>: F + 1 → <code class="inline">cout=1</code></li>
          <li><em>Signed overflow (+ + → −)</em>: 7 + 4 → overflows (positive + positive yields negative)</li>
          <li><em>Signed overflow (− − → +)</em>: (8) + (8) → overflows (negative + negative yields positive)</li>
        </ul>
      </div>
    </div>
  </section>

  <section id="testing">
    <h2>Testing & Stimulus Files</h2>
    <div class="grid cols-2">
      <div class="card">
        <h3>four_bit_adder_stim.txt bit map</h3>
        <div class="small">Bit layout per hex nibble (20 bits total):</div>
        <div class="ascii-box">
          <div class="ascii-head">[19:0] mapping</div>
          <div class="ascii-body">[19:18 unused] [17 exp_overfl] [16 exp_cout] [15:12 exp_y3..0] [11:9 unused] [8 cin] [7:4 a3..0] [3:0 b3..0]</div>
        </div>
        <p class="small subtle">Each row like <code class="inline">E_0_F_F_?</code> is five hex digits separated by underscores for readability.</p>
      </div>
      <div class="card">
        <h3>Example Test Rows & Motives</h3>
        <table class="table small">
          <thead><tr><th>Stimulus</th><th>What it checks</th></tr></thead>
          <tbody>
            <tr><td><code class="inline">0_0_0_0_0</code></td><td>Stuck‑at‑1 sanity (no wires tied high)</td></tr>
            <tr><td><code class="inline">0_3_0_1_2</code></td><td>Simple add: 1 + 2 → y=3</td></tr>
            <tr><td><code class="inline">0_4_1_1_2</code></td><td>Carry‑in handling</td></tr>
            <tr><td><code class="inline">0_F_0_F_0</code></td><td>Max + 0</td></tr>
            <tr><td><code class="inline">1_0_0_F_1</code></td><td>Smallest unsigned overflow</td></tr>
            <tr><td><code class="inline">3_2_0_9_9</code></td><td>Signed overflow (−7 + −7)</td></tr>
            <tr><td><code class="inline">2_8_0_7_1</code></td><td>Smallest signed overflow (+7 + +1)</td></tr>
            <tr><td><code class="inline">2_9_1_4_4</code></td><td>Signed overflow with Cin (4 + 4 + 1)</td></tr>
          </tbody>
        </table>
      </div>
    </div>
    <div class="card">
      <h3>Stim Harness Pattern</h3>
      <pre><button class="copy" data-copy="iverilog -o four_bit_adder.exe four_bit_adder.v four_bit_adder_top.v\n./four_bit_adder.exe\n# If a mismatch appears, the printed index lines up with your test row number (0..15).">Copy</button>iverilog -o four_bit_adder.exe four_bit_adder.v four_bit_adder_top.v
./four_bit_adder.exe
# If a mismatch appears, the printed index lines up with your test row number (0..15).</pre>
    </div>
  </section>

  <section id="pitfalls" class="grid cols-2">
    <div class="card">
      <h3>Common Pitfalls</h3>
      <ul class="small">
        <li><strong>Wrong signal names:</strong> Use <code class="inline">cry</code> (not <em>carry</em>) where required.</li>
        <li><strong>Custom component not visible:</strong> Save a new schematic into <code class="inline">Lab1/</code> first so <code class="inline">Components → Custom</code> refreshes.</li>
        <li><strong>Splitter order:</strong> Put MSB on top (<code class="inline">[3..0]</code>) consistently for readability.</li>
        <li><strong>Overfl vs cout:</strong> Know which flag means signed vs unsigned overflow.</li>
      </ul>
    </div>
    <div class="card">
      <h3>Quick Sanity Matrix</h3>
      <table class="table small">
        <thead><tr><th>Case</th><th>Inputs</th><th>Expect</th></tr></thead>
        <tbody>
          <tr><td>Increment wrap</td><td>a=F, inc=1</td><td>y=0, cry=1</td></tr>
          <tr><td>Unsigned carry</td><td>a=F, b=1, cin=0</td><td>cout=1</td></tr>
          <tr><td>Signed overflow (+ +)</td><td>a=7, b=4, cin=0</td><td>overfl=1</td></tr>
          <tr><td>Signed overflow (− −)</td><td>a=8, b=8, cin=0</td><td>overfl=1</td></tr>
        </tbody>
      </table>
    </div>
  </section>

  <section id="zip">
    <h2>Submission Zip Checklist</h2>
    <ul class="small">
      <li>All <code class="inline">*.dig</code> schematics</li>
      <li>All exported <code class="inline">*.v</code> DUT files</li>
      <li>All provided <code class="inline">*_top.v</code> test benches</li>
      <li>All provided/edited <code class="inline">*_stim.txt</code> files</li>
      <li><code class="inline">*_waves.vcd</code> optional but helpful</li>
      <li>Screenshot images (schematics + waves)</li>
      <li><code class="inline">my_answers.pdf</code> (completed template)</li>
    </ul>
    <div class="callout">Do <em>not</em> embed your video in the zip. Host it and include the link in your PDF.</div>
  </section>

  <section id="video">
    <h2>Fast Video Script (teleprompter‑ready)</h2>
    <div class="card">
      <ol class="small">
        <li><strong>Intro (10–15s):</strong> “Hi, I’m Lalo Morales — Lab 1: Half Adder, Full Adder, 4‑bit Incrementer/Adder. I’ll show schematics and GTKWave results.”</li>
        <li><strong>Half Adder (~20s):</strong> Show XOR/AND, truth table match in waves.</li>
        <li><strong>Incrementer (~20s):</strong> Four half adders + splitters. <code class="inline">inc=0</code> pass‑through, <code class="inline">inc=1</code> +1, wrap at F→0 with <code class="inline">cry=1</code>.</li>
        <li><strong>Full Adder (~20s):</strong> 3‑input XOR/OR, sum & carry logic demo.</li>
        <li><strong>4‑bit Adder (~30–40s):</strong> Cascaded full adders, signed vs unsigned flags, edge‑case tests all pass.</li>
        <li><strong>Close (10–15s):</strong> “All circuits verified. Thanks!”</li>
      </ol>
    </div>
  </section>

  <section id="faq" class="grid cols-2">
    <div class="card">
      <h3>FAQ — Why include <code class="inline">*_top.v</code>?</h3>
      <p>They’re the test benches. They instantiate your DUT, feed vectors from <code class="inline">*_stim.txt</code>, and auto‑check expected outputs. Without them, the grader can’t re‑run your sims.</p>
    </div>
    <div class="card">
      <h3>GTKWave looks noisy — what do I add?</h3>
      <p>Add only high‑level I/Os: <code class="inline">a, b, cin, y, cout, overfl, inc, cry</code>. Ignore internal <code class="inline">s#</code> wires unless debugging.</p>
    </div>
  </section>

  <footer>
    <div class="small">© Lab 1 Reference • Single‑file HTML • Dark ASCII theme • Built for speed and clarity</div>
  </footer>
</main>

<script>
  // Matrix ASCII rain — adapted for subtle ambience
  const canvas = document.getElementById('asciiRain');
  const ctx = canvas.getContext('2d');
  const glyphs = "░▒▓#*+:-·".split("");
  let w, h, cols, drops;
  function resize(){
    w = canvas.width = window.innerWidth;
    h = canvas.height = window.innerHeight;
    cols = Math.floor(w / 12);
    drops = Array(cols).fill(0).map(()=> Math.random()*h);
  }
  window.addEventListener('resize', resize); resize();
  function tick(){
    ctx.fillStyle = 'rgba(10,11,15,0.22)';
    ctx.fillRect(0,0,w,h);
    ctx.fillStyle = 'rgba(126,252,246,0.35)';
    ctx.font = '12px ui-monospace,Consolas,Menlo,monospace';
    for(let i=0;i<cols;i++){
      const ch = glyphs[(Math.random()*glyphs.length)|0];
      ctx.fillText(ch, i*12, drops[i]);
      drops[i] += 14 + Math.random()*6;
      if(drops[i] > h) drops[i] = -Math.random()*200;
    }
    requestAnimationFrame(tick);
  }
  tick();

  // Smooth scroll for TOC
  document.querySelectorAll('nav.toc a').forEach(a=>{
    a.addEventListener('click', e=>{e.preventDefault(); document.querySelector(a.getAttribute('href')).scrollIntoView({behavior:'smooth',block:'start'});});
  });

  // Copy buttons
  document.querySelectorAll('pre .copy').forEach(btn=>{
    btn.addEventListener('click',async()=>{
      const text = btn.getAttribute('data-copy');
      try{ await navigator.clipboard.writeText(text); btn.textContent='Copied'; setTimeout(()=>btn.textContent='Copy',1200);}catch{ btn.textContent='Copy failed'; setTimeout(()=>btn.textContent='Copy',1200);} 
    });
  });
</script>
</body>
</html>