test_common.py 4.31 KB
Newer Older
1
from textwrap import dedent
2 3
from collections.abc import Iterable
from glob import glob
Martin Jeřábek's avatar
Martin Jeřábek committed
4
from os.path import join, abspath
5 6
import logging
from pathlib import Path
7
from jinja2 import Environment, PackageLoader
Martin Jeřábek's avatar
Martin Jeřábek committed
8
from pprint import pprint
9
import random
10 11

__all__ = ['add_sources', 'add_common_sources', 'get_common_modelsim_init_files',
12 13
           'add_flags', 'dict_merge', 'vhdl_serialize', 'dump_sim_options',
           'TestsBase', 'get_seed']
14 15 16 17

d = Path(abspath(__file__)).parent
log = logging.getLogger(__name__)

18 19
jinja_env = Environment(loader=PackageLoader(__package__, 'data'), autoescape=False)

Martin Jeřábek's avatar
Martin Jeřábek committed
20

21 22 23 24 25 26 27 28
class TestsBase:
    def __init__(self, ui, lib, config, build, base):
        self.ui = ui
        self.lib = lib
        self.config = config
        self.build = build
        self.base = base

29 30 31 32
    @property
    def jinja_env(self):
        return jinja_env

Martin Jeřábek's avatar
Martin Jeřábek committed
33 34 35 36 37
    def add_sources(self):
        raise NotImplementedError()

    def configure(self):
        raise NotImplementedError()
38

39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
    def add_modelsim_gui_file(self, tb, cfg, name):
        if 'wave' in cfg:
            tcl = self.base / cfg['wave']
            if not tcl.exists():
                log.warn('Wave file {} not found'.format(cfg['wave']))
        else:
            tcl = self.build / 'modelsim_gui_{}.tcl'.format(name)
            with tcl.open('wt', encoding='utf-8') as f:
                print(dedent('''\
                    start_CAN_simulation "dummy"
                    global IgnoreAddWaveErrors
                    puts "Automatically adding common waves. Failures are handled gracefully."
                    set IgnoreAddWaveErrors 1
                    add_test_status_waves
                    add_system_waves
                    set IgnoreAddWaveErrors 0
                    run_simulation
                    get_test_results
                    '''.format(name)), file=f)
        tb.set_sim_option("modelsim.init_file.gui", str(tcl))

Martin Jeřábek's avatar
Martin Jeřábek committed
60

61 62 63 64 65 66 67 68
def add_sources(lib, patterns):
    for pattern in patterns:
        p = join(str(d.parent), pattern)
        log.debug('Adding sources matching {}'.format(p))
        for f in glob(p, recursive=True):
            if f != "tb_wrappers.vhd":
                lib.add_source_file(str(f))

Martin Jeřábek's avatar
Martin Jeřábek committed
69

70 71 72
def add_common_sources(lib):
    return add_sources(lib, ['../src/**/*.vhd', '*.vhd', 'lib/*.vhd'])

Martin Jeřábek's avatar
Martin Jeřábek committed
73

74 75 76 77 78 79 80 81 82 83
def get_common_modelsim_init_files():
    modelsim_init_files = '../lib/test_lib.tcl,modelsim_init.tcl'
    modelsim_init_files = [str(d/x) for x in modelsim_init_files.split(',')]
    return modelsim_init_files

def add_flags(ui, lib, build):
    unit_tests = lib.get_test_benches('*_unit_test', allow_empty=True)
    for ut in unit_tests:
        ut.scan_tests_from_file(str(build / "../unit/vunittb_wrapper.vhd"))

Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
84
    reference_tests = lib.get_test_benches('*reference*', allow_empty=True)
Ille, Ondrej, Ing.'s avatar
Bug-fix  
Ille, Ondrej, Ing. committed
85
    for rt in reference_tests:
Ille, Ondrej, Ing.'s avatar
Ille, Ondrej, Ing. committed
86
        rt.scan_tests_from_file(str(build / "../reference/vunit_reference_wrapper.vhd"))
87

88
    #lib.add_compile_option("ghdl.flags", ["-Wc,-g"])
89 90
    lib.add_compile_option("ghdl.flags", ["-fprofile-arcs", "-ftest-coverage", "-fpsl"])
    ui.set_sim_option("ghdl.elab_flags", ["-Wl,-lgcov", "-Wl,--coverage", "-Wl,-no-pie", "-fpsl"])
91 92 93 94
    ui.set_sim_option("ghdl.sim_flags", ["--ieee-asserts=disable-at-0"])
    modelsim_init_files = get_common_modelsim_init_files()
    ui.set_sim_option("modelsim.init_files.after_load", modelsim_init_files)

Martin Jeřábek's avatar
Martin Jeřábek committed
95

96 97 98 99 100 101 102 103 104 105 106 107 108
def get_seed(cfg):
    if 'seed' in cfg and 'randomize' in cfg:
        log.warning('Both "seed" and "randomize" are set - seed takes precedence')
    if 'seed' in cfg:
        seed = cfg['seed']
    elif cfg.get('randomize', False):
        # only 31 bits
        seed = int(random.random() * 2**31) & 0x7FFFFFFF
    else:
        seed = 0
    return seed


109 110 111 112 113 114
def dict_merge(up, *lowers):
    for lower in lowers:
        for k, v in lower.items():
            if k not in up:
                up[k] = v

Martin Jeřábek's avatar
Martin Jeřábek committed
115

116 117 118 119 120 121 122 123 124
def vhdl_serialize(o):
    if isinstance(o, Iterable):
        ss = []
        for x in o:
            ss.append(vhdl_serialize(x))
        return ''.join(['(', ', '.join(ss), ')'])
    else:
        return str(o)

Martin Jeřábek's avatar
Martin Jeřábek committed
125

126 127 128 129 130 131 132
def dump_sim_options(lib):
    for tb in lib.get_test_benches('*'):
        for cfgs in tb._test_bench.get_configuration_dicts():
            for name, cfg in cfgs.items():
                print('{}#{}:'.format(tb.name, name))
                #pprint(cfg.__dict__)
                pprint(cfg.sim_options)