Commit d0c32452 authored by Martin Jeřábek's avatar Martin Jeřábek

testfw: add generating gtkw from tcl files

* requires patched VUnit
* bug: only 0th bit of std_logic_vectors is displayed now
parent 515e6d64
from vcd.gtkw import GTKWSave
import tkinter
from typing import List
import logging
import traceback
import functools
log = logging.getLogger('gtkwave')
def logexc(f):
@functools.wraps(f)
def wrapper(*args, **kwds):
try:
return f(*args, **kwds)
except:
traceback.print_exc()
raise
return wrapper
class TclFuncs:
def __init__(self, gtkw: str):
self.gtkw = gtkw
# set up TCL
tcl = tkinter.Tcl()
self.tcl = tcl
tcl.createcommand("add", self.tcl_add)
tcl.createcommand('quietly', self.tcl_quietly)
def source(self, file: str):
log.debug('Sourcing '+file)
self.tcl.eval('source "{}"'.format(file))
def finalize(self):
pass
def tcl_quietly(self, *args):
return self.tcl.call(*args)
@staticmethod
def convsig(sig: str) -> str:
return 'top.' + sig.replace('/', '.').replace('(', '[').replace(')', ']')
@logexc
def tcl_add(self, *args):
i = 0
if args[i] != 'wave':
raise ValueError("Unsupported add TCL command")
i += 1
label = None
format = 'hex'
signal = None
isdivider = False
group = None
while i < len(args):
a0 = args[i]
i += 1
if a0 == '-label':
label = args[i]
i += 1
elif a0 == '-hexadecimal':
format = 'hex'
elif a0 == '-unsigned':
format = 'dec'
elif a0 == '-signed': # ????
format = 'signed'
elif a0 == '-noupdate':
pass
elif a0 == '-divider':
isdivider = True
elif a0 == '-height':
i += 1
elif a0 == '-group':
if group:
self.gtkw.end_group(group, closed=False)
group = args[i]
self.gtkw.begin_group(group, closed=False)
i += 1
elif a0[0] == '-':
raise ValueError("Unknown TCL add wave arg " + a0)
else:
signal = a0
if isdivider:
self.gtkw.blank(label=signal)
else:
self.gtkw.trace(self.convsig(signal), alias=label, datafmt=format)
label = None
format = 'hex'
signal = None
isdivider = False
if group:
self.gtkw.end_group(group)
def tcl2gtkw(tcl_wave, tcl_init_files: List[str], gtkw):
with open(gtkw, 'wt') as f:
gtkw = GTKWSave(f)
gtkw.zoom_markers(-27.0)
c = TclFuncs(gtkw)
c.tcl.createcommand('vunit_help', lambda: None)
for tcl in tcl_init_files:
c.source(tcl)
c.tcl.createcommand('run_simulation', lambda: None)
c.source(tcl_wave)
c.finalize()
......@@ -7,6 +7,7 @@ from pathlib import Path
from jinja2 import Environment, PackageLoader
from pprint import pprint
import random
from .gtkwave import tcl2gtkw
from typing import List
__all__ = ['add_sources', 'add_common_sources', 'get_common_modelsim_init_files',
......@@ -41,7 +42,9 @@ class TestsBase:
raise NotImplementedError()
def add_modelsim_gui_file(self, tb, cfg, name) -> None:
def add_modelsim_gui_file(self, tb, cfg, name, tcl_init_files: List[str] = None) -> None:
if tcl_init_files is None:
tcl_init_files = tb.get_sim_option("modelsim.init_files.after_load")
if 'wave' in cfg:
tcl = self.base / cfg['wave']
if not tcl.exists():
......@@ -60,7 +63,20 @@ class TestsBase:
run_simulation
get_test_results
'''.format(name)), file=f)
tb.set_sim_option("modelsim.init_file.gui", str(tcl))
if 'gtkw' in cfg:
gtkw = self.base / cfg['gtkw']
if not gtkw.exists():
log.warn('GTKW wave file {} not found'.format(cfg['gtkw']))
else:
gtkw = tcl.with_suffix('.gtkw')
tclfname = tcl.relative_to(self.base)
log.info('Converting wave file {} to gtkw ...'.format(tclfname))
tcl2gtkw(str(tcl), tcl_init_files, str(gtkw))
if gtkw:
tb.set_sim_option("ghdl.gtkw_file", str(gtkw))
def add_sources(lib, patterns) -> None:
for pattern in patterns:
......
......@@ -34,7 +34,6 @@ class FeatureTests(TestsBase):
def configure(self) -> bool:
tb = self.lib.get_test_benches('*tb_feature')[0]
default = self.config['default']
self.add_modelsim_gui_file(tb, default, 'feature')
# generate & set per-test modelsim tcl file
tcl = self.build / 'modelsim_init_feature.tcl'
......@@ -70,7 +69,7 @@ class FeatureTests(TestsBase):
tb.add_config(name, generics=generics, sim_options=psl_opts)
else:
tb.add_config(name, generics=generics)
self.add_modelsim_gui_file(tb, default, 'feature', init_files)
return self._check_for_unconfigured()
def _check_for_unconfigured(self) -> bool:
......
......@@ -50,7 +50,7 @@ class UnitTests(TestsBase):
tb.set_sim_option("modelsim.init_files.after_load", init_files)
if (cfg['psl_coverage']):
self.add_psl_cov_file(tb, name)
self.add_modelsim_gui_file(tb, cfg, name)
self.add_modelsim_gui_file(tb, cfg, name, tcl_init_files=init_files)
return self._check_for_unconfigured()
def _check_for_unconfigured(self) -> bool:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment