Skip to content

Commit

Permalink
CI - Run RTL elaboration during tests, add SV tests, use argparse in …
Browse files Browse the repository at this point in the history
…tests

The RTL elaboration is done using ghdl and verilator. In the case of
verilator, a apptainer container is used to get a newer (>=5) version of
verilator.

Also adds the necessary packages for the SV files.
  • Loading branch information
stefanlippuner committed Nov 5, 2023
1 parent 92413bc commit cc0b9bd
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 38 deletions.
1 change: 1 addition & 0 deletions .github/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sif
11 changes: 11 additions & 0 deletions .github/verilator_apptainer
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

IMAGE='verilator/verilator:v5.018'
IMAGE_FILE=$(dirname $0)/verilator.sif

if [ ! -f $IMAGE_FILE ]; then
apptainer pull $IMAGE_FILE docker://$IMAGE
fi

export LC_ALL="C"
apptainer run $IMAGE_FILE $@
11 changes: 10 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ jobs:
- name: Checkout sources
uses: actions/checkout@v4

- name: Install Tools
run: |
sudo apt-get install ghdl
wget https://github.com/apptainer/apptainer/releases/download/v1.2.4/apptainer_1.2.4_amd64.deb -O /tmp/apptainer.deb
sudo dpkg -i /tmp/apptainer.deb && false
sudo apt-get install -f
.github/verilator_apptainer --version
- name: Setup Python venv
run: |
python3 -m venv .venv
Expand All @@ -19,8 +27,9 @@ jobs:
- name: Test Generation
run: |
export VERILATOR=$(pwd)/.github/verilator_apptainer
cd proto
python3 tests.py
python3 tests.py -e
interaction:
name: Interaction
Expand Down
108 changes: 71 additions & 37 deletions proto/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import sys
import os
import subprocess
import argparse
import cheby.parser as parser
import cheby.layout as layout
import cheby.print_pretty as pprint
Expand All @@ -29,9 +30,8 @@

srcdir = os.path.join(os.path.dirname(os.path.realpath(__file__)),
'../testfiles/')
verbose = False
flag_regen = False
flag_keep = False

args = None
nbr_tests = 0


Expand All @@ -46,7 +46,7 @@ def werr(s):


def error(msg):
if flag_keep:
if args.keep:
werr('error: {}'.format(msg))
else:
raise TestError('error: {}'.format(msg))
Expand Down Expand Up @@ -91,7 +91,7 @@ def test_parser():
'features/block1', 'features/submap2', 'features/submap3',
'features/block4', 'parser/extension1']:
f += '.cheby'
if verbose:
if args.verbose:
print('test parser: {}'.format(f))
parse_ok(srcdir + f)
nbr_tests += 1
Expand All @@ -105,7 +105,7 @@ def test_parser():
'parse_err_array1', 'parse_err_array2',
'parse_err_block1',
'err_cnt', 'err_cnt2', 'err_extension']:
if verbose:
if args.verbose:
print('test parser: {}'.format(f))
parse_err(srcdir + 'parser/' + f + '.cheby')
nbr_tests += 1
Expand Down Expand Up @@ -135,7 +135,7 @@ def test_layout():
'bug-gen-c-02/fip_urv_regs',
'issue99/m1', 'issue99/m2']:
f += '.cheby'
if verbose:
if args.verbose:
print('test layout: {}'.format(f))
t = parse_ok(srcdir + f)
layout_ok(t)
Expand Down Expand Up @@ -176,7 +176,7 @@ def test_layout():
'issue14/test-err',
'issue57/m1', 'issue71/m1', 'features/enums3']:
f += '.cheby'
if verbose:
if args.verbose:
print('test layout: {}'.format(f))
t = parse_ok(srcdir + f)
layout_err(t)
Expand Down Expand Up @@ -208,9 +208,9 @@ def compare_buffer_and_file(buf, filename):
return True
except:
# Usually an IO error.
if not flag_regen:
if not args.regen:
raise
if flag_regen:
if args.regen:
open(filename, 'w').write(buf)
werr('Regenerate {}'.format(filename))
return True
Expand All @@ -220,7 +220,7 @@ def compare_buffer_and_file(buf, filename):
if nlines != len(ref_lines):
werr('Number of lines mismatch')
return False
if flag_keep:
if args.keep:
return False
for i in range(nlines):
if buf_lines[i] == ref_lines[i]:
Expand Down Expand Up @@ -275,7 +275,7 @@ def test_hdl():
'issue95/m1', 'issue95/m2', 'issue95/m3', 'issue95/sm1', 'issue95/sm3',
'features/avalon-noaddr', 'issue129/acdipole_ip', 'issue129/acdipole_ip-orig',
'issue67/repeatInRepeat']:
if verbose:
if args.verbose:
print('test hdl: {}'.format(f))
t = parse_ok(srcdir + f + '.cheby')
layout_ok(t)
Expand Down Expand Up @@ -315,7 +315,7 @@ def test_hdl_err():
'access/autoclear_err_ro',
'access/orclr_err_ro', 'access/orclr_err_wo',
'issue109/test']:
if verbose:
if args.verbose:
print('test hdl error: {}'.format(f))
t = parse_ok(srcdir + f + '.cheby')
layout_ok(t)
Expand All @@ -324,7 +324,7 @@ def test_hdl_err():
nbr_tests += 1
# Error in gen_name
for f in ['issue65/m1']:
if verbose:
if args.verbose:
print('test hdl error: {}'.format(f))
t = parse_ok(srcdir + f + '.cheby')
layout_ok(t)
Expand All @@ -344,8 +344,18 @@ def test_hdl_err():
nbr_tests += 1

