You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/lessons/sv/always-ff/description.html
+15-1Lines changed: 15 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -25,6 +25,20 @@
25
25
</pre>
26
26
<blockquote><p>
27
27
We use <strong><dfndata-card="Non-blocking assignment (<=) schedules the update to happen after all right-hand sides in the current time step are evaluated. This means two flip-flops can swap values correctly: a <= b; b <= a; works as expected. Blocking assignment (=) takes effect immediately, like a variable assignment in C — correct for combinational logic but causes races in sequential logic.">non-blocking assignment</dfn></strong> (<code><=</code>) inside <code>always_ff</code>. It works in two steps: first, all right-hand sides are sampled using current values; then all left-hand sides update simultaneously. So <code>out</code> always captures the value <code>mem</code> held <em>before</em> this edge — creating a true one-cycle delay, not a zero-delay pass-through. The same rule is why <code>a <= b; b <= a;</code> correctly swaps two flip-flops.</p></blockquote>
28
+
29
+
<p>The names describe how each operator behaves in the flow of your procedural code — whether the assignment <strong>blocks</strong> (pauses) execution until it completes.</p>
30
+
<p><strong>Blocking <code>=</code></strong> — execution stops and waits. The assignment completes immediately, in place, before the next line runs. Think of it like hand-delivering a letter: the recipient has it before you walk away.</p>
31
+
<pre>
32
+
a = b; // a gets b's value RIGHT NOW
33
+
c = a; // c sees the new value of a
34
+
</pre>
35
+
<p><strong>Non-blocking <code><=</code></strong> — execution continues without waiting. The assignment schedules a write for later and immediately moves on. Think of it like dropping a letter in a mailbox: you keep walking and it gets delivered later, when the NBA update region runs.</p>
36
+
<pre>
37
+
a <= b; // schedules a write to a, but doesn't apply it yet
38
+
c <= a; // c gets a's OLD value — the write above hasn't happened yet
39
+
</pre>
40
+
<p>All right-hand sides are evaluated first, then all writes happen together at the end of the time step. This is what makes <code>always_ff</code> correctly model real hardware, where all flip-flops in a clocked stage sample their inputs and update simultaneously.</p>
41
+
28
42
<p>
29
43
An SRAM is an array of flip-flops — one per bit — indexed by address.
30
44
We'll need a slightly more advanced pattern to model that array.
@@ -78,4 +92,4 @@
78
92
</ul>
79
93
<blockquote><p>The read is <em>registered</em>: drive <code>addr</code> on cycle N and <code>rdata</code> reflects that address on cycle N+1. This is the standard synchronous-read SRAM model.</p></blockquote>
80
94
<h2>Testbench</h2>
81
-
<p><code>tb.sv</code> writes three values to addresses 2, 7, and 0, then reads them back one cycle later. Each read prints <code>PASS</code> or <code>FAIL</code> — run it before solving to see all three fail, then again after to confirm they all pass. Open the <strong>Waves</strong> tab to see <code>clk</code>, <code>we</code>, <code>addr</code>, <code>wdata</code>, and <code>rdata</code> over time.</p>
95
+
<p><code>tb.sv</code> writes three values to addresses 2, 7, and 0, then reads them back one cycle later. Each read prints <code>PASS</code> or <code>FAIL</code> — run it before solving to see all three fail, then again after to confirm they all pass. Open the <strong>Waves</strong> tab to see <code>clk</code>, <code>we</code>, <code>addr</code>, <code>wdata</code>, and <code>rdata</code> over time.</p>
Copy file name to clipboardExpand all lines: src/lessons/sv/tasks-functions/description.html
+5-2Lines changed: 5 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -8,8 +8,8 @@
8
8
// task body
9
9
endtask</code></pre>
10
10
<p>
11
-
Here <code>automatic</code> means the task is re-entrant: it can be called recursively or from multiple places without interference.
12
-
Non-automatic tasks share state across calls.
11
+
Here <code>automatic</code> means the task is re-entrant: it can be called recursively or from multiple places without interference — just like a normal C/C++ function whose local variables live on the stack, with a fresh copy created for each call.
12
+
A non-<code>automatic</code> (static) task behaves like a C function where every local variable is declared <code>static</code>: all calls share the same memory, so concurrent calls will overwrite each other's state.
13
13
</p>
14
14
<p>
15
15
Calling a task <code>write_word(addr, data)</code> is blocking.
@@ -21,6 +21,9 @@
21
21
<li><code>write_word(vif, addr, data)</code> — a task that drives one write transaction: assert <code>we</code>, set <code>addr</code> and <code>wdata</code>, wait one clock edge, then de-assert <code>we</code>.</li>
22
22
<li><code>read_word(vif, addr, data)</code> — a task that drives one read transaction: set <code>addr</code>, wait one clock edge, then capture <code>rdata</code>.</li>
23
23
</ul>
24
+
<blockquote><p>
25
+
Waiting for <code>@(posedge clk)</code> is not enough on its own. The testbench and the DUT are both sensitive to the same edge, so driving or sampling signals <em>at</em> the edge puts you in a race against the simulator's scheduler. The safe pattern is to wait for the edge and then advance a small delta — <code>@(posedge clk); #1;</code> — so that your assignments land in a quiet moment after the DUT has already reacted to the clock.
26
+
</p></blockquote>
24
27
<blockquote><p>These are the exact helper routines a UVM driver uses internally. In Part 3 the driver wraps them in a class method that pulls transactions from a sequencer — but the core protocol logic is the same.</p></blockquote>
25
28
<h2>Testbench structure</h2>
26
29
<p>The <code>initial</code> block calls <code>write_word</code> and <code>read_word</code> using the shared <code>mem_if</code> virtual interface, then checks the parity of the returned data with <code>parity_check</code>.</p>
0 commit comments