t27.aiРусский

Debug with waves

You will learn

How to go from a symptom to a signal, cycle by cycle, on a real measured bug.

Here is a bug found with waves, end to end. A UART link on the bench requested 115,200 baud and the wire carried 115,385 -- a +0.16 % error from the clock divider, invisible in code, obvious in a capture. Requested 921,600, the wire carries 923,077, the same fractional error; 3,000,000 divides exactly and is exact on the wire. The measurement names the fix: choose divisors that land on integers. Waves turn a symptom (bytes lost) into a number (0.16 %) into an edit.

Try it

Compute what divider would put 115,200 on the wire exactly; check it against the 921,600 and 3,000,000 rows in the widget.

Open the interactive lesson →

tri fpga-wire · the baud rate actually on the wire
tri fpga-wire · the baud rate actually on the wire ↗

CP2102N on a direct USB port, no hub. Requested 115,200 puts 115,385 on the wire (+0.16 %), 921,600 puts 923,077 (+0.16 %), 3,000,000 is exact.

specs/fpga/testbench/vcd_trace_tb.t27

// SPDX-License-Identifier: Apache-2.0
// t27/specs/fpga/testbench/vcd_trace_tb.t27
// VCD Trace Testbench
// Tests waveform dump generation, signal hierarchy, and timestamp management
// phi^2 + 1/phi^2 = 3 | TRINITY

module VCD_Trace_Testbench {
    use fpga::vcd_trace::VcdTrace;

    const CLK_PERIOD : u32 = 20;
    const MAX_SIGNALS : u32 = 256;
    const TIMESTAMP_RES_PS : u32 = 10;

    var clk : bool = false;
    var rst_n : bool = false;
    var trace_en : bool = false;
    var signal_count : u32 = 0;
    var timestamp_ps : u32 = 0;
    var dump_complete : bool = false;

    var test_passed : u32 = 0;
    var test_failed : u32 = 0;

    fn tick() {
        clk = false;
        clk = true;
        timestamp_ps = timestamp_ps + TIMESTAMP_RES_PS;
    }

    fn reset() {
        rst_n = false;
        tick();
        tick();
        rst_n = true;
        tick();
    }

    fn advance_time(steps : u32) -> u32 {
        var i : u32 = 0;
        while i < steps {
            tick();
            i = i + 1;
        }
        return timestamp_ps;
    }

    fn format_timestamp(ps : u32) -> u32 {
        return ps / 1000;
    }

    test test_reset_state {
        reset();
        invariant trace_en == false;
        invariant dump_complete == false;
    }

    test test_timestamp_advance {
        timestamp_ps = 0;
        var t : u32 = advance_time(10);
        invariant t == 100;
    }

    test test_format_timestamp {
        var ns : u32 = format_timestamp(10000);
        invariant ns == 10;
    }

    test test_max_signals {
        invariant MAX_SIGNALS == 256;
    }

    test test_timestamp_resolution {
        invariant TIMESTAMP_RES_PS == 10;
    }

    test test_tick {
        tick();
        invariant clk == true;
        invariant timestamp_ps == 10;
    }

    invariant max_signals_positive : MAX_SIGNALS > 0;
    invariant resolution_positive : TIMESTAMP_RES_PS > 0;

    bench bench_vcd_trace {
        reset();
        trace_en = true;
        advance_time(100);
        trace_en = false;
    }
}

Open the lesson's spec in the player ↗

All lessons