Menu

Verilog $dumpfile и $dumpvars: получение VCD waveform

Как добавить VCD-вывод waveform в testbench - $dumpfile, $dumpvars, выбор scope и как смотреть получившийся файл в GTKWave или редакторе в браузере.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Waveform, который тебе реально нужен

$display печатает текст. Это норм для быстрой проверки sanity, но в момент, когда ты отлаживаешь счётчик с проблемой тайминга или state machine, который застрял, хочется картинку: сигналы, нарисованные как напряжения во времени, скроллящиеся, зумирующиеся, с курсором, который можно бросить на любой переход.

Эта картинка - VCD-файл - "value change dump", текстовый формат, стандартизированный IEEE в оригинальной спеке Verilog. Каждый современный симулятор может его писать; каждый современный просмотрщик waveform может его читать. Цена производства - две строки в testbench.

Две строки

Внутри блока initial - обычно того же, что держит твои стимулы - добавь:

$dumpfile("dump.vcd");
$dumpvars(0, test);
  • $dumpfile именует выходной файл. Передавай любой путь; если в нём нет директории, он попадёт в рабочую директорию симулятора.
  • $dumpvars(0, test) говорит "запиши каждый сигнал в scope test и каждый sub-scope, рекурсивно, с unlimited глубиной".

Это весь setup. Прогони симуляцию - у тебя будет dump.vcd, который можно открыть в GTKWave или во вкладке Waveform редактора в браузере.

Полный пример

Запусти. Вкладка Waveform теперь показывает три сигнала - clk, reset, count - нарисованные на всём времени симуляции. Можно бросить курсор в любую точку и прочитать значения сигналов в этот момент. Можно зумировать drag'ом, чтобы рассмотреть один такт.

Что делает первый аргумент $dumpvars

$dumpvars(depth, scope) обходит scope и каждый sub-instance в нём, записывая сигналы до depth уровней. Значения depth:

  • 0 - unlimited. Каждый сигнал в scope и каждый вложенный подмодуль записывается.
  • 1 - только сигналы, объявленные прямо в scope. Подмодули не записываются.
  • 2 - scope плюс один уровень подмодулей.
  • N - scope плюс N-1 уровней подмодулей.

На практике $dumpvars(0, test) - то, что использует почти каждый testbench. Захватить всё дёшево (VCD хранят только переходы, не steady state), и не хочется в середине отладки узнать, что нужный сигнал не был задампен.

Если дизайн реально большой и VCD слишком тяжёлый, можно дампить выборочно:

$dumpvars(0, dut.inner_module);     // только интересный подмодуль
$dumpvars(0, dut.regs);             // только register file

$dumpvars можно вызывать несколько раз, чтобы накопить scope.

Дамп конкретных сигналов

$dumpvars также принимает список конкретных сигналов вместо целого scope:

$dumpvars(0, test.clk, test.reset, dut.count);

Это записывает только эти три сигнала. Полезно, когда дизайн огромный и важна только горстка сигналов. Для маленьких - дампить всё проще.

Управление дампом посреди симуляции

Две парные задачи с $dumpvars:

  • $dumpoff - приостановить дамп. Дальнейшие изменения не попадают в VCD.
  • $dumpon - возобновить дамп.
initial begin
    $dumpfile("dump.vcd");
    $dumpvars(0, test);

    // ... интересный регион ...

    #1000 $dumpoff;
    // ... длинный скучный регион, который не нужен в VCD ...
    #5000 $dumpon;

    // ... ещё один интересный регион ...
end

Так пропускают скучную часть "крутится миллион тактов" длинного теста, не получая 5GB VCD-файл.

Просмотр результата

Два основных способа:

В редакторе в браузере

Редактор на этой странице рендерит VCD inline. Прогони симуляцию; переключись на вкладку Waveform; сигналы появятся с иерархией слева и draggable-курсором справа. Кликни в любую точку trace, чтобы бросить курсор; он покажет значения сигналов в этот момент маленькими пилюлями рядом с именами сигналов.

