Skip to content

Instantly share code, notes, and snippets.

@racerxdl
Last active March 4, 2024 20:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save racerxdl/0aeeb5430f999abace58a135a5039827 to your computer and use it in GitHub Desktop.
Save racerxdl/0aeeb5430f999abace58a135a5039827 to your computer and use it in GitHub Desktop.
Very bad converter from ValueChangeDump (VCD) to Tikz Timing on Latex.
#!/usr/bin/env python3
import vcdvcd, math
from vcdvcd import VCDVCD
vcdfile = "digital_port_tb.vcd"
vcd = VCDVCD(vcdfile, only_sigs=True)
all_signals = vcd.signals
# print(all_signals)
dataW = [0 for i in range(len(all_signals))]
data = [[] for i in range(len(all_signals))]
###########
def nibble_to_hex(s):
for c in s:
if not c in '01':
return c
return hex(int(s, 2))[2:].upper()
def binary_string_to_hex(s, w):
if len(s) == 1:
if s != '0' and s != '1':
return s
s = s.zfill(w)
n = 4
groups = [s[i:i+n] for i in range(0, len(s), n)]
hexgroups = [nibble_to_hex(x) for x in groups]
return "".join(hexgroups)
class ParserCallbacks(vcdvcd.StreamParserCallbacks):
def __init__(self, deltas=True):
self._deltas = deltas
self._references_to_widths = {}
def enddefinitions(
self,
vcd,
signals,
cur_sig_vals
):
if signals:
self._print_dumps_refs = signals
else:
self._print_dumps_refs = sorted(vcd.data[i].references[0] for i in cur_sig_vals.keys())
for i, ref in enumerate(self._print_dumps_refs, 1):
if i == 0:
i = 1
identifier_code = vcd.references_to_ids[ref]
size = int(vcd.data[identifier_code].size)
width = max(((size // 4)), int(math.floor(math.log10(i))) + 1)
self._references_to_widths[ref] = width
dataW[i-1] = size
def time(
self,
vcd,
time,
cur_sig_vals
):
if (not self._deltas or vcd.signal_changed):
ss = []
ss.append('{}'.format(time))
for i, ref in enumerate(self._print_dumps_refs):
identifier_code = vcd.references_to_ids[ref]
value = cur_sig_vals[identifier_code]
data[i].append(binary_string_to_hex(value, dataW[i]))
###########
callbacks = ParserCallbacks()
VCDVCD(
vcdfile,
signals=all_signals,
store_tvs=False,
callbacks=callbacks,
)
ltx = '''
\\documentclass{standalone}
\\usepackage{tikz-timing}
\\begin{document}
\\begin{tikztimingtable}[timing/xunit=35,timing/yunit=10]
'''
def latexEscape(val):
return val.\
replace("_", "\\_").\
replace("{", "\\{").\
replace("}", "\\}").\
replace("&", "\\&").\
replace("%", "\\%").\
replace("$", "\\$").\
replace("#", "\\#").\
replace("$", "\\$")
for sig in range(len(data)):
sigName = latexEscape(all_signals[sig])
sigSeries = data[sig]
sigWidth = dataW[sig]
# print(f"SigName: {sigName} - SigWidth: {sigWidth}")
ltx += format(f" {sigName} &")
for value in sigSeries:
prefix = ""
token = format(f" D{{{value}}} ")
if value == "x":
token = "X"
elif value == "z":
token = "Z"
elif sigWidth == 1:
token = "H" if value == "1" else "L"
if "x" in token:
prefix = " [red] "
elif "z" in token:
prefix = " [blue] "
ltx += format(f" {prefix}{token} ;")
ltx += " \\\\\n"
# ltx += "\\vertlines[help lines,opacity=0.3]{}\n"
ltx += '''\\extracode
\\vertlines[help lines,opacity=0.3]{}
\\end{tikztimingtable}
\\end{document}
'''
# print(ltx)
with open("tmp.tex", "w") as f:
f.write(ltx)
'''
\\begin{tikztimingtable}[timing/wscale=0.8]
M-cycle & X 8D{M1} 8D{M2/M1} X \\\\
Instruction & ; [opacity=0.4] 9D{Previous} ; [opacity=1.0] 8D{LD r, r'} ; [opacity=0.4] X \\\\
Mem R/W & X 8D{R: opcode}; [opacity=0.4] 8D{R: next op} X \\\\
Mem addr & X 8D{PC} ; [opacity=0.4] 8D{PC+1} X \\\\
\\end{tikztimingtable}
'''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment