|
1 | | -<p><code>always @(event) begin ... end</code> is block that runs every time a specified event fires. |
| 1 | +<p><code>always @(event) begin ... end</code> is a block that runs every time a specified event fires. |
2 | 2 | If the event is a clock edge (e.g. <code>posedge clk</code>) we typically use <code>always_ff</code> instead, where "ff" stands for "flip-flop". |
3 | 3 | </p> |
4 | 4 | <svg width="300" height="68" viewBox="0 0 300 68" xmlns="http://www.w3.org/2000/svg" style="display:block;max-width:100%;font-family:'IBM Plex Mono',monospace;font-size:13px;margin:10px auto"> |
|
15 | 15 | </svg> |
16 | 16 | <p> |
17 | 17 | A flip-flop is a 1-bit memory element that captures its input (d) at a clock edge and holds it until the next edge. |
18 | | -It's easy to model a flip-flop in SystemVerilog using an <code>always_ff</code> block: |
| 18 | +It's easy to model a flip-flop in SystemVerilog using an <code>always_ff</code> block. |
| 19 | +Here, two flip-flops form a 2-stage pipeline — <code>out</code> always lags <code>mem</code> by one cycle: |
19 | 20 | <pre> |
20 | 21 | always_ff @(posedge clk) begin |
21 | | - mem <= d; // on each rising edge, capture d into mem |
22 | | - out <= mem; // on the same edge, capture mem into out (the old value of mem) |
| 22 | + mem <= d; // on each rising edge, capture d into mem |
| 23 | + out <= mem; // capture the old value of mem into out |
23 | 24 | end |
24 | 25 | </pre> |
25 | 26 | <blockquote><p> |
26 | 27 | We use <strong><dfn data-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>. All right-hand sides are evaluated first, then all assignments happen simultaneously — this prevents races and models real flip-flop behaviour.</p></blockquote> |
27 | 28 | <p> |
28 | | -SRAM consists entirely of flip-flops. |
29 | | -However we'll need a slightly more advanced pattern to model memory addresses: |
| 29 | +An SRAM is an array of flip-flops — one per bit — indexed by address. |
| 30 | +We'll need a slightly more advanced pattern to model that array. |
| 31 | +We also use a port <code>we</code> (write enable) to control when writes happen, and a separate port <code>rdata</code> for the read result. |
30 | 32 | </p> |
31 | 33 | <!-- Timing diagram: write on cycle 1, read request cycle 2, result cycle 3 --> |
32 | 34 | <svg width="400" height="210" viewBox="0 0 400 210" xmlns="http://www.w3.org/2000/svg" style="display:block;max-width:100%;font-family:'IBM Plex Mono',monospace;font-size:13px;margin:10px auto"> |
|
69 | 71 | <line x1="108" y1="196" x2="324" y2="196" stroke="#586469" stroke-width="1.5" marker-start="url(#sff-larr)" marker-end="url(#sff-rarr)" stroke-dasharray="4,3"/> |
70 | 72 | <text x="216" y="208" text-anchor="middle" fill="#586469" font-size="12">1-cycle read latency</text> |
71 | 73 | </svg> |
72 | | -<p>Open <code>sram_core.sv</code> and fill in the <code>always_ff</code> body with two statements:</p> |
| 74 | +<p>In <code>sram_core.sv</code> fill in the <code>always_ff</code> body with two statements:</p> |
73 | 75 | <ul> |
74 | 76 | <li>When <code>we</code> is high, write <code>wdata</code> into <code>mem[addr]</code></li> |
75 | 77 | <li>Always register the read: capture <code>mem[addr]</code> into <code>rdata</code></li> |
|
0 commit comments