Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here6
  • SystemVerilog Language Foundations35
    • SystemVerilog Data Types
    • Arrays: Packed, Dynamic, Queues & Associative
    • Procedural Code & Scheduling
      • always_comb, always_ff, always_latch
      • Blocking vs Nonblocking Assignments
      • Tasks vs Functions
      • The Event Scheduler & Stratified Regions
      • initial, final & Startup Ordering
      • Loops & Flow Control
    • Operators, Expressions & Width Rules
    • Packages, Typedefs & Compilation
    • Interfaces, Modports & Clocking Blocks
  • Object-Oriented SystemVerilog for Verification35
  • Constraint Randomization — Interview-Critical Deep Dive66
  • SystemVerilog Assertions — Interview-Critical Deep Dive63
  • Functional Coverage in SystemVerilog28
  • Testbench Architecture in SystemVerilog38
  • Advanced Language & Integration30
  • Senior & Interview Preparation34
  • Principal-Level Verification28
Loading lesson

‹Procedural Code & Scheduling
  1. Topics
  2. SystemVerilog
  3. SystemVerilog Language Foundations
  4. Procedural Code & Scheduling
  5. Loops & Flow Control

Part 1 · Language Foundations · Intermediate

Loops & Flow Control

Loops, break and continue, named-block disable, and timing controls inside forever.

On this page

    Why this matters

    The simulation froze at time 0 and printed nothing. A forever loop had no clock wait inside it, so simulated time could never move on.

    After this lesson you can: choose foreach, repeat, while or forever for a job, leave loops early with break, continue and disable, and keep forever loops from hanging.

    Loops for hardware shapes

    Beyond for and while, SystemVerilog adds loops shaped for verification work. foreach walks an array's declared index space with no off-by-one risk, and repeat (n) runs a body a fixed count with no loop variable.

    Predict first int a[3:0] is declared with the range written high to low. In what index order does foreach (a[i]) visit it?

    3, 2, 1, 0. foreach runs from the left bound to the right bound as declared, not always upward.

    foreach order is defined: fixed and dynamic dimensions run from the left bound to the right bound (int a[3:0] gives 3, 2, 1, 0), and associative arrays run in ascending key order. Multidimensional arrays use one form, foreach (t[r, c]). forever loops until its process dies and must block on @ or # every pass, or it starves the scheduler in a zero-time hang.

    Loop

    Fits

    foreach (flat[k])

    Filling and scanning an array with no index bookkeeping

    repeat (n)

    Waiting a fixed number of clocks

    while

    Waiting for a state change with a live condition

    forever

    Monitors and clock generators, always with a timing control

    Early exits with break and disable

    break leaves the innermost loop and continue jumps to its next iteration. Both are structured and preferred for ordinary early exits.

    Naming a block (begin : search) and calling disable search terminates it from inside nested loops or from another process, which is how watchdogs stand down stuck waits. Disabling a task name kills every concurrent activation, so selective kills target a named inner block instead.

    A monitor that must survive reset races its collecting loops against a reset watcher and kills the losers with fork ... join_any and disable fork. Those process controls belong to Interprocess Communication in the OOP part.

    Interview

    “When do you use break and when disable?”

    break leaves the innermost loop and is the normal early exit. disable on a named block leaves several nested loops at once, or stops a block from another process, such as a watchdog.

    Check yourself A forever monitor loop contains no @ or #. What happens?

    The simulation hangs in a zero-time infinite loop. Every pass must block on a timing control.

    Check yourself A watchdog must kill one stuck call of a task with three live calls. Why is disable task_name the wrong tool?

    It kills every activation at once. A named inner block per call gives a selective target.

    Testbench

    A one-dimensional and a two-dimensional foreach fill, a search with nested for loops, a bounded forever loop, and a watchdog that stands down via cross-process disable.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    module tb_flow;
      timeunit 1ns; timeprecision 1ps;
      logic clk = 0;
      always #5 clk = ~clk;
      int flat[12];
      int t[3][4];
      int target = 9;
      int hit_r = -1, hit_c = -1, found = 0;
      logic done = 0;
      int beats = 0;
      int errors = 0;
      initial begin
        foreach (flat[k]) flat[k] = k * 2;
        if (flat[5] !== 10) errors++;
        foreach (t[r, c]) t[r][c] = r * 4 + c;  // one loop over both dimensions
        begin : search
          for (int r = 0; r < 3; r++) begin
            for (int c = 0; c < 4; c++) begin
              if (t[r][c] == target) begin
                hit_r = r; hit_c = c; found = 1;
                disable search;
              end
            end
          end
        end
        if (found !== 1) errors++;
        if (hit_r !== 2 || hit_c !== 1) errors++;
        forever begin
          @(posedge clk);
          beats = beats + 1;
          if (beats == 3) break;
        end
        if (beats !== 3) errors++;
        @(posedge done);
        disable guard;
        #1100;                                // past the guard's timeout: it must stay quiet
        if (errors != 0) $fatal(1, "FAIL: fill, search or loop counts look wrong, or the watchdog fired");
        $display("PASS: foreach fill and [2][1] search hit, forever loop runs 3 beats, watchdog stands down");
        $finish;
      end
      initial begin
        repeat (5) @(posedge clk);
        done = 1;
      end
      initial begin : guard
        #1000;
        errors = 1;
      end
    endmodule
    Terminal
    PASS: foreach fill and [2][1] search hit, forever loop runs 3 beats, watchdog stands down

    Remember

    • foreach walks the declared range, left bound to right bound.

    • Every forever pass needs @ or #, or time stops.

    • break leaves one loop; disable leaves a named block, even from another process.

    Rule of thumb: a loop that waits on nothing must end; a loop that never ends must wait.

    How this was checked

    Run with Verilator 5.048 (--binary --timing) on 2026-10-18; every bench printed the PASS line shown, with no warnings. Icarus 13 (-g2012) runs them too, with the same output.

    Related topics

    • Next topic: Operators, Expressions & Width Rules

    Previous

    24 / 363

    Next: Operators, Expressions & Width Rules

    Up next

    Up nextOperators, Expressions & Width Rules

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • always_comb, always_ff, always_latch
    • Blocking vs Nonblocking Assignments
    • Tasks vs Functions