System Tasks, Functions & File I/O
Complete reference for Verilog’s built-in system tasks and functions — display, simulation control, math, conversion, random — and the full set of file-based I/O tasks for reading and writing files during simulation.
📖 Introduction
System tasks and system functions are built-in Verilog constructs whose names begin with a dollar sign ($). They provide essential simulation services — printing output, controlling simulation time, generating random numbers, performing math, and reading/writing files. They operate entirely at simulation time and are never synthesized.
$. Tasks are called as statements; functions return a value and appear in expressions.$ statement in the design.$display, $finish) perform actions with no return value. Functions ($time, $random) return a value for use in expressions.📺 Display Tasks
Display tasks print formatted text to the simulation console. They are the primary debugging tool in Verilog testbenches — equivalent to printf in C. Each variant controls when it prints and whether it appends a newline.
| Task | Newline? | When prints | Use case |
|---|---|---|---|
| $display | ✅ Yes | Immediately (active region) | Standard debug print — most common |
| $write | ❌ No | Immediately (active region) | Build a line in parts across multiple calls |
| $writeln | ✅ Yes | Immediately (active region) | Alias of $display (SystemVerilog) |
| $strobe | ✅ Yes | End of time step (after NBA) | Print stable post-NBA values — avoids mid-cycle x |
| $monitor | ✅ Yes | End of time step, whenever any listed signal changes | Continuous automatic logging |
| $monitoron | — | Immediately | Re-enable monitoring after $monitoroff |
| $monitoroff | — | Immediately | Pause monitoring during setup/reset phases |
// ── Basic $display ──────────────────────────────────────────── $display("Hello Verilog!"); // prints with newline $display("a = %b, b = %d", a, b); // formatted output // ── $write — no automatic newline ───────────────────────────── $write("Part1 "); $write("Part2 "); $display("Part3"); // output: "Part1 Part2 Part3\n" // ── $strobe — always shows final stable values ──────────────── always @(posedge clk) begin q <= d; $display("$display: q=%b", q); // may show OLD q (pre-NBA) $strobe ("$strobe: q=%b", q); // always shows NEW q ✅ end // ── $monitor — fires automatically on any signal change ─────── initial $monitor("t=%0t a=%b b=%b out=%b", $time, a, b, out); // Prints every time a, b, or out changes — no explicit call needed // ── Suppress monitor during initialization ──────────────────── initial begin $monitoroff; // pause — suppress noise during reset rst_n = 0; #20; rst_n = 1; #5; $monitoron; // resume — start logging from here end
🔤 Format Specifiers
Format strings use %-prefixed specifiers to control how values are printed. The same specifiers apply to $display, $write, $strobe, $monitor, and all file I/O variants ($fdisplay, $fwrite, etc.).
| Spec | Name | Example output | Notes |
|---|---|---|---|
| %b | Binary | 8'hAB → 10101011 | Exact bit width, leading zeros shown |
| %o | Octal | 8'hAB → 253 | Groups of 3 bits |
| %d | Decimal | 8'hAB → 171 | Unsigned decimal; most readable for counters |
| %h | Hexadecimal | 8'hAB → ab | Lowercase hex; use for addresses and data |
| %H | Hex uppercase | 8'hAB → AB | Same as %h but uppercase |
| %e | Scientific | 3.14 → 3.140000e+00 | Floating point exponential notation |
| %f | Float | 3.14 → 3.140000 | Fixed point decimal; default 6 decimal places |
| %g | Auto float | 3.14 → 3.14 | Shorter of %e or %f |
| %s | String | "abc" → abc | ASCII string from packed reg |
| %c | Character | 65 → A | Single ASCII character (7:0 of value) |
| %t | Time | $time → 100 | Formatted per $timeformat settings |
| %m | Module path | tb.dut.alu | Hierarchical instance name — no argument needed |
| %0d | No padding | 5 → 5 not 5 | %0 prefix removes leading spaces |
| %% | Literal % | % | Escape to print a percent sign |
| \n | Newline | (newline) | Explicit newline inside format string |
| \t | Tab | (tab) | Horizontal tab character |
reg [7:0] data = 8'hAB; integer cnt = 42; // All numeric formats for the same value $display("Binary : %b", data); // Binary : 10101011 $display("Octal : %o", data); // Octal : 253 $display("Decimal : %d", data); // Decimal : 171 (width-padded) $display("Decimal : %0d", data); // Decimal : 171 (no padding) $display("Hex : %h", data); // Hex : ab $display("Hex UC : %H", data); // Hex UC : AB // Time and module path $display("Time=%0t Module=%m", $time); // Time=100 Module=tb.u_dut // Multi-signal formatted line $display("[%0t] data=0x%h cnt=%0d", $time, data, cnt); // [100] data=0xab cnt=42 // $timeformat: sets how %t appears globally // $timeformat(units, precision, suffix, min_width); $timeformat(-9, 2, " ns", 10); // -9=ns, 2 decimal places $display("Time = %t", $time); // Time = 100.00 ns
👁 $monitor and $strobe — Stable Value Printing
Both $strobe and $monitor wait until the end of the current time step (after all non-blocking assignment updates) before printing. This guarantees that post-NBA final values are shown — not intermediate simulation states.
🔵 $strobe — Once per call
// Prints once at end of timestep // when the statement is encountered always @(posedge clk) $strobe("q=%b", q); // Fires every posedge clk // Prints stable q (post-NBA)
🟢 $monitor — Auto on any change
// Set once, fires automatically // whenever ANY listed signal changes initial $monitor("%t q=%b", $time, q); // Fires any time q changes value // Prints at end of that time step
$monitor again replaces the previous one — only the most recently declared $monitor is active. Use $monitoroff / $monitoron to selectively pause logging during initialization or when applying stimulus.
⚙️ Simulation Control Tasks
These tasks control the execution of the simulation itself — stopping it, exiting with a status code, or pausing for interactive debugging.
| Task | Effect | When to use |
|---|---|---|
| $finish | Ends simulation immediately — exits the simulator | Normal end of testbench — always the last call |
| $finish(n) | Ends simulation with detail level n (0=quiet, 1=stats, 2=full) | When you need simulation performance statistics |
| $stop | Pauses simulation — enters interactive mode | Breakpoint debugging — simulation can be resumed |
| $stop(n) | Pauses with detail level n | Debugging with timing statistics |
| $fatal | Terminates with error message and non-zero exit code | Assertion failures — signal test failure to CI systems |
| $error | Prints error message, increments error count | Non-fatal test failures — lets simulation continue |
| $warning | Prints warning, increments warning count | Non-critical anomalies |
| $info | Prints informational message | Progress reporting, pass messages |
integer pass_count=0, fail_count=0; task check_result; input [7:0] expected, actual; input [63:0] test_id; begin if (actual === expected) begin $display("PASS [%0d] expected=%h got=%h", test_id, expected, actual); pass_count = pass_count + 1; end else begin $error("FAIL [%0d] expected=%h got=%h", test_id, expected, actual); fail_count = fail_count + 1; end end endtask initial begin // ... run all tests ... #1000; // Final summary $display("\n===== RESULTS: %0d PASS / %0d FAIL =====", pass_count, fail_count); if (fail_count > 0) $fatal(1, "%0d test(s) failed", fail_count); // non-zero exit else $finish; // success — exit normally end
⏱ Time Functions
Time functions return the current simulation time — essential for timestamping events, measuring intervals, and generating time-relative stimulus.
| Function | Returns | Type | Notes |
|---|---|---|---|
| $time | Current simulation time | 64-bit integer | In units of the current `timescale time unit. Rounds to time unit. |
| $realtime | Current simulation time | real (floating point) | Includes fractional time unit — matches precision setting. |
| $stime | Current simulation time | 32-bit integer | 32-bit truncated version of $time. Wraps at 4.29 billion time units. |
`timescale 1ns/1ps // ── Reading current time ────────────────────────────────────── initial begin #10.5; $display("$time = %0t", $time); // 10 (rounded to 1ns) $display("$realtime = %0.3f", $realtime); // 10.500 (ps precision) end // ── $timeformat configuration ───────────────────────────────── // $timeformat(time_unit, decimal_places, suffix, min_field_width) $timeformat(-9, 3, " ns", 12); // -9 = nanoseconds, 3 decimal places, suffix " ns", min width 12 $display("Current time = %t", $time); // " 10.000 ns" // ── Measuring interval between events ──────────────────────── integer t_start, t_end; initial begin t_start = $time; @(posedge done); t_end = $time; $display("Operation took %0d ns", t_end - t_start); end
🧮 Math Functions
Verilog provides a set of built-in math system functions for both integer and floating-point computations. These are useful in parameterised designs (e.g., $clog2 for deriving address widths) and in testbenches for stimulus generation.
| Function | Returns | Synthesizable? | Example |
|---|---|---|---|
| $clog2(n) | ⌈log₂(n)⌉ — ceiling log base 2 | ✅ Yes (Verilog-2005+) | $clog2(256) = 8 |
| $bits(expr) | Bit width of an expression or type | ✅ Yes | $bits(data) = 32 for 32-bit data |
| Function | Returns | Notes |
|---|---|---|
| $abs(x) | Absolute value |x| | Works on integer and real |
| $sqrt(x) | Square root √x | Returns real; x must be ≥ 0 |
| $pow(x, y) | x raised to power y (xʸ) | Returns real |
| $log(x) | Natural logarithm ln(x) | Returns real |
| $log10(x) | Log base 10 | Returns real |
| $exp(x) | e raised to power x (eˣ) | Returns real |
| $sin(x) | Sine of x (radians) | Returns real |
| $cos(x) | Cosine of x (radians) | Returns real |
| $floor(x) | Floor ⌊x⌋ | Returns real |
| $ceil(x) | Ceiling ⌈x⌉ | Returns real |
| $min(a,b) | Minimum of a and b | Returns same type |
| $max(a,b) | Maximum of a and b | Returns same type |
// ── $clog2 — synthesizable, used in parameter expressions ───── parameter DEPTH = 256; localparam ADDR_W = $clog2(DEPTH); // = 8 localparam CNT_W = $clog2(DEPTH+1); // = 9 (count 0..256) reg [ADDR_W-1:0] ptr; // [7:0] — auto-sized // ── Real math in testbench ──────────────────────────────────── real freq_hz, period_ns, amplitude; freq_hz = 1e9; // 1 GHz period_ns = 1e9 / freq_hz; // 1.0 ns // Sine wave stimulus generation real pi = 3.14159265; integer i; initial for (i=0; i<360; i=i+1) begin amplitude = $sin(i * pi / 180.0); $display("%0d deg: sin = %.4f", i, amplitude); end
🔄 Conversion Functions
Conversion functions translate between Verilog’s different data representations — integers, real numbers, and bit vectors.
| Function | Converts | Notes |
|---|---|---|
| $rtoi(x) | real → integer (truncates toward zero) | $rtoi(3.9) = 3, $rtoi(-3.9) = -3 |
| $itor(n) | integer → real | $itor(7) = 7.0 — for use in real expressions |
| $realtobits(x) | real → 64-bit IEEE 754 representation | Transfers real values across module ports (reals cannot cross ports) |
| $bitstoreal(v) | 64-bit integer → real | Reverse of $realtobits — reconstructs real from bit pattern |
| $signed(expr) | Interprets expression as signed | Changes sign extension behaviour — does not change bit values |
| $unsigned(expr) | Interprets expression as unsigned | Removes signed interpretation — result is always non-negative |
// ── $rtoi / $itor ───────────────────────────────────────────── real r = 3.75; integer n = $rtoi(r); // n = 3 (truncated) real r2 = $itor(n * 2); // r2 = 6.0 // ── $realtobits / $bitstoreal — transfer reals across ports ─── module top; real r_val = 3.14; wire [63:0] wire_bits; real r_recv; assign wire_bits = $realtobits(r_val); // pack real as 64-bit assign r_recv = $bitstoreal(wire_bits); // unpack on other side endmodule // ── $signed / $unsigned — arithmetic interpretation ─────────── reg [7:0] a = 8'hFF; // bit pattern: 11111111 $display("unsigned: %0d", a); // 255 $display("signed: %0d", $signed(a)); // -1 // Signed arithmetic comparison if ($signed(a) < 0) $display("a is negative when treated as signed");
🎲 Random Functions
Random functions generate pseudo-random numbers for constrained-random testbenches, stimulus generation, and fault injection.
| Function / Task | Returns | Notes |
|---|---|---|
| $random | 32-bit signed random integer | Range: −2³¹ to +2³¹−1. Same seed produces identical sequence. |
| $random(seed) | 32-bit signed random integer | Seeded call — provide an integer variable; it gets updated each call. |
| $urandom | 32-bit unsigned random integer | SystemVerilog. Always non-negative. Range: 0 to 2³²−1. |
| $urandom_range(max, min) | Unsigned random in [min, max] | SystemVerilog. Easier than computing range manually. |
| $dist_uniform(seed,lo,hi) | Uniform distribution in [lo, hi] | Verilog PLI — uses Mersenne Twister algorithm. |
| $dist_normal(seed,mean,sd) | Gaussian (normal) distribution | Returns integer approximation of normal distribution. |
| $dist_exponential(seed,mean) | Exponential distribution | Models inter-arrival times in queuing systems. |
// ── $random: basic usage ───────────────────────────────────── reg [7:0] rand_byte; rand_byte = $random; // lower 8 bits of 32-bit random rand_byte = $random % 256; // same — forces 0..255 // ── Bounded random — common patterns ───────────────────────── integer r; r = {$random} % 16; // {} makes it unsigned → 0..15 r = ($random % 10) + 1; // 1..10 // ── With seed for reproducible sequences ───────────────────── integer seed = 42; r = $random(seed); // seed is modified each call // ── Generate random test packet ─────────────────────────────── reg [7:0] pkt [0:63]; integer pkt_len, i; pkt_len = ({$random} % 60) + 4; // 4..63 bytes for (i=0; i<pkt_len; i=i+1) pkt[i] = $random; // ── $dist_uniform — clean bounded generation (PLI) ─────────── integer seed2 = 1234; r = $dist_uniform(seed2, 0, 255); // uniform 0..255
📈 VCD and Waveform Dump Tasks
VCD (Value Change Dump) tasks record signal value changes to a file that can be opened in waveform viewers (GTKWave, Verdi, DVE). Every change to a dumped signal is captured with a timestamp.
| Task | Purpose | Notes |
|---|---|---|
| $dumpfile(“file.vcd”) | Set the VCD output filename | Must be called before any $dumpvars |
| $dumpvars(levels, scope) | Specify which signals to dump | levels=0 dumps all levels; scope=module dumps that hierarchy |
| $dumpall | Force a dump of all current values right now | Used to create a reference point in the waveform |
| $dumpon | Resume VCD dumping after $dumpoff | Re-enables recording |
| $dumpoff | Suspend VCD dumping | Saves file size by excluding uninteresting time windows |
| $dumplimit(size) | Limit VCD file size in bytes | Stops dumping when file reaches this size |
initial begin // ── Configure waveform dump ─────────────────────────────── $dumpfile("sim_output.vcd"); // VCD output file name $dumpvars(0, tb); // dump ALL signals in tb hierarchy $dumpvars(1, tb.dut); // dump only top-level of dut $dumpvars(0, tb.dut.alu); // dump all of alu sub-module // Apply reset stimulus... $dumpoff; // stop recording during reset rst_n = 0; #20; rst_n = 1; $dumpon; // resume recording // Run tests... #5000; $finish; end // ── Memory load tasks (often used with waveform) ────────────── reg [7:0] rom [0:255]; initial begin $readmemh("program.hex", rom); // load hex file into array $readmemh("data.hex", rom, 10, 20); // load into addresses 10..20 $readmemb("data.bin", rom); // load binary format $writememh("out.hex", rom); // write memory to file end
💾 Memory Load and Save Tasks
| Task | Purpose | Format |
|---|---|---|
| $readmemh(file, mem) | Load hex values from file into memory array | Space or newline separated hex values; @addr sets start address |
| $readmemb(file, mem) | Load binary values from file into memory array | Same as $readmemh but values are in binary (0/1) |
| $readmemh(file, mem, start) | Load starting at specific address | start = first array index to write |
| $readmemh(file, mem, start, end) | Load into address range start..end | Limits the region of the array populated |
| $writememh(file, mem) | Save memory array to hex file | Writes hex values, one per line |
| $writememb(file, mem) | Save memory array to binary file | Writes binary values, one per line |
📁 File-Based Tasks and Functions — Introduction
Verilog provides a complete set of file I/O system tasks for reading data from and writing data to files during simulation. This enables testbenches to load stimulus from external files, compare results against golden reference files, and log detailed simulation output for post-processing.
$fopen. Pass this handle to all subsequent read/write operations.$fdisplay, $fwrite, $fstrobe, $fmonitor — all take a file descriptor as first argument.$fclose before $finish to flush buffers and release file handles. Unclosed files may lose the last writes.🔑 $fopen and $fclose
$fopen opens a file for reading or writing and returns an integer file descriptor. $fclose closes it, flushing all buffered writes.
integer log_fd, ref_fd; initial begin // ── Open files ──────────────────────────────────────────── log_fd = $fopen("sim_log.txt", "w"); // write new log ref_fd = $fopen("reference.hex", "r"); // read reference // ── Always check for open failure (fd=0 means failure) ─── if (log_fd == 0) begin $display("ERROR: Cannot open sim_log.txt"); $finish; end // ── Use files... ────────────────────────────────────────── $fdisplay(log_fd, "Simulation started at t=%0t", $time); // ── Always close before $finish ─────────────────────────── $fclose(log_fd); $fclose(ref_fd); $finish; end // ── Multi-channel write — OR descriptors together ───────────── integer f1, f2, both; f1 = $fopen("file1.txt", "w"); f2 = $fopen("file2.txt", "w"); both = f1 | f2; // write to BOTH at once $fdisplay(both, "This goes to both files!");
✍️ Writing to Files
All display tasks have file equivalents — add f prefix and a file descriptor as the first argument. The format string and remaining arguments are identical to the console versions.
| File Task | Console equivalent | Newline? | When writes |
|---|---|---|---|
| $fdisplay(fd, fmt, …) | $display | ✅ Yes | Immediately |
| $fwrite(fd, fmt, …) | $write | ❌ No | Immediately |
| $fstrobe(fd, fmt, …) | $strobe | ✅ Yes | End of time step |
| $fmonitor(fd, fmt, …) | $monitor | ✅ Yes | End of step, on change |
integer fd; reg [7:0] data; initial begin fd = $fopen("output.csv", "w"); // Write CSV header $fdisplay(fd, "time_ns,data_hex,data_dec,data_bin"); // Write data rows as simulation runs repeat(16) begin @(posedge clk); $fdisplay(fd, "%0t,%h,%0d,%b", $time, data, data, data); end // Write without newlines then add one manually $fwrite(fd, "Summary: "); $fwrite(fd, "16 samples written"); $fwrite(fd, "\n"); // manual newline // Write to console AND file simultaneously $fdisplay(fd | 1, "Done!"); // fd|1: fd=file, 1=stdout $fclose(fd); end
📖 Reading from Files
File reading tasks parse text files and populate Verilog variables with the read values. They are essential for loading test vectors, golden reference data, and configuration from external files.
| Task / Function | Purpose | Returns |
|---|---|---|
| $fgetc(fd) | Read one character (byte) from file | Character value as integer; -1 (EOF) at end |
| $fgets(str, fd) | Read one line into string variable | 0 on success, -1 at EOF |
| $fscanf(fd, fmt, vars…) | Read formatted values from file (like C scanf) | Number of items successfully matched |
| $sscanf(str, fmt, vars…) | Parse formatted values from a string | Number of items successfully matched |
| $fread(mem, fd) | Read binary data into memory array | Number of bytes read |
| $feof(fd) | Check if end-of-file reached | Non-zero if at EOF, 0 otherwise |
| $rewind(fd) | Seek back to beginning of file | 0 on success |
| $fseek(fd, offset, origin) | Seek to position in file | 0 on success; origin: 0=start, 1=current, 2=end |
| $ftell(fd) | Return current file position | Byte offset from start of file |
🔍 $fscanf and $sscanf
$fscanf reads formatted values from a file — exactly like C’s fscanf. $sscanf parses a string instead of a file. Both are essential for reading structured test vector files.
// ── $fscanf: read test vectors from CSV ─────────────────────── integer fd, n; reg [7:0] in_a, in_b, expected; string line; initial begin fd = $fopen("vectors.txt", "r"); if (fd == 0) begin $fatal(1, "Cannot open vectors.txt"); end // File format example (one test per line): // 0xAB 0xCD 0x01 // 0xFF 0x00 0xFF while (!$feof(fd)) begin n = $fscanf(fd, "%h %h %h\n", in_a, in_b, expected); if (n == 3) begin // 3 items matched @(posedge clk); a = in_a; b = in_b; @(posedge clk); if (result !== expected) $error("FAIL: a=%h b=%h exp=%h got=%h", in_a, in_b, expected, result); end end $fclose(fd); end // ── $sscanf: parse a string in memory ──────────────────────── reg [255:0] str_buf; integer val1, val2; str_buf = "0xAB 0xCD"; n = $sscanf(str_buf, "%h %h", val1, val2); // n=2, val1=8'hAB, val2=8'hCD
// ── $fgetc: read character by character ────────────────────── integer fd, ch; fd = $fopen("input.txt", "r"); while (1) begin ch = $fgetc(fd); if (ch == -1) break; // -1 = EOF if (ch == "\n") $display(""); // newline else $write("%c", ch); end $fclose(fd); // ── $fgets: read a whole line ───────────────────────────────── reg [1023:0] line_buf; // wide enough for 128 chars integer fd2, ret; fd2 = $fopen("log.txt", "r"); while (!$feof(fd2)) begin ret = $fgets(line_buf, fd2); // ret=0 success, -1=EOF if (ret != -1) $display("Line: %s", line_buf); end $fclose(fd2);
💡 Complete File I/O Examples
Fig 13 — Golden Reference Comparison Testbench
module golden_tb; reg [7:0] a, b; wire [7:0] result; reg clk = 0; alu_dut dut(.a(a), .b(b), .out(result)); always #5 clk = ~clk; integer stim_fd, gold_fd, log_fd; integer n, pass=0, fail=0; reg [7:0] exp; initial begin stim_fd = $fopen("stimulus.txt", "r"); gold_fd = $fopen("golden.txt", "r"); log_fd = $fopen("results.log", "w"); $fdisplay(log_fd, "%-8s %-8s %-8s %-8s %-5s", "time", "a", "b", "result", "PASS?"); while (!$feof(stim_fd)) begin n = $fscanf(stim_fd, "%h %h\n", a, b); // read a, b n = $fscanf(gold_fd, "%h\n", exp); // read expected @(posedge clk); #1; if (result === exp) begin $fdisplay(log_fd, "%t %h %h %h PASS", $time, a, b, result); pass++; end else begin $fdisplay(log_fd, "%t %h %h %h FAIL(exp=%h)", $time, a, b, result, exp); fail++; end end $fdisplay(log_fd, "\nTotal: %0d pass, %0d fail", pass, fail); $fclose(stim_fd); $fclose(gold_fd); $fclose(log_fd); if (fail) $fatal(1, "%0d failures", fail); else $finish; end endmodule
Fig 14 — Waveform + Log File simultaneously
integer log_fd; initial begin // VCD waveform $dumpfile("waves.vcd"); $dumpvars(0, tb); // Text log log_fd = $fopen("sim.log", "w"); $timeformat(-9, 2, " ns", 10); // fd|1 writes to both log file AND console (fd=1 is stdout) $fmonitor(log_fd | 1, "%t clk=%b d=%b q=%b", $time, clk, d, q); #200; $fclose(log_fd); $finish; end
📋 Summary Reference
Display and Monitor Tasks
| Task | Output | Newline | Timing |
|---|---|---|---|
| $display | Console | ✅ | Active region (immediate) |
| $write | Console | ❌ | Active region (immediate) |
| $strobe | Console | ✅ | Observed region (post-NBA) |
| $monitor | Console | ✅ | Observed region, auto on change |
| $fdisplay | File | ✅ | Active region (immediate) |
| $fwrite | File | ❌ | Active region (immediate) |
| $fstrobe | File | ✅ | Observed region (post-NBA) |
| $fmonitor | File | ✅ | Observed region, auto on change |
File I/O Quick Reference
| Task / Function | Operation | Returns |
|---|---|---|
| $fopen(name, mode) | Open file | File descriptor (0=fail) |
| $fclose(fd) | Close file (flush) | — |
| $feof(fd) | Check end-of-file | Non-zero at EOF |
| $fgetc(fd) | Read one character | Integer (-1=EOF) |
| $fgets(str, fd) | Read one line | 0=ok, -1=EOF |
| $fscanf(fd, fmt, …) | Read formatted values | Items matched |
| $sscanf(str, fmt, …) | Parse string | Items matched |
| $fread(mem, fd) | Read binary data | Bytes read |
| $fseek(fd, off, org) | Seek in file | 0=success |
| $ftell(fd) | Current position | Byte offset |
| $rewind(fd) | Seek to start | 0=success |
| $readmemh(file, mem) | Load hex file → array | — |
| $readmemb(file, mem) | Load binary file → array | — |
| $writememh(file, mem) | Save array → hex file | — |
$dumpfile+$dumpvars (waveform) with $fopen+$fdisplay (text log) and self-checking assertions that call $fatal on failure. This gives you waveform debug capability, a machine-readable log for CI, and automatic pass/fail detection — all three essential elements of a production-quality testbench.
