Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/lessons/verilog/always-blocks/counter.sol.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module counter(
input clk,
input reset,
output reg [3:0] count
);
always @(posedge clk) begin
if (reset)
count <= 4'b0;
else
count <= count + 1;
end
endmodule
7 changes: 7 additions & 0 deletions src/lessons/verilog/always-blocks/counter.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module counter(
input clk,
input reset,
output reg [3:0] count
);
// TODO: increment count on posedge clk, reset to 0 when reset is high
endmodule
62 changes: 62 additions & 0 deletions src/lessons/verilog/always-blocks/description.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<p>The <code>always</code> block is the core procedural construct in Verilog. It describes behavior that is re-evaluated
whenever signals in its <dfn
data-card="The sensitivity list tells the simulator when to re-evaluate the always block. @(*) means 'whenever any input changes' (combinational). @(posedge clk) means 'on the rising edge of clk' (sequential).">sensitivity
list</dfn> change.</p>

<h2>Combinational Logic: always @(*)</h2>
<pre>always @(*) begin
if (sel)
y = a;
else
y = b;
end</pre>
<p>The <code>@(*)</code> (or <code>@*</code>) is shorthand for "re-evaluate when any input changes." Use
<strong>blocking assignment</strong> (<code>=</code>) for combinational logic.</p>

<h2>Sequential Logic: always @(posedge clk)</h2>
<pre>always @(posedge clk) begin
if (reset)
q <= 0;
else
q <= d;
end</pre>
<p>This creates a <dfn
data-card="A flip-flop (or register) is a circuit element that captures and stores a value on a clock edge. On the rising edge of clk, the value of d is captured into q and held there until the next rising edge.">flip-flop</dfn>.
Use <strong>non-blocking assignment</strong> (<code><=</code>) for sequential logic to avoid race conditions.</p>

<svg width="420" height="150" viewBox="0 0 420 150" xmlns="http://www.w3.org/2000/svg"
style="display:block;max-width:100%;font-family:'IBM Plex Mono',monospace;font-size:12px;margin:10px auto">
<rect x="10" y="10" width="190" height="130" rx="8" fill="#e8f4f8" stroke="#0d6f72" stroke-width="2" />
<text x="105" y="35" text-anchor="middle" font-weight="bold" fill="#0d6f72" font-size="13">Combinational</text>
<text x="105" y="58" text-anchor="middle" fill="#3d9fa3" font-size="11">always @(*)</text>
<text x="105" y="78" text-anchor="middle" fill="#3d9fa3" font-size="11">Blocking =</text>
<text x="105" y="98" text-anchor="middle" fill="#3d9fa3" font-size="11">No clock needed</text>
<text x="105" y="118" text-anchor="middle" fill="#3d9fa3" font-size="11">→ Gates & muxes</text>

<rect x="220" y="10" width="190" height="130" rx="8" fill="#f0e8f8" stroke="#6b2fa0" stroke-width="2" />
<text x="315" y="35" text-anchor="middle" font-weight="bold" fill="#6b2fa0" font-size="13">Sequential</text>
<text x="315" y="58" text-anchor="middle" fill="#8b5fbf" font-size="11">always @(posedge clk)</text>
<text x="315" y="78" text-anchor="middle" fill="#8b5fbf" font-size="11">Non-blocking <=< /text>
<text x="315" y="98" text-anchor="middle" fill="#8b5fbf" font-size="11">Clock-triggered</text>
<text x="315" y="118" text-anchor="middle" fill="#8b5fbf" font-size="11">→ Flip-flops</text>
</svg>

<h2>Critical Rules</h2>
<ul>
<li>Use <code>=</code> in <code>always @(*)</code> — blocking, evaluates immediately</li>
<li>Use <code><=</code> in <code>always @(posedge clk)</code> — non-blocking, all assignments happen simultaneously
at the clock edge</li>
<li>Every variable assigned in an <code>always</code> block must be of type <code>reg</code></li>
<li>Never mix blocking and non-blocking in the same <code>always</code> block</li>
</ul>

