Skip to content

Session 05: RTL Design & Verification

In this session, I learned how to write Verilog for describing digital circuit in Register-Transfer Level (RTL). I am very struggle to study what I am learn.... Maybe my brain would be collapsed, so I learned Verilog with dialog to Chat GPT.

Homework

  • Write Verilog for your project’s core module (aim for 10-30 lines to start)
  • Integrate with any provided library modules (e.g., debounce, UART, PWM) — create a top-level wrapper
  • Simulate with a testbench and examine waveforms in GTKWave
  • Run linter (verilator –lint-only) and fix any warnings

My Project

As my IC project, I am planning to design IC incorporating memory registers (such as flip-flops) into a 4-bit adder-subtractor to perform addition and subtraction while maintaining some input state. However, I have no idea how to design it. (I was not sure whether it could be possible to design…).

So, I asked ChatGPT as follow:

I am studying microelectronics. For my final project, I need to design a simple IC. Is it possible to design an IC that performs addition and subtraction while maintaining some input state by adding memory registers (such as flip-flops) to a 4-bit adder-subtractor?

Then, I got an some answer to design as following

Basic Architecture

         +-------------------+
A[3:0] ->|                   |
         |                   |
         |  4bit Adder /     |----> Result[3:0]
Breg ----|  Subtractor       |
         |                   |
         +-------------------+
                 |
                 |
            +----------+
B[3:0] ---->| 4bit     |
Load ------>| Register |
Clock ----->| (D-FF)   |
            +----------+

The schema of 4bit adder and subtactor are that I described in the last session.

The schema of 4 bit register based on D-Flip Flop are as follow:

Source: 4 bit shift register with using d flip flop in MultisimLive

Taxonomy

  • Flip-Flop: A fundamental element of digital memory circuits (sequential circuits) that holds 1-bit information in either a “0” or “1” state. It captures input data at the timing of a clock signal and determines the output. Main types include D-type (data retention), JK-type(toggle/control) and RS-type.
  • Latch: A logic IC design to temporarily store information. It possesses the property of holding a signal steady once it is input, without releasing it until the next update instruction arrives. Latch is disadvantage against flip-flop as unpreditable timing, hard analyzing and mistake in synchronous design.
  • RTL: Register-Transfer Level describe digital circuits in terms of Register(flip-flops that store data), combinational logic (transform data between registers) and Transfer(data moving from one register to another)

Learn verilog

Modules

Here I wrote the class sample verilog of “my_module”

module my_module (
    input   wire            clk, // Clock
    input   wire            rst_n,  // Reset (active low)
    input   wire    [7:0]   data_in, // 8-bit input
    output  reg     [7:0]   data_out
);

    // Internal signals
    wire    [7:0]   intermediate;
    reg     [7:0]   stored;

    // logic goes here
endmodule

If I want to define my module, write as follow (define module_name as I like):

module module_name(

    (define a register (signals) here that could be connected to outside the modules)

);


    (define internal logics here)

endmodule

This “my_module” define the port as following

  • clk: input clock wire (to control the timing)
  • rst_n: input reset signal (when it is LOW(=0), the reset would be active. usually it could be HIGH(=1)).
  • [7:0] data_in: input 8bit data
  • [7:0] data_out: output 8bit data

I asked ChatGPT as follow:

Please teach me what is defined in this my_module verilog.

And ChatGPT answered;

it defines the module = circuit block. In the Verilog, module means parts of digital circuit. This module define the block that treate 8bit input/output data.

And GPT shows the fighre of this module as follow:

           clk
            │
        +-----------+
rst_n ->|           |
data_in>| my_module |-> data_out (register)
        |           |
        +-----------+

When I saw this figure, I could understand totally what verilog is used for.

Assign and Always

In asking the definition of my_module to ChatGPT, GPT showed the meaning of the circuit definition in Verilog, in other words, how to write the circuit in Verilog.

First is the method to use “assign”. For example, here is “AND” circuit.

assign y = a & b;

The circuit of this assign logic is here:

 a ----\
        AND ---- y
 b ----/

Another way to write the circuit is to use “always block”. Here is the same “AND” circuit when using always block

always @(*)
    y = a + b;

Combinational vs Sequential

In the class page, those are defined as follow:

  • Combinational Logic has no memory - output depends on current inputs.
  • Sequential Logic has memory - uses flip-flops triggered by a clock.

