Closed amb5l closed 2 years ago
Regarding waveform colour, the syntax is simply [color] n
where 0 <= n <= 7. For example:
[color] 1
tbr6522.regclk
tbr6522.regclken
tbr6522.regrst
tbr6522.regcs
tbr6522.regrs[3:0]
tbr6522.regdw[7:0]
tbr6522.regdr[7:0]
tbr6522.regirq
[color] 2
tbr6522.uut_1.ddra[7:0]
You can dump VCD at the moment with --format=vcd
. It's perhaps not as convenient as gktw but it is textual.
OK that was a good suggestion. I've written a short Python script - below - which pulls the relevant data from the vcd file and writes a gtkw file. Because NVC preserves the source declared order of ports and signals when it writes the VCD (thankyou!) the result is really useful. I find the alphabetic listing of signals in the gtkwave UI really unhelpful. I can live with my script but the logic is simple, maybe it might make its way into NVC one day?!
# vhdl2gtkw.py
import sys
if len(sys.argv) < 2 or len(sys.argv) > 3:
print('usage: vcd2gtkw.py filename [level]')
print(' filename = VCD file to process')
print(' level = hierarchy levels to descend (0 = all, default)')
sys.exit(1)
file_name = sys.argv[1]
level = 0
if len(sys.argv) == 3:
level = int(sys.argv[2])
print("processing: "+file_name)
hier = []
scope = ""
scope_waves = []
color = 1
![vcd2gtkw](https://user-images.githubusercontent.com/33783239/186771871-7e4c0cd9-05f4-43e4-8b50-55a321ba718c.png)
with open(file_name, 'r') as f:
while True:
l = f.readline()
if "$" in l:
ll = l.split()
cmd = ll[0][1:]
if cmd == "enddefinitions":
break
elif cmd == "scope":
if scope_waves:
print("-"+"/".join(hier))
color = (color%7)+1
for w in scope_waves:
print("[color] "+str(color))
print(w)
scope_waves = []
scope = ll[2]
hier.append(scope)
elif cmd == "upscope":
if scope_waves:
print("-"+"/".join(hier))
color = (color%7)+1
for w in scope_waves:
print("[color] "+str(color))
print(w)
scope_waves = []
hier.pop()
scope = hier[-1] if hier else ""
elif cmd == "var":
if level == 0 or len(hier) <= level:
scope_waves.append(".".join(hier)+"."+ll[4] if hier else ll[4])
I've put the script in its own repo after a bit of tidying.
Here's the same functionality in a bash script. It might fit - perhaps if the infrastructure you have for "nvc install" to run scripts was extended to support other (contributed) scripts? e.g. with "script" as an alias for "install".
#!/bin/bash
#
# vcd2gtkw.sh
#
# This script creates a .gtkw (waveform save file) from a .vcd (value change
# dump). Waves are added in the order they are found in the VCD, which normally
# matches the order of port, signal declarations etc in the design source. Wave
# colours are cycled as the hierarchy levels are traversed.
#
# Arguments:
# $1 : vcd filename
# $2 : gtkw filename
# $3 : (optional) hierarchy levels to descend, 0 = all (default if omitted)
vcd_filename=$1
gtkw_filename=$2
if [ -z "$3" ]; then
levels=0;
else
levels=$3
fi
echo "vcd2gtkw.sh: $1 -> $2 (levels = $3)"
echo "[\*] vcd2gtkw.sh: $1 -> $2 (levels = $3)" > $gtkw_filename
declare -a hlevel=() # current hierarchy level
scope="" # current scope name
declare -a waves=() # waves gathered for current scope
color=7
wave_name=""
function join_with { local IFS="$1"; shift; echo "$*"; }
while read -r line; do # read file line by line
if [[ ${line:0:1} == "\$" ]]; then
IFS=' ' read -ra line_tokens <<< "$line" # split line into tokens
cmd=${line_tokens[0]} # cmd = 1st token
cmd="${cmd:1}" # strip $ from cmd
if [ "$cmd" = "enddefinitions" ]; then # marks end of defs section of VCD
break
fi
if [[ "$cmd" == *"scope"* ]]; then # change of scope
if [ ${#waves[@]} -ne 0 ]; then # there are some waves to dump
echo "-$(join_with // ${hlevel[*]})" >> $gtkw_filename # comment: current hierarchy level
color=$(( (color%7)+1 )) # cycle colour
# dump waves
dn="" # deferred wave name } for building vectors
di="" # wave index } from bits
df="" # wave 1st index }
declare -a dw=() # wave list }
for w in ${waves[*]}; do # dump waves
if [ ${w:0-1} = "]" ]; then # wave is vector (whole or bit)
IFS='[' read -ra w_parts <<< "${w::-1}"
n=${w_parts[0]} # name
i=${w_parts[1]} # index
if [[ "$i" == *":"* ]]; then # whole vector
n=$w
i=""
fi
else # scalar
n=$w
i=""
fi
if [ "$di" != "" ]; then # previous wave was vector bit
if [ "$dn" != "$n" ]; then # this wave is not part of that vector
# dump previous wave vector
echo "#{$dn[$df:$di]} ${dw[*]}" >> $gtkw_filename
dw=()
else # this wave is part of that vector
dw+=("$w")
fi
else # no previous wave to consider
df=$i
dw=()
fi
if [ "$i" = "" ]; then # this wave is not vector bit
echo "[color] $color" >> $gtkw_filename
echo "$w" >> $gtkw_filename
fi
dn=$n
di=$i
done
if [ "$di" != "" ]; then # deal with final deferred wave
echo "#{$dn[$df:$di]} ${dw[*]}" >> $gtkw_filename
dw=()
fi
waves=() # reset wave list
fi
fi
if [ "$cmd" = "scope" ]; then
scope=${line_tokens[2]} # new scope name (descend hierarchy)
hlevel+=("$scope")
elif [ "$cmd" = "upscope" ]; then # ascend hierarchy
unset 'hlevel[$(( ${#hlevel[@]}-1 ))]' # pop last element
if [ ${#hlevel[@]} -ne 0 ]; then
scope=${hlevel[-1]}
else
scope=""
fi
elif [ "$cmd" = "var" ]; then
wave_name=${line_tokens[4]}
if [[ "${line_tokens[5]}" == "["*"]" ]]; then # bus wire - concatenate index
wave_name="$wave_name${line_tokens[5]}"
fi
# add signal if not too far down in hierarchy
if [ $levels -eq 0 ] || [ ${#hlevel[@]} le $levels]; then
waves+=("$(join_with . ${hlevel[*]}).$wave_name")
fi
fi
fi
done <"$vcd_filename"
Thanks for the script. There's a contrib/
directory in the source which is meant for this kind of user-contributed script, but actually having tried it, I think this is useful enough to be implemented in the main program. I've added a --gtkw
(alias -g
) run option that does basically the same as the above. Could you try it?
I tried the latest commit against UVVM's bitvis_uart example. Analysis and elaboration OK, but the run ended with this error:
nvc --std=08 --work=bitvis_uart -r uart_vvc_demo_tb --format=vcd --wave=wave.vcd
...
=======================================================
UVVM: >> Simulation SUCCESS: No mismatch between counted and expected serious alerts
UVVM: ====================================================================================================================================================================
UVVM:
UVVM:
UVVM:
UVVM:
UVVM: ID_LOG_HDR 371672.5 ns TB seq. SIMULATION COMPLETED
UVVM: -------------------------------------------------------------------------------------------------------------------------------------------------------------------------
** Note: STOP called
** Fatal: wave_dumper_free called before end of simulation
[00007ff7dab76440]
[00007ff7dac001f0]
[00007ff7dab72a12]
[00007ff7dac53832] vhpi_put_data+0x23942
[00007ff7dab713ae]
[00007ff7dab714e6]
[00007ffc210854e0] BaseThreadInitThunk+0x10
[00007ffc229e485b] RtlUserThreadStart+0x2b
@amb5l could you test again with the latest master? That should be fixed in d6170a2f.
I checked out a slightly more recent master commit (a4a61c) and reran this test successfully - thankyou for incorporating this useful feature.
A command line option e.g. --gtkw [filename] to output a gtkw file as a very useful starting point for viewing waveforms with ports/signals grouped by design unit, and listed in the order that they are declared in the source.
A barebones gtkw file can simply comprise a list of signals with dots separating hierarchy levels:
Everything is lower case.
A useful upgrade would be to change the waveform colour for each design unit.