<blockquote>
<p><strong>Latch warning:</strong> If you don't assign a <code>reg</code> in every branch of an
<code>always @(*)</code> block, synthesis creates a <em>latch</em> (unintentional memory). Always cover all
cases!</p>
</blockquote>

<blockquote>
<p><strong>Exercise:</strong> Complete <code>counter.sv</code>. Implement a 4-bit counter that increments on each
rising clock edge and resets to 0 when <code>reset</code> is high.</p>
</blockquote>
81 changes: 81 additions & 0 deletions src/lessons/verilog/gates/description.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<p>Verilog provides built-in <dfn
data-card="Gate-level primitives are built-in Verilog constructs that model basic logic gates. They map directly to physical gates in silicon. Using them is called 'structural modeling' — you're describing the circuit's structure rather than its behavior.">gate-level
primitives</dfn> that model fundamental logic gates. This is the lowest level of abstraction before transistors.
</p>

<h2>Basic Gates</h2>
<svg width="500" height="340" viewBox="0 0 500 340" xmlns="http://www.w3.org/2000/svg"
style="display:block;max-width:100%;font-family:'IBM Plex Mono',monospace;font-size:11px;margin:10px auto">
<!-- AND gate -->
<text x="10" y="38" font-weight="bold" fill="#0d6f72">AND</text>
<rect x="70" y="20" width="50" height="35" rx="0" fill="#e6f5f5" stroke="#0d6f72" stroke-width="1.5" />
<path d="M120,20 Q145,37.5 120,55" fill="#e6f5f5" stroke="#0d6f72" stroke-width="1.5" />
<line x1="50" y1="30" x2="70" y2="30" stroke="#1e2a2c" stroke-width="1.5" />
<line x1="50" y1="45" x2="70" y2="45" stroke="#1e2a2c" stroke-width="1.5" />
<line x1="145" y1="37" x2="165" y2="37" stroke="#1e2a2c" stroke-width="1.5" />
<text x="180" y="42" fill="#1e2a2c">Y = A · B</text>

<!-- OR gate -->
<text x="10" y="98" font-weight="bold" fill="#0d6f72">OR</text>
<path d="M70,80 Q100,80 120,80 Q145,97.5 120,115 Q100,115 70,115 Q90,97.5 70,80Z" fill="#e6f5f5" stroke="#0d6f72"
stroke-width="1.5" />
<line x1="50" y1="90" x2="78" y2="90" stroke="#1e2a2c" stroke-width="1.5" />
<line x1="50" y1="105" x2="78" y2="105" stroke="#1e2a2c" stroke-width="1.5" />
<line x1="145" y1="97" x2="165" y2="97" stroke="#1e2a2c" stroke-width="1.5" />
<text x="180" y="102" fill="#1e2a2c">Y = A + B</text>

<!-- NOT gate -->
<text x="10" y="158" font-weight="bold" fill="#0d6f72">NOT</text>
<polygon points="70,140 130,157.5 70,175" fill="#e6f5f5" stroke="#0d6f72" stroke-width="1.5" />
<circle cx="135" cy="157.5" r="5" fill="#e6f5f5" stroke="#0d6f72" stroke-width="1.5" />
<line x1="50" y1="157" x2="70" y2="157" stroke="#1e2a2c" stroke-width="1.5" />
<line x1="140" y1="157" x2="165" y2="157" stroke="#1e2a2c" stroke-width="1.5" />
<text x="180" y="162" fill="#1e2a2c">Y = ~A</text>

<!-- XOR gate -->
<text x="10" y="218" font-weight="bold" fill="#0d6f72">XOR</text>
<path d="M75,200 Q105,200 125,200 Q150,217.5 125,235 Q105,235 75,235 Q95,217.5 75,200Z" fill="#e6f5f5"
stroke="#0d6f72" stroke-width="1.5" />
<path d="M68,200 Q88,217.5 68,235" fill="none" stroke="#0d6f72" stroke-width="1.5" />
<line x1="50" y1="210" x2="82" y2="210" stroke="#1e2a2c" stroke-width="1.5" />
<line x1="50" y1="225" x2="82" y2="225" stroke="#1e2a2c" stroke-width="1.5" />
<line x1="150" y1="217" x2="165" y2="217" stroke="#1e2a2c" stroke-width="1.5" />
<text x="180" y="222" fill="#1e2a2c">Y = A ⊕ B</text>