ChatGPT also ansereed the difference of combinational and sequential when ansered the my_module definitions. According to GPT’s answer, Combinational logic is the logic that the output is determined solely by the input, as shown in the above exapmle (in “assign and always” seciton).

I thought the Sequential Logic is very important. According to the GPT’s explanation, Sequential Logic is the logic that possessing a past state (ex. counter, register, state machine…).

Using always block, the sequential logic define as following example:

always @(postedge clk)
    q <= d;

I asked GPT

Please describe a circuit diagram of the above verilog: always @(postedge clk) q <= d;

And, GPT says this is a circuit that captures input “d” on the clock rising edge and holds it as the next state in “q”. This is simple D Flip-Flop circuit.

        +-------------+
 d ---->| D       Q   |----> q
        |             |
 clk -->|>            |
        +-------------+

The clock signal works as following.

clk

0 ___/‾‾‾\___/‾‾‾\___
     ↑     ↑
   posedge

When the clock signal rising (Turn to HIGH), “q <= d” is executed. “Postage” means this signal rising. The following show the transison of each signals in time.

Time d q
t0 0 0
t1 (postage) 1 1
t2 0 1
t3 (postage) 0 0

Important points are:

  • The value is updated only at the rising edge of the clock
  • It holds the value at all other times

The following is the flip-flop circuit in the class page.

always @(postedge clk or negedge rst_n) begin
    if (!rst_n) begin
        // Reset values
        q <= 0;
    end
    else begin
        // Normal operation
        q <= d;
    end
end

“postedge” is the timing when rising the signal, on the other hand “negedge” is the timing when falling the signal. This sample circuit have two signal, clock (“clk”) and reset (“rst_n”). When clock signal is rising, the value is update. When reset would be active (become low), the value change to 0 (zero). The circuit diagram of this verilog is here:

                +-------------+
 d ------------>| D       Q   |----> q
                |             |
 clk ---------->|>            |
                |             |
 rst_n -------->| reset       |
                +-------------+

important: <= vs. =

As written in the class page, “<=” and “=” is different.

  • ”=”: it is “blocking”. It used for writing combinational logic.
  • ”<=”: it is “non-blocking. IT used for writing sequential logic.

And important rule is: Use <= inside always @(posedge clk) blocks!

Test bench

Here is the test bench in the class page.

`timescale 1ns/1ps

module my_module_tb;

    // Inputs are reg -> define the store
    reg clk, rst_n, data_in;

    // Outputs are wire (DUT drives them)
    wire data_out;

    my_module dut (
        .clk(clk),
        .rst_n(rst_n),
        .data_in(data_in),
        .data_out(data_out)
    );

    // Clock generation
    always #10 clk = ~clk;

    // Test stimulus
    initial begin
       $dumpfile("waves.vcd");
       $dumpvars(0, my_module_tb);

       // Initialize
       clk = 0;
       rst_n = 0;
       data_in = 0;

       // Reset
       #40 rst_n = 1;

       // Test cases
       #20 data_in = 1;
       #20 data_in = 0;

     #200 $finish;

    end
endmodule

First, defining the unit and accuracy of simulation time.

`timescale 1ns/1ps
  • 1ns.... the unit of time (nano second)
  • 1ps.... simulation accuracy

It means

#10 = 10ns

“module my_module_tb ~” define the test module. Because test bench module works only inside the simulation, it doesn’t have input/output ports.

The following part define the input/output signals for “my_module”

// Inputs are reg -> define the store
    reg clk, rst_n, data_in;

    // Outputs are wire (DUT drives them)
    wire data_out;

    my_module dut (
        .clk(clk),
        .rst_n(rst_n),
        .data_in(data_in),
        .data_out(data_out)
    );

The following part generate a clock.

// Clock generation
    always #10 clk = ~clk;

It means clock reverse in 10 nano second. That works in 20nano second cycle as follow. That means 50MHz clock.

clk

0 ____----____----____
      10ns   10ns

The following part define the simulation case. “initial” block define that execute only once at the start of the simulation.

// Test stimulus
    initial begin
       $dumpfile("waves.vcd");
       $dumpvars(0, my_module_tb);

       // Initialize
       clk = 0;
       rst_n = 0;
       data_in = 0;

       // Reset
       #40 rst_n = 1;

       // Test cases
       #20 data_in = 1;
       #20 data_in = 0;

     #200 $finish;

    end