def test_hdl_ref():
# Generate vhdl and compare with a baseline.
# Generate HDL, compare with a baseline and potentially elaborate.
global nbr_tests

if args.elaborate:
# Allow the definition of a different verilator command
if 'VERILATOR' in os.environ:
verilator_cmd = os.environ['VERILATOR']
else:
verilator_cmd = 'verilator'
if args.verbose:
print('Running elaboration with verilator command {}.'.format(verilator_cmd))

for f in ['fmc-adc01/fmc_adc_alt_trigin', 'fmc-adc01/fmc_adc_alt_trigout',
'issue9/test', 'issue10/test',
'issue8/simpleMap_bug', 'issue8/simpleMap_noBug',
Expand Down Expand Up @@ -385,10 +395,11 @@ def test_hdl_ref():
'issue92/blockInMap', 'issue90/bugDPSSRAMbwSel',
'bug-repmem/bran', 'bug-empty/noout', 'bug-empty/noinp',
'bug-cernbe/repro', 'bug-cernbe/sub_repro']:
if verbose:
if args.verbose:
print('test hdl with ref: {}'.format(f))
cheby_file = srcdir + f + '.cheby'
vhdl_file = srcdir + f + '.vhdl'
sv_file = srcdir + f + '.sv'
t = parse_ok(cheby_file)
layout_ok(t)
expand_hdl.expand_hdl(t)
Expand All @@ -398,13 +409,31 @@ def test_hdl_ref():
print_vhdl.print_vhdl(buf, h)
if not compare_buffer_and_file(buf, vhdl_file):
error('vhdl generation error for {}'.format(f))
buf_sv = write_buffer()
print_verilog.print_verilog(buf_sv, h)
if not compare_buffer_and_file(buf_sv, sv_file):
error('SV generation error for {}'.format(f))
nbr_tests += 1

if args.elaborate:
# Elaboration tests
top_entity = t.hdl_module_name

vhdl_pkgs = [srcdir + 'tb/cheby_pkg.vhd', srcdir + 'tb/wishbone_pkg.vhd']
res = subprocess.run(['ghdl', '-s'] + vhdl_pkgs + [vhdl_file])
if res.returncode != 0:
error('VHDL elaboration failed for {}'.format(f))

sv_pkgs = [srcdir + 'tb/dpssram.sv', srcdir + 'tb/wishbone_pkg.sv']
res = subprocess.run([verilator_cmd, '--lint-only', '--top-module', top_entity] + sv_pkgs + [sv_file])
if res.returncode != 0:
error('SV elaboration failed for {}'.format(f))

def test_verilog_ref():
# Generate verilog and compare with a baseline.
global nbr_tests
for f in ['crossbar/crossbar']:
if verbose:
if args.verbose:
print('test verilog with ref: {}'.format(f))
cheby_file = srcdir + f + '.cheby'
vlog_file = srcdir + f + '.v'
Expand All @@ -422,10 +451,11 @@ def test_verilog_ref():
def test_issue84():
global nbr_tests
for f in ['issue84/sps200CavityControl_as']:
if verbose:
if args.verbose:
print('test hdl with ref: {}'.format(f))
cheby_file = srcdir + f + '.cheby'
vhdl_file = srcdir + f + '.vhdl'
sv_file = srcdir + f + '.sv'
t = parse_ok(cheby_file)
layout_ok(t)
expand_hdl.expand_hdl(t)
Expand All @@ -435,12 +465,16 @@ def test_issue84():
print_vhdl.print_vhdl(buf, h)
if not compare_buffer_and_file(buf, vhdl_file):
error('vhdl generation error for {}'.format(f))
buf_sv = write_buffer()
print_verilog.print_verilog(buf_sv, h)
if not compare_buffer_and_file(buf_sv, sv_file):
error('SV generation error for {}'.format(f))
nbr_tests += 1