<!-- NAND gate -->
<text x="280" y="38" font-weight="bold" fill="#6b2fa0">NAND</text>
<rect x="340" y="20" width="50" height="35" rx="0" fill="#f0e8f8" stroke="#6b2fa0" stroke-width="1.5" />
<path d="M390,20 Q415,37.5 390,55" fill="#f0e8f8" stroke="#6b2fa0" stroke-width="1.5" />
<circle cx="420" cy="37.5" r="5" fill="#f0e8f8" stroke="#6b2fa0" stroke-width="1.5" />
<text x="440" y="42" fill="#1e2a2c">Y = ~(A·B)</text>

<!-- NOR gate -->
<text x="280" y="98" font-weight="bold" fill="#6b2fa0">NOR</text>
<path d="M340,80 Q370,80 390,80 Q415,97.5 390,115 Q370,115 340,115 Q360,97.5 340,80Z" fill="#f0e8f8"
stroke="#6b2fa0" stroke-width="1.5" />
<circle cx="420" cy="97.5" r="5" fill="#f0e8f8" stroke="#6b2fa0" stroke-width="1.5" />
<text x="440" y="102" fill="#1e2a2c">Y = ~(A+B)</text>
</svg>

<h2>Verilog Gate Syntax</h2>
<pre>and u1 (y, a, b); // y = a & b
or u2 (y, a, b); // y = a | b
not u3 (y, a); // y = ~a
xor u4 (y, a, b); // y = a ^ b
nand u5 (y, a, b); // y = ~(a & b)
nor u6 (y, a, b); // y = ~(a | b)</pre>

<p>The first argument is always the <strong>output</strong>, followed by <strong>inputs</strong>. The instance name (u1,
u2, ...) is optional but recommended.</p>

<blockquote>
<p><strong>Industry note:</strong> Gate-level modeling is rarely written by hand today — synthesis tools generate it
from behavioral RTL. However, understanding gates is essential for reading netlists and debugging timing issues.
</p>
</blockquote>

<blockquote>
<p><strong>Exercise:</strong> Build a 2-to-1 multiplexer using only gate primitives (<code>and</code>,
<code>or</code>, <code>not</code>). When <code>sel=0</code>, output <code>a</code>; when <code>sel=1</code>,
output <code>b</code>.</p>
</blockquote>
12 changes: 12 additions & 0 deletions src/lessons/verilog/gates/mux2.sol.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module mux2(
input a,
input b,
input sel,
output y
);
wire sel_n, w1, w2;
not u1 (sel_n, sel);
and u2 (w1, a, sel_n);
and u3 (w2, b, sel);
or u4 (y, w1, w2);
endmodule
10 changes: 10 additions & 0 deletions src/lessons/verilog/gates/mux2.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module mux2(
input a,
input b,
input sel,
output y
);
// TODO: build a 2:1 mux using and, or, not gates
// y = (a & ~sel) | (b & sel)
wire sel_n, w1, w2;
endmodule
16 changes: 16 additions & 0 deletions src/lessons/verilog/if-case/alu.sol.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module alu(
input [7:0] a,
input [7:0] b,
input [1:0] op,
output reg [7:0] result
);
always @(*) begin
case (op)
2'b00: result = a + b;
2'b01: result = a - b;
2'b10: result = a & b;
2'b11: result = a | b;
default: result = 8'b0;
endcase
end
endmodule
11 changes: 11 additions & 0 deletions src/lessons/verilog/if-case/alu.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module alu(
input [7:0] a,
input [7:0] b,
input [1:0] op, // 00=ADD, 01=SUB, 10=AND, 11=OR
output reg [7:0] result
);
// TODO: use a case statement on 'op' to compute result
always @(*) begin
result = 8'b0;
end
endmodule
65 changes: 65 additions & 0 deletions src/lessons/verilog/if-case/description.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<p>Verilog provides <code>if/else</code> and <code>case</code> statements for decision-making inside procedural blocks.
These map directly to hardware multiplexers and priority encoders.</p>