The following define the output file of simulation result that could see in simulation software like GTKWave, ModelSim,,,,.

$dumpfile("waves.vcd");
$dumpvars(0, my_module_tb);

The test case defines…

  • initialized clk, rst_n, data_in as 0 (zero).
  • after 40 nano second, reset (rst_) turn to 1.
  • after more 20 nano second (60 nano second after starting simulation), data_in turns 1.
  • after more 20 nano second (80 nano second after starting simulation), data_in turns 0.
  • after more 200 nano second (280 nano second after starting simulation), the simulation finished.

Simulation and Debugging

To start simulation, first compile each Verilog file as follow.

iverilog -o sim.vpp my_module.v my_module_tb.v

If something warning or error happens, it could be outputed as follow:

my_module_tb.v:11: warning: Port 3 (data_in) of module my_module expects 8 bit(s), given 1.
my_module_tb.v:11:        : Padding 7 high bits of the port.
my_module_tb.v:11: warning: Port 4 (data_out) of module my_module expects 8 bit(s), given 1.
my_module_tb.v:11:        : Padding 7 high bits of the port.

Then, if the compile finished, “sim.vpp” file are generated. So, run the following simulation command.

vvp sim.vvp

Then outputed the simulation result.

VCD info: dumpfile waves.vcd opened for output.
my_module_tb.v:38: $finish called at 280000 (1ps)

And, view the waveforms on GTKWave.

gtkwave waves.vcd 

The simulation result show on the GTKWave

Assignment 1: Write a verilog of core module

I asked ChatGPT:

Please write the core module of that my project

And, ChatGPT suggest the following code.

// alu_core.v
// 4-bit add/sub core (combinational)
// sub=0: a + b
// sub=1: a - b  (implemented as a + (~b) + 1)