def test_self():
"""Auto-test"""
def test(func, func_name):
if verbose:
if args.verbose:
print('test self: {}'.format(func_name))
ok = False
try:
Expand Down Expand Up @@ -507,7 +541,7 @@ def test_gena():
'Submap', 'Submap_internal',
'Muxed', 'Muxed2', 'Semver', 'Consts']
for f in files:
if verbose:
if args.verbose:
print('test gena: {}'.format(f))
# Test Gena to Cheby conversion
xmlfile = srcdir + 'gena/' + f + '.xml'
Expand Down Expand Up @@ -543,7 +577,7 @@ def test_gena_regctrl_err():
global nbr_tests
files = ['Muxed_name', 'Muxed_code']
for f in files:
if verbose:
if args.verbose:
print('test gena regctrl err: {}'.format(f))
# Test Gena to Cheby conversion
xmlfile = srcdir + 'err_gena/' + f + '.xml'
Expand Down Expand Up @@ -576,7 +610,7 @@ def test_gena2cheby():
'sub_reg_gen', 'sub_reg_gen_ignore',
'bit_field_gen', 'reg_name_boolean']
for f in files:
if verbose:
if args.verbose:
print('test gena2cheby: {}'.format(f))
# Test Gena to Cheby conversion
xmlfile = srcdir + 'gena2cheby/' + f + '.xml'
Expand All @@ -601,7 +635,7 @@ def test_gena2cheby_err():
'err_bit_field_gen', 'err_bit_field_attrs', 'err_bit_field_child',
'err_bit_field_preset']
for f in files:
if verbose:
if args.verbose:
print('test gena2cheby err: {}'.format(f))
# Test Gena to Cheby conversion
xmlfile = srcdir + 'gena2cheby/' + f + '.xml'
Expand Down Expand Up @@ -633,7 +667,7 @@ def test_gena2cheby_regressions():
'issue51/map', 'bug-unit/rfLimiter',
'bug-note/WB3_DDR', 'bug-note/WB3_DDR-1']
for f in files:
if verbose:
if args.verbose:
print('test gena2cheby regression: {}'.format(f))
# Test Gena to Cheby conversion
xmlfile = srcdir + f + '.xml'
Expand All @@ -659,7 +693,7 @@ def test_gena_gen_regressions():
'issue32/memmap', 'gena2cheby/submap_noinc', 'issue49/mainMap', 'issue33e/timing',
'issue68/m1', 'issue70/m3', 'issue69/m1', 'issue73/yesno2', 'issue102/mainMap']
for f in files:
if verbose:
if args.verbose:
print('test gena regression: {}'.format(f))
chebfile = srcdir + f + '.cheby'
# Test parse+layout
Expand Down Expand Up @@ -687,7 +721,7 @@ def test_gena_dsp_regressions():
global nbr_tests
files = ['issue106/m1']
for f in files:
if verbose:
if args.verbose:
print('test gena regression: {}'.format(f))
chebfile = srcdir + f + '.cheby'
# Test parse+layout
Expand Down Expand Up @@ -721,7 +755,7 @@ def test_wbgen2cheby():
'../issue28/wrc_syscon_wb']
print_vhdl.style = 'wbgen'
for f in files:
if verbose:
if args.verbose:
print('test wbgen2cheby: {}'.format(f))
# Test Gena to Cheby conversion
wbfile = srcdir + 'wbgen/' + f + '.wb'
Expand Down Expand Up @@ -750,7 +784,7 @@ def test_consts():
for f in ['demo_all', 'features/semver1', 'features/mapinfo1',
'issue64/simple_reg1', 'bug-consts/blkpfx',
'features/enums1', 'features/enums2']:
if verbose:
if args.verbose:
print('test consts: {}'.format(f))
cheby_file = srcdir + f + '.cheby'
vhdl_file = srcdir + f + '-consts.vhdl'
Expand All @@ -777,7 +811,7 @@ def test_doc():
# Generate html and md, compare with a baseline.
global nbr_tests
for f in ['issue9/test', 'features/semver1', 'issue84/sps200CavityControl_as', 'issue67/repeatInRepeat']:
if verbose:
if args.verbose:
print('test doc: {}'.format(f))
cheby_file = srcdir + f + '.cheby'
html_file = srcdir + f + '.html'
Expand Down Expand Up @@ -805,7 +839,7 @@ def test_doc():
def test_custom():
global nbr_tests
for f in ['custom/fidsErrMiss']:
if verbose:
if args.verbose:
print('test custom: {}'.format(f))
cheby_file = srcdir + f + '.cheby'
c_file = srcdir + f + '.h'
Expand All @@ -823,15 +857,15 @@ def test_custom():


def main():
global verbose, flag_regen, flag_keep
global args

# Crude
if '-v' in sys.argv[1:]:
verbose = True
if '--regen' in sys.argv[1:]:
flag_regen = True
if '-k' in sys.argv[1:]:
flag_keep = True
aparser = argparse.ArgumentParser(description='cheby tests')
aparser.add_argument('-v', '--verbose', action='store_true', help='Enable additional prints.')
aparser.add_argument('-r', '--regen', action='store_true', help='Regenerate golden test files.')
aparser.add_argument('-k', '--keep', action='store_true', help='Keep running tests after an error occured.')
aparser.add_argument('-e', '--elaborate', action='store_true', help='Enable elaboration tests.')
args = aparser.parse_args()

try:
test_self()
Expand Down
Loading

0 comments on commit cc0b9bd

Please sign in to comment.