В GTKWave

Если прогонял симуляцию локально (iverilog -o sim test.v, потом vvp sim), открой получившийся VCD:

gtkwave dump.vcd

GTKWave загружает файл, показывает scope-дерево слева и ждёт, пока ты перетянешь сигналы в область waveform справа. Правый клик на многобитном сигнале меняет формат отображения (binary, hex, decimal, analog). Используй поле поиска внизу, чтобы прыгать на конкретные моменты или переходы.

Частые паттерны

Маленький helper testbench

Большинство файлов testbench начинаются с этого блока. Можно держать коротко, объединив всё в одном initial:

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

    // ... стимулы ...

    $finish;
end

Условный дамп

В test-окружении, где VCD-вывод нужен только для падающих тестов:

initial begin
    if (DUMP_VCD) begin
        $dumpfile("dump.vcd");
        $dumpvars(0, test);
    end
    // ... стимулы ...
end

DUMP_VCD был бы parameter, который ты задаёшь из командной строки или дефайнишь в зависимости от режима теста. Экономит дисковое пространство в regression-сьютах.

Дамп memory

Memories (unpacked arrays) по умолчанию не дампятся $dumpvars - они могут быть огромными. Используй $dumpvars(0, dut.memory) явно, если они нужны, или $dumpmem в некоторых симуляторах.

Частые ошибки

Пустой VCD-файл. Забыл $dumpfile или $dumpvars, или симуляция вызвала $finish до того, как сигналы поменялись. Прогоняй хотя бы несколько единиц времени после setup.

Сигналы отсутствуют на waveform. Scope, который ты передал, их не включал. $dumpvars(0, dut) записывает только то, что внутри dut; если testbench приводит сигналы на уровне test, они не появятся. Всегда дампи от scope testbench: $dumpvars(0, test).

VCD-файл огромный. Длинная симуляция с быстро меняющимися широкими сигналами производит много VCD-строк. Три фикса: дампить более узкий scope, использовать $dumpoff/$dumpon вокруг скучных частей или переключиться на более компактный формат вроде FST (iverilog и GTKWave оба поддерживают через флаги -fst).

Что дальше

Последний документ в этой главе - Timescale and Delays - разбирает директиву \timescaleи как#delay` реально отображается в wall-clock-время. После этого ты прошёл документы из конца в конец.

Часто задаваемые вопросы

Что такое VCD-файл в Verilog?

VCD - это Value Change Dump, текстовый формат для записи каждого перехода сигнала во время симуляции. Симулятор пишет начальное значение каждого сигнала в момент 0, затем каждое изменение с timestamp. Просмотрщики waveform вроде GTKWave читают файл и рендерят его как графическую timing-диаграмму, которую можно скроллить и зумировать.

Как сгенерировать VCD-файл в Verilog?

Добавь две системные задачи внутри блока initial в testbench: $dumpfile("dump.vcd"); именует выходной файл, и $dumpvars(0, top_module); записывает каждый сигнал в top_module и ниже. После завершения симуляции у тебя будет файл dump.vcd, который можно открыть в любом просмотрщике waveform.

Что значит $dumpvars(0, ...) в Verilog?

$dumpvars(depth, instance) записывает сигналы, начиная с instance и рекурсивно depth уровней вглубь. $dumpvars(0, test) значит 'все сигналы в scope test и каждом sub-scope, рекурсивно' - глубина 0 специальная, означает unlimited. $dumpvars(1, test) записал бы только сигналы прямо в test, не в инстанцированных подмодулях.

Почему мой VCD-файл пустой в Verilog?

Три вероятные причины: не вызвал $dumpfile/$dumpvars вообще; симуляция дошла до $finish до того, как сигналы поменялись (прогоняй хотя бы несколько единиц времени после dump-вызова); или scope, переданный в $dumpvars, не соответствует реальной иерархии. Минимально рабочая последовательность - $dumpfile("dump.vcd"); $dumpvars(0, test); #10; $finish;.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