<h2>if / else</h2>
<pre>always @(*) begin
if (sel == 2'b00)
y = a;
else if (sel == 2'b01)
y = b;
else if (sel == 2'b10)
y = c;
else
y = d;
end</pre>
<p><code>if/else</code> creates <strong>priority logic</strong> — the first matching condition wins. This synthesizes to
a chain of muxes.</p>

<h2>case</h2>
<pre>always @(*) begin
case (sel)
2'b00: y = a;
2'b01: y = b;
2'b10: y = c;
2'b11: y = d;
default: y = 0;
endcase
end</pre>
<p><code>case</code> checks for an exact match. All values should be covered — use <code>default</code> to catch
remaining cases.</p>

<h2>Variants</h2>
<ul>
<li><code>casez</code> — Treats <code>?</code> and <code>z</code> as don't-care in the pattern (useful for priority
encoders)</li>
<li><code>casex</code> — Treats <code>x</code> and <code>z</code> as don't-care (dangerous in simulation, avoid in
RTL)</li>
</ul>
<pre>always @(*) begin
casez (req)
4'b1???: grant = 4'b1000; // bit 3 highest priority
4'b01??: grant = 4'b0100;
4'b001?: grant = 4'b0010;
4'b0001: grant = 4'b0001;
default: grant = 4'b0000;
endcase
end</pre>

<h2>Synthesis Implications</h2>
<svg width="400" height="100" viewBox="0 0 400 100" xmlns="http://www.w3.org/2000/svg"
style="display:block;max-width:100%;font-family:'IBM Plex Mono',monospace;font-size:11px;margin:10px auto">
<rect x="10" y="10" width="170" height="80" rx="8" fill="#e8f4f8" stroke="#0d6f72" stroke-width="2" />
<text x="95" y="35" text-anchor="middle" font-weight="bold" fill="#0d6f72" font-size="12">if/else</text>
<text x="95" y="55" text-anchor="middle" fill="#3d9fa3" font-size="11">Priority chain</text>
<text x="95" y="72" text-anchor="middle" fill="#3d9fa3" font-size="11">Slower, cascaded muxes</text>

<rect x="220" y="10" width="170" height="80" rx="8" fill="#f0e8f8" stroke="#6b2fa0" stroke-width="2" />
<text x="305" y="35" text-anchor="middle" font-weight="bold" fill="#6b2fa0" font-size="12">case</text>
<text x="305" y="55" text-anchor="middle" fill="#8b5fbf" font-size="11">Parallel selection</text>
<text x="305" y="72" text-anchor="middle" fill="#8b5fbf" font-size="11">Faster, one-hot mux</text>
</svg>

<blockquote>
<p><strong>Exercise:</strong> Complete the ALU in <code>alu.sv</code> using a <code>case</code> statement. Implement
ADD, SUB, AND, OR operations based on a 2-bit opcode.</p>
</blockquote>
34 changes: 34 additions & 0 deletions src/lessons/verilog/intro/description.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<p><strong>Verilog</strong> is a <dfn data-card="A Hardware Description Language (HDL) is a specialized programming language used to describe the structure and behavior of electronic circuits. Unlike software languages that run on processors, HDL code gets synthesized into actual hardware (gates, flip-flops, wires). The two dominant HDLs are Verilog and VHDL.">Hardware Description Language (HDL)</dfn> used to model and design digital circuits. Created in 1984 by Phil Moorby and Prabhu Goel at Gateway Design Automation, it became an IEEE standard (IEEE 1364) in 1995.</p>

<h2>HDL vs Software Languages</h2>
<p>While Verilog looks syntactically similar to C, there's a fundamental difference:</p>

<svg width="500" height="200" viewBox="0 0 500 200" xmlns="http://www.w3.org/2000/svg" style="display:block;max-width:100%;font-family:'IBM Plex Mono',monospace;font-size:12px;margin:10px auto">
<rect x="20" y="20" width="200" height="160" rx="10" fill="#e8f4f8" stroke="#0d6f72" stroke-width="2"/>
<text x="120" y="50" text-anchor="middle" font-weight="bold" fill="#0d6f72" font-size="14">Software (C/Python)</text>
<text x="120" y="80" text-anchor="middle" fill="#3d9fa3" font-size="11">Sequential execution</text>
<text x="120" y="100" text-anchor="middle" fill="#3d9fa3" font-size="11">One thing at a time</text>
<text x="120" y="120" text-anchor="middle" fill="#3d9fa3" font-size="11">Runs on a processor</text>
<text x="120" y="140" text-anchor="middle" fill="#3d9fa3" font-size="11">Instructions → CPU</text>

<rect x="280" y="20" width="200" height="160" rx="10" fill="#f0e8f8" stroke="#6b2fa0" stroke-width="2"/>
<text x="380" y="50" text-anchor="middle" font-weight="bold" fill="#6b2fa0" font-size="14">Hardware (Verilog)</text>
<text x="380" y="80" text-anchor="middle" fill="#8b5fbf" font-size="11">Parallel execution</text>
<text x="380" y="100" text-anchor="middle" fill="#8b5fbf" font-size="11">Everything at once</text>
<text x="380" y="120" text-anchor="middle" fill="#8b5fbf" font-size="11">Becomes the circuit</text>
<text x="380" y="140" text-anchor="middle" fill="#8b5fbf" font-size="11">Description → Gates</text>
</svg>

<p>In software, statements execute one after another. In Verilog, all <code>assign</code> statements and <code>always</code> blocks execute <strong>concurrently</strong> — just like real wires and gates in a circuit all operate simultaneously.</p>

<h2>Synthesis vs Simulation</h2>
<p>Verilog code serves two purposes:</p>
<ul>
<li><strong>Synthesis</strong> — A synthesis tool (like Yosys or Synopsys DC) converts your Verilog into actual logic gates and flip-flops. This is the "real hardware" path.</li>
<li><strong>Simulation</strong> — A simulator (like this tutorial's built-in engine) executes your Verilog to verify behavior before manufacturing. Constructs like <code>initial</code>, <code>$display</code>, and <code>#delay</code> exist only in simulation.</li>
</ul>

<h2>Verilog vs SystemVerilog</h2>
<p><dfn data-card="SystemVerilog (IEEE 1800) is a superset of Verilog that adds features for verification (classes, assertions, constrained random, coverage) and design (interfaces, always_comb, always_ff, logic type). It's backward-compatible: all Verilog code is valid SystemVerilog.">SystemVerilog</dfn> is a superset of Verilog. Think of Verilog as the foundation for describing hardware, and SystemVerilog as the extended version with added verification and design features. This tutorial starts with core Verilog concepts, then builds into SystemVerilog.</p>

<blockquote><p><strong>Your first task:</strong> Open <code>top.sv</code> and use <code>$display</code> to print "Hello, Verilog!" followed by <code>$finish</code>. This confirms the simulation environment is working.</p></blockquote>
6 changes: 6 additions & 0 deletions src/lessons/verilog/intro/top.sol.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module top;
initial begin
$display("Hello, Verilog!");
$finish;
end
endmodule
5 changes: 5 additions & 0 deletions src/lessons/verilog/intro/top.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module top;
initial begin
// TODO: print "Hello, Verilog!" using $display, then call $finish
end
endmodule
7 changes: 7 additions & 0 deletions src/lessons/verilog/modules/adder.sol.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module adder(
input [3:0] a,
input [3:0] b,
output [4:0] sum
);
assign sum = a + b;
endmodule
7 changes: 7 additions & 0 deletions src/lessons/verilog/modules/adder.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module adder(
input [3:0] a,
input [3:0] b,
output [4:0] sum
);
// TODO: assign sum = a + b
endmodule
Loading