module alu_core (
    input  wire [3:0] a,
    input  wire [3:0] b,
    input  wire       sub,
    output wire [3:0] y,
    output wire       carry_out
);
    wire [3:0] b_xor;
    wire [4:0] sum;

    assign b_xor = b ^ {4{sub}};          // invert b when subtracting
    assign sum   = {1'b0, a} + {1'b0, b_xor} + {4'b0, sub};

    assign y         = sum[3:0];
    assign carry_out = sum[4];            // for subtraction, this is "no-borrow" flag
endmodule

This is a basic circuit block for adder/subtract calculation based on 4-bit adder. In this circuit, subtract is executed by two’s complement.

A - B = A + (~B) + 1

two’s complement

In IC circuits (and consequently in all computers with ICs at their core), calculations can only be performed using two numbers: 0 and 1. This is achieved by using the register’s on (1) and off (0) states for computation. Therefore, unlike how we perform calculations in the real world using + and - in decimal numbers, we cannot compute negative numbers using symbols like “minus.”

Therefore, when calculating negative numbers, the sign is determined by whether the most significant bit is 0 or 1.For example, 0110 (decimal 6) has a most significant bit of 0, so it is positive. 1110 (decimal -6) has a most significant bit of 1, so it is negative.

The remaining three bits represent the numerical value. However, there are various ways to express this number. The notation we are accustomed to in the real world treats the most significant bit as the sign and the remaining three bits as the absolute value. For example, 0110 is 6 in decimal, and 1110 is -6 in decimal. However, in this notation, 0000 and 1000 both become +0 and -0, resulting in two representations for zero. This complicates addition and subtraction operations, making the computer itself more complex.

Therefore, when representing positive and negative numbers on a computer, two’s complement is used.

In two’s complement representation, for a positive number, we consider how much greater it is than zero; for a negative number, how much less it is than zero. Furthermore, within the digits the computer can handle, the most significant digit is used to determine whether the number is positive or negative. A value of 0 indicates a positive number (or zero), while a value of 1 indicates a negative number.

For example, in 4 bits, -2 is the value obtained by subtracting 2 from 0. How do we represent this in binary? Two’s complement represents the number by placing the binary number with all zeros and the binary number with all ones side by side, forming a ring-like shape, as shown in the following diagram. For example, in 4 bits, 0000 is decimal 0, so 1111 becomes decimal -1.

This arrangement makes clockwise the positive direction and counterclockwise the negative direction, allowing us to determine whether the number is greater or less than zero. In other words, with 4 bits, you can handle decimal numbers ranging from -8 to +7.

The number of values that can be represented in n bits is \(2^n\). Of these \(2^n\) possibilities, half are used for negative numbers and the other half for zero and positive numbers. Therefore, negative numbers can range from \(-2^n-1\) to \(2^{n-1}-1\), and positive numbers can range from \(2^{n-1}\) to \(2^{n-1}-1\), minus one to represent zero. Therefore, the range of numbers that can be represented in two’s complement representation with n bits is, for an integer x, can be expressed as:

\[ -2^{n-1} \leqq x \leqq 2^{n-1} - 1 \]

For example, in case of 8bit is expressed as below,

\[ -128 \leqq x \leqq 127 \]

So, we need to calculate two’s complement when doing subtract calculation. The typical way is:

  1. make one’s complement
  2. Then add 1 to it.

The one’s complement is obtained by flipping the bits in a binary number. For example, 0110b becomes 1001b, and 1110b becomes 0001b.

Adding 1 to this result yields the two’s complement.

That is, adding 1 (0001) to 1001b gives 1010b, and adding 1 (0001) to 0001b gives 0010b.

The operation to create a complement, i.e., swapping the 0s and 1s in a binary number, is a bit inversion (NOT) in programming. This is done using the tilde operator (~). To obtain the two’s complement, add 1 to the bit-inverted value. For example, in C language, it is written as follows:

char a = 0b00001111;
int inverted = ~a;
int complement2 = inverted + 0b00000001;

The result of this program are:

Original: (15) in binary 00001111
One's compelent: (-16) in binary 11110000
Two's compelent: (-15) in binary 11110001

sum and subtract in Verilog

In this Verilog, if “sub” is LOW (0), the circuit works as adder mode. It works as follow:

XOR result

b XOR sub(0) = b

in adder:

A + B + sub(0)

mean

A + B

If “sub” is HIGH (1), the circuit works as subtact mode. It works as follow:

XOR result

b xor sub(1) = ~b

In adder:

a + (~b) + sub(1)

It means

A - B

As shown in the top in this page, 4 bit adder/subtractor consists of 4 full-adder chains and 4 XOR gate.

The four adder chains is expressed in Verilog as following line:

assign b_xor = b ^ {4{sub}};          // invert b when subtracting

The four XOR gate is expressed as following line:

wire [3:0] b_xor;

Here is expressed a 4-bit ripple carry adder

assign sum   = {1'b0, a} + {1'b0, b_xor} + {4'b0, sub};

Here, {} express concatenation. if a = 0001 (4bit), {1’b0,a} would be 00001 (5bit). In case of {4’b0, sub}, it makes carry-in. If sub = 0 (add mode), it would be 00000, if sub = 1 (subtract mode), it would be 00001.

Assignment 2: create a top-level wrapper

I asked ChatGPT:

Please write top-level wrapper of that my project with using alu_core module

And, ChatGPT suggest the following code.

// top_wrapper.v
// Registers + core integration (simple "system")
// - load_a: latch in_a into reg_a
// - load_b: latch in_b into reg_b
// - exec  : compute reg_a +/- reg_b and store into acc

module top_wrapper (
    input  wire       clk,
    input  wire       rst,      // synchronous active-high reset
    input  wire       load_a,
    input  wire       load_b,
    input  wire       exec,
    input  wire       sub,
    input  wire [3:0] in_a,
    input  wire [3:0] in_b,
    output wire [3:0] acc,
    output wire       carry_out
);
    reg  [3:0] reg_a;
    reg  [3:0] reg_b;
    reg  [3:0] acc_r;

    wire [3:0] y_w;
    wire       c_w;

    // integrate library/core module here (core is your project's logic)
    alu_core u_core (
        .a(reg_a),
        .b(reg_b),
        .sub(sub),
        .y(y_w),
        .carry_out(c_w)
    );

    // sequential logic: hold inputs and result
    always @(posedge clk) begin
        if (rst) begin
            reg_a <= 4'b0000;
            reg_b <= 4'b0000;
            acc_r <= 4'b0000;
        end else begin
            if (load_a) reg_a <= in_a;
            if (load_b) reg_b <= in_b;
            if (exec)   acc_r <= y_w;
        end
    end

    assign acc       = acc_r;
    assign carry_out = c_w;   // combinational flag from current reg_a/reg_b/sub
endmodule

And, I asked GPT to show the diagram of this top wrapper circuit:

                      +-------------------------------+
                      |          top_wrapper          |
                      |                               |
                      |   +-----------------------+   |
in_a[3:0] ----------->|-->|       A register      |---|----+
                      |   |    (hold in load_a)   |   |    |
                      |   +-----------------------+   |    |
                      |                               |    |
in_b[3:0] ----------->|-->|       B register      |---|----|----+
                      |   |    (hold in load_b)   |   |    |    |
                      |   +-----------------------+   |    |    |
                      |                               |    |    |
sub ----------------->|-------------------------------|----|----|----+
                      |                               |    |    |    |
                      |        +----------------------+    |    |    |
                      |        |                           |    |    |
                      |        v                           v    v    v
                      |   +-------------------------------------------+
                      |   |                alu_core                   |
                      |   |                                           |
                      |   |   b_xor = b ^ {4{sub}}                    |
                      |   |   sum   = a + b_xor + sub                 |
                      |   |                                           |
                      |   |   add : sub=0 -> A + B                    |
                      |   |   sub : sub=1 -> A + (~B) + 1 = A - B     |
                      |   +-------------------+-----------------------+
                      |                       | 
                      |                       |
                      |                    y_w[3:0]
                      |                       |
                      |                       v
                      |   +-------------------------------+
exec ---------------->|-->|    ACC register               |-----> acc[3:0]
                      |   |   (hold the result inexec)    |
clk ----------------->|   +-------------------------------+
rst ----------------->|                              
                      |                              
                      |-----------------------------------------> carry_out
                      |                              
                      +-----------------------------------------+

load_a is a clock line for reg_a, load_b is a clock line for reg_b. When load_a rise HIGH, in_a[3:0] is stored in reg_a[3:0]. When load_b rise HIGH, in_a[3:0] is stored in reg_b[3:0].

alu_core is loaded with assigning a = reg_a, b = reg_b, sub=sub, y=y_w and carry_out = c_w. Then, caluclate as follow:

when sub = 0, add mode (a + b).

when sub = 1, subtractmode (a - b)

In the clock when exec rise HIGH, the output of alu_core (y_w) is stored in reg acc_r, and that value is output as acc[3:0]

This sequential logic is controled to hold each value in each registers.

always @(posedge clk) begin
        if (rst) begin
            reg_a <= 4'b0000;
            reg_b <= 4'b0000;
            acc_r <= 4'b0000;
        end else begin
            if (load_a) reg_a <= in_a;
            if (load_b) reg_b <= in_b;
            if (exec)   acc_r <= y_w;
        end
    end

Assignment 3: Simulation

I asked ChatGPT:

Please write test bench of that my project.

And, ChatGPT suggest the following code.

// tb_top.sv
`timescale 1ns/1ps

module tb_top;
    logic       clk;
    logic       rst;
    logic       load_a, load_b, exec, sub;
    logic [3:0] in_a, in_b;
    wire  [3:0] acc;
    wire        carry_out;

    top_wrapper dut (
        .clk(clk),
        .rst(rst),
        .load_a(load_a),
        .load_b(load_b),
        .exec(exec),
        .sub(sub),
        .in_a(in_a),
        .in_b(in_b),
        .acc(acc),
        .carry_out(carry_out)
    );

    // 10ns period clock
    initial clk = 1'b0;
    always #5 clk = ~clk;

    initial begin
        $dumpfile("tb_top.vcd");
        $dumpvars(0, tb_top);

        // initialize
        rst    = 1'b0;
        load_a = 1'b0;
        load_b = 1'b0;
        exec   = 1'b0;
        sub    = 1'b0;
        in_a   = 4'h0;
        in_b   = 4'h0;

        // ---- reset ----
        @(negedge clk);
        rst = 1'b1;
        @(posedge clk);   // In this posedge works reset.
        @(negedge clk);
        rst = 1'b0;

        // ---- load A=3  ----
        @(negedge clk);
        in_a   = 4'd3;
        load_a = 1'b1;
        @(posedge clk);   // In this posedge, reg_a <= 3
        @(negedge clk);
        load_a = 1'b0;
        $display("[%0t] load_a done", $time);

        // ---- load B=5 ----
        @(negedge clk);
        in_b   = 4'd5;
        load_b = 1'b1;
        @(posedge clk);   // In this posedge, reg_b <= 5
        @(negedge clk);
        load_b = 1'b0;
        $display("[%0t] load_b done", $time);

        // ---- ADD: 3 + 5 = 8 ----
        @(negedge clk);
        sub  = 1'b0;
        exec = 1'b1;
        @(posedge clk);   // In this posedge, acc <= 8
        @(negedge clk);
        exec = 1'b0;
        @(posedge clk);   // wait 1 clock for displaying
        $display("[%0t] ADD 3+5 => acc=%0d (0x%0h), carry=%0b", $time, acc, acc, carry_out);

        // ---- SUB: 3 - 5 = -2 = 0xE ----
        @(negedge clk);
        sub  = 1'b1;
        exec = 1'b1;
        @(posedge clk);   // In this postage acc <= 0xE
        @(negedge clk);
        exec = 1'b0;
        @(posedge clk);
        $display("[%0t] SUB 3-5 => acc=%0d (0x%0h), carry(no-borrow)=%0b", $time, acc, acc, carry_out);

        // ---- Change external input (not loaded ----
        @(negedge clk);
        in_a = 4'd9;
        in_b = 4'd2;

        // reg_a/reg_b is still 3,5, so acc is still 8
        @(negedge clk);
        sub  = 1'b0;
        exec = 1'b1;
        @(posedge clk);
        @(negedge clk);
        exec = 1'b0;
        @(posedge clk);
        $display("[%0t] HOLD-CHECK => acc=%0d (0x%0h) (expected 8)", $time, acc, acc);

        // ---- Only update B: 3 + 2 = 5 ----
        @(negedge clk);
        load_b = 1'b1;
        @(posedge clk);   // In this posedge, reg_b <= 2
        @(negedge clk);
        load_b = 1'b0;
        $display("[%0t] load_b(2) done", $time);

        @(negedge clk);
        exec = 1'b1;
        @(posedge clk);   // In this posedge, acc <= 5
        @(negedge clk);
        exec = 1'b0;
        @(posedge clk);
        $display("[%0t] ADD 3+2 => acc=%0d (0x%0h)", $time, acc, acc);

        repeat (2) @(posedge clk);
        $finish;
    end
endmodule

Then, run the following commands, and got the result.

(base) yosuke@ysk-M1Pro design % iverilog -g2012 -o sim_addr-subtract.vvp tb_top.sv alu_core.v top_wrapper.v
(base) yosuke@ysk-M1Pro design % vvp sim_addr-subtract.vvp                                                  
VCD info: dumpfile tb_top.vcd opened for output.
[40000] load_a done
[60000] load_b done
[85000] ADD 3+5 => acc=8 (0x8), carry=0
[105000] SUB 3-5 => acc=14 (0xe), carry(no-borrow)=0
[135000] HOLD-CHECK => acc=8 (0x8) (expected 8)
[150000] load_b(2) done
[175000] ADD 3+2 => acc=5 (0x5)
tb_top.sv:118: $finish called at 195000 (1ps)

Finally, show the waveform.

gtkwave tb_top.vcd

  • When next postage of load_a=1, reg_a=3
  • When next postage of load_b=1, reg_b=5
  • When next postage of exec=1, acc_r=8
  • When next postage of sub=1, acc_r=0xE

Note that acc=14 (0xe) is 1110b, it represents -2 in 4-bit two’s complement.

Assignment 4: Run linter

Executing the following command.

verilator --lint-only -Wall alu_core.v

and the result is…

%Warning-EOFNEWLINE: alu_core.v:21:10: Missing newline at end of file (POSIX 3.206).
                                     : ... Suggest add newline.
   21 | endmodule
      |          ^
                     ... For warning description see https://verilator.org/warn/EOFNEWLINE?v=5.046
                     ... Use "/* verilator lint_off EOFNEWLINE */" and lint_on around source to disable this message.
%Error: Exiting due to 1 warning(s)

The verilog should be finished with one empty line, so I added one more empty line to alu_core.v file. Then execute again.

verilator --lint-only -Wall alu_core.v
- V e r i l a t i o n   R e p o r t: Verilator 5.046 2026-02-28 rev vUNKNOWN-built20260228
- Verilator: Built from 0.033 MB sources in 2 modules, into 0.010 MB in 3 C++ files needing 0.000 MB
- Verilator: Walltime 0.004 s (elab=0.000, cvt=0.001, bld=0.000); cpu 0.004 s on 1 threads; allocated 9.297 MB

Files