mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Add support of Events for VCD/FST traces (#3759)
This commit is contained in:
parent
e97e6c2213
commit
06fdf7be58
@ -221,6 +221,10 @@ void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum, fstVar
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedFst::declEvent(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0);
|
||||
}
|
||||
void VerilatedFst::declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0);
|
||||
@ -279,6 +283,12 @@ void VerilatedFst::configure(const VerilatedTraceConfig& config) {
|
||||
// verilated_trace_imp.h, which is included in this file at the top),
|
||||
// so always inline them.
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFstBuffer::emitEvent(uint32_t code, VlEvent newval) {
|
||||
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], "1");
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFstBuffer::emitBit(uint32_t code, CData newval) {
|
||||
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
|
||||
|
@ -101,6 +101,8 @@ public:
|
||||
//=========================================================================
|
||||
// Internal interface to Verilator generated code
|
||||
|
||||
void declEvent(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum);
|
||||
void declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum);
|
||||
void declBus(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
@ -161,6 +163,7 @@ class VerilatedFstBuffer VL_NOT_FINAL {
|
||||
|
||||
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
|
||||
// called from only one place (the full* methods), so always inline them.
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, VlEvent newval);
|
||||
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
|
||||
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
|
||||
|
@ -107,6 +107,7 @@ public:
|
||||
CHG_QDATA = 0x5,
|
||||
CHG_WDATA = 0x6,
|
||||
CHG_DOUBLE = 0x8,
|
||||
CHG_EVENT = 0x9,
|
||||
// TODO: full..
|
||||
TIME_CHANGE = 0xc,
|
||||
TRACE_BUFFER = 0xd,
|
||||
@ -422,6 +423,7 @@ public:
|
||||
void fullQData(uint32_t* oldp, QData newval, int bits);
|
||||
void fullWData(uint32_t* oldp, const WData* newvalp, int bits);
|
||||
void fullDouble(uint32_t* oldp, double newval);
|
||||
void fullEvent(uint32_t* oldp, VlEvent newval);
|
||||
|
||||
// In non-offload mode, these are called directly by the trace callbacks,
|
||||
// and are called chg*. In offload mode, they are called by the worker
|
||||
@ -456,6 +458,9 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, VlEvent newval) {
|
||||
fullEvent(oldp, newval);
|
||||
}
|
||||
VL_ATTR_ALWINLINE void chgDouble(uint32_t* oldp, double newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
|
||||
@ -533,6 +538,12 @@ public:
|
||||
m_offloadBufferWritep += 4;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
void chgEvent(uint32_t code, VlEvent newval) {
|
||||
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_EVENT ;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep += 2;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
|
@ -183,6 +183,10 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
|
||||
traceBufp->chgDouble(oldp, *reinterpret_cast<const double*>(readp));
|
||||
readp += 2;
|
||||
continue;
|
||||
case VerilatedTraceOffloadCommand::CHG_EVENT:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_EVENT " << top);
|
||||
traceBufp->chgEvent(oldp, *reinterpret_cast<const VlEvent*>(readp));
|
||||
continue;
|
||||
|
||||
//===
|
||||
// Rare commands
|
||||
@ -834,6 +838,13 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullBit(uint32_t* oldp, CData newval) {
|
||||
emitBit(code, newval);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, VlEvent newval) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
*oldp = 1; // Do we really store an "event" ?
|
||||
emitEvent(code, newval);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullCData(uint32_t* oldp, CData newval, int bits) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
|
@ -548,6 +548,9 @@ void VerilatedVcd::declare(uint32_t code, const char* name, const char* wirep, b
|
||||
m_namemapp->emplace(hiername, decl);
|
||||
}
|
||||
|
||||
void VerilatedVcd::declEvent(uint32_t code, const char* name, bool array, int arraynum) {
|
||||
declare(code, name, "event", array, arraynum, false, false, 0, 0);
|
||||
}
|
||||
void VerilatedVcd::declBit(uint32_t code, const char* name, bool array, int arraynum) {
|
||||
declare(code, name, "wire", array, arraynum, false, false, 0, 0);
|
||||
}
|
||||
@ -694,6 +697,19 @@ void VerilatedVcdBuffer::finishLine(uint32_t code, char* writep) {
|
||||
// verilated_trace_imp.h, which is included in this file at the top),
|
||||
// so always inline them.
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedVcdBuffer::emitEvent(uint32_t code, VlEvent newval) {
|
||||
const bool triggered = newval.isTriggered();
|
||||
// TODO : It seems that untriggerd events are not filtered
|
||||
// should be tested before this last step
|
||||
if(triggered) {
|
||||
// Don't prefetch suffix as it's a bit too late;
|
||||
char* wp = m_writep;
|
||||
*wp++ = '1' ;
|
||||
finishLine(code, wp);
|
||||
}
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedVcdBuffer::emitBit(uint32_t code, CData newval) {
|
||||
// Don't prefetch suffix as it's a bit too late;
|
||||
|
@ -140,6 +140,7 @@ public:
|
||||
//=========================================================================
|
||||
// Internal interface to Verilator generated code
|
||||
|
||||
void declEvent(uint32_t code, const char* name, bool array, int arraynum);
|
||||
void declBit(uint32_t code, const char* name, bool array, int arraynum);
|
||||
void declBus(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declQuad(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
@ -206,6 +207,7 @@ class VerilatedVcdBuffer VL_NOT_FINAL {
|
||||
// Implementation of VerilatedTraceBuffer interface
|
||||
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
|
||||
// called from only one place (the full* methods), so always inline them.
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, VlEvent newval);
|
||||
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
|
||||
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
|
||||
|
@ -637,6 +637,8 @@ class EmitCTrace final : EmitCFunc {
|
||||
puts("tracep->declQuad");
|
||||
} else if (nodep->bitRange().ranged()) {
|
||||
puts("tracep->declBus");
|
||||
} else if (nodep->dtypep()->basicp()->isEvent()) {
|
||||
puts("tracep->declEvent");
|
||||
} else {
|
||||
puts("tracep->declBit");
|
||||
}
|
||||
@ -689,11 +691,11 @@ class EmitCTrace final : EmitCFunc {
|
||||
else if (kwd == VBasicDTypeKwd::SHORTINT) { fstvt = "FST_VT_SV_SHORTINT"; }
|
||||
else if (kwd == VBasicDTypeKwd::LONGINT) { fstvt = "FST_VT_SV_LONGINT"; }
|
||||
else if (kwd == VBasicDTypeKwd::BYTE) { fstvt = "FST_VT_SV_BYTE"; }
|
||||
else if (kwd == VBasicDTypeKwd::EVENT) { fstvt = "FST_VT_VCD_EVENT"; }
|
||||
else { fstvt = "FST_VT_SV_BIT"; }
|
||||
// clang-format on
|
||||
//
|
||||
// Not currently supported
|
||||
// FST_VT_VCD_EVENT
|
||||
// FST_VT_VCD_PORT
|
||||
// FST_VT_VCD_SHORTREAL
|
||||
// FST_VT_VCD_REALTIME
|
||||
@ -779,6 +781,9 @@ class EmitCTrace final : EmitCFunc {
|
||||
puts("bufp->" + func + "SData");
|
||||
} else if (nodep->declp()->widthMin() > 1) {
|
||||
puts("bufp->" + func + "CData");
|
||||
} else if (nodep->dtypep()->basicp()->isEvent()) {
|
||||
puts("bufp->" + func + "Event");
|
||||
emitWidth = false;
|
||||
} else {
|
||||
puts("bufp->" + func + "Bit");
|
||||
emitWidth = false;
|
||||
|
@ -1,16 +1,17 @@
|
||||
$version Generated by VerilatedVcd $end
|
||||
$date Thu Oct 20 09:56:59 2022 $end
|
||||
$date Tue Nov 22 16:48:14 2022 $end
|
||||
$timescale 1ps $end
|
||||
|
||||
$scope module TOP $end
|
||||
$scope module t $end
|
||||
$var wire 32 * CLK_HALF_PERIOD [31:0] $end
|
||||
$var wire 32 ) CLK_PERIOD [31:0] $end
|
||||
$var wire 32 + CLK_HALF_PERIOD [31:0] $end
|
||||
$var wire 32 * CLK_PERIOD [31:0] $end
|
||||
$var wire 1 $ a $end
|
||||
$var wire 1 % b $end
|
||||
$var wire 1 & c $end
|
||||
$var wire 1 ( clk $end
|
||||
$var wire 1 ) clk $end
|
||||
$var wire 1 ' d $end
|
||||
$var event 1 ( ev $end
|
||||
$var wire 1 # rst $end
|
||||
$upscope $end
|
||||
$upscope $end
|
||||
@ -23,54 +24,57 @@ $enddefinitions $end
|
||||
0%
|
||||
0&
|
||||
0'
|
||||
0(
|
||||
b00000000000000000000000000001010 )
|
||||
b00000000000000000000000000000101 *
|
||||
0)
|
||||
b00000000000000000000000000001010 *
|
||||
b00000000000000000000000000000101 +
|
||||
#5
|
||||
1(
|
||||
1)
|
||||
#10
|
||||
0#
|
||||
1%
|
||||
0(
|
||||
1(
|
||||
0)
|
||||
#15
|
||||
1(
|
||||
1)
|
||||
#20
|
||||
0(
|
||||
1(
|
||||
0)
|
||||
#25
|
||||
1(
|
||||
1)
|
||||
#30
|
||||
0(
|
||||
0)
|
||||
#35
|
||||
1(
|
||||
1)
|
||||
#40
|
||||
0(
|
||||
0)
|
||||
#45
|
||||
1(
|
||||
1)
|
||||
#50
|
||||
0(
|
||||
0)
|
||||
#55
|
||||
1(
|
||||
1)
|
||||
#60
|
||||
0(
|
||||
0)
|
||||
#65
|
||||
1(
|
||||
1)
|
||||
#70
|
||||
0(
|
||||
0)
|
||||
#75
|
||||
1(
|
||||
1)
|
||||
#80
|
||||
0(
|
||||
0)
|
||||
#85
|
||||
1(
|
||||
1)
|
||||
#90
|
||||
0(
|
||||
0)
|
||||
#95
|
||||
1(
|
||||
1)
|
||||
#100
|
||||
0(
|
||||
0)
|
||||
#105
|
||||
1(
|
||||
1)
|
||||
#110
|
||||
1#
|
||||
0%
|
||||
0(
|
||||
1(
|
||||
0)
|
||||
|
@ -16,6 +16,7 @@ module t;
|
||||
logic b;
|
||||
logic c;
|
||||
logic d;
|
||||
event ev;
|
||||
|
||||
initial begin
|
||||
$dumpfile(`STRINGIFY(`TEST_DUMPFILE));
|
||||
@ -34,10 +35,15 @@ module t;
|
||||
#CLK_PERIOD;
|
||||
rst = 0;
|
||||
b = 1;
|
||||
-> ev ;
|
||||
#CLK_PERIOD;
|
||||
-> ev ;
|
||||
|
||||
#(10 * CLK_PERIOD);
|
||||
#(9 * CLK_PERIOD);
|
||||
-> ev ;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
87
test_regress/t/t_timing_trace_fst.out
Normal file
87
test_regress/t/t_timing_trace_fst.out
Normal file
@ -0,0 +1,87 @@
|
||||
$date
|
||||
Tue Nov 22 18:14:18 2022
|
||||
|
||||
$end
|
||||
$version
|
||||
fstWriter
|
||||
$end
|
||||
$timescale
|
||||
1ps
|
||||
$end
|
||||
$scope module TOP $end
|
||||
$scope module t $end
|
||||
$var parameter 32 ! CLK_PERIOD [31:0] $end
|
||||
$var parameter 32 " CLK_HALF_PERIOD [31:0] $end
|
||||
$var logic 1 # rst $end
|
||||
$var logic 1 $ clk $end
|
||||
$var logic 1 % a $end
|
||||
$var logic 1 & b $end
|
||||
$var logic 1 ' c $end
|
||||
$var logic 1 ( d $end
|
||||
$var event 1 ) ev $end
|
||||
$upscope $end
|
||||
$upscope $end
|
||||
$enddefinitions $end
|
||||
#0
|
||||
$dumpvars
|
||||
1)
|
||||
0(
|
||||
0'
|
||||
0&
|
||||
0%
|
||||
0$
|
||||
1#
|
||||
b00000000000000000000000000000101 "
|
||||
b00000000000000000000000000001010 !
|
||||
$end
|
||||
#5
|
||||
1$
|
||||
#10
|
||||
0$
|
||||
0#
|
||||
1&
|
||||
1)
|
||||
#15
|
||||
1$
|
||||
#20
|
||||
0$
|
||||
1)
|
||||
#25
|
||||
1$
|
||||
#30
|
||||
0$
|
||||
#35
|
||||
1$
|
||||
#40
|
||||
0$
|
||||
#45
|
||||
1$
|
||||
#50
|
||||
0$
|
||||
#55
|
||||
1$
|
||||
#60
|
||||
0$
|
||||
#65
|
||||
1$
|
||||
#70
|
||||
0$
|
||||
#75
|
||||
1$
|
||||
#80
|
||||
0$
|
||||
#85
|
||||
1$
|
||||
#90
|
||||
0$
|
||||
#95
|
||||
1$
|
||||
#100
|
||||
0$
|
||||
#105
|
||||
1$
|
||||
#110
|
||||
0$
|
||||
1)
|
||||
0&
|
||||
1#
|
32
test_regress/t/t_timing_trace_fst.pl
Executable file
32
test_regress/t/t_timing_trace_fst.pl
Executable file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2022 Yves Mathieu. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
top_filename("t/t_timing_trace.v");
|
||||
|
||||
if (!$Self->have_coroutines) {
|
||||
skip("No coroutine support");
|
||||
}
|
||||
else {
|
||||
compile(
|
||||
verilator_flags2 => ["--exe --main --timing --trace-fst -Wno-MINTYPMAXDLY"],
|
||||
make_main => 0,
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
fst_identical($Self->trace_filename, $Self->{golden_filename});
|
||||
}
|
||||
|
||||
ok(1);
|
||||
1;
|
Loading…
Reference in New Issue
Block a user