Skip to content

Commit

Permalink
Add testcases
Browse files Browse the repository at this point in the history
  • Loading branch information
amykyta3 committed Oct 15, 2023
1 parent 8d774dc commit 3d1025c
Show file tree
Hide file tree
Showing 19 changed files with 568 additions and 250 deletions.
45 changes: 42 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,21 @@ jobs:
strategy:
matrix:
python-version:
- 3.6
- 3.7
- 3.8
- 3.9
- "3.10"
- "3.11"
- "3.12"
include:
- os: ubuntu-latest

runs-on: ubuntu-latest
# older versions need older OS
- python-version: 3.6
os: ubuntu-20.04

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v3
Expand All @@ -37,10 +45,41 @@ jobs:

- name: Install dependencies
run: |
python -m pip install pytest
python -m pip install -U -r tests/requirements.txt
- name: Install
run: |
python -m pip install .
- name: Test
run: |
cd tests
pytest --cov=peakrdl_cheader
# TODO: Add actual testcase
- name: Coveralls
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_PARALLEL: true
run: |
cd tests
coveralls --service=github
finish_coveralls:
needs: test
runs-on: ubuntu-latest
steps:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: 3.x

- name: Coveralls
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_PARALLEL: true
run: |
python -m pip install -U coveralls>=3.0.0
coveralls --service=github --finish
#-------------------------------------------------------------------------------
lint:
Expand Down
2 changes: 2 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ sphinx:
python:
install:
- requirements: docs/requirements.txt
- method: pip
path: .
5 changes: 5 additions & 0 deletions docs/output.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Generated Header Contents

Block Structs
-------------
TODO: Add details. possible unions, anon unions

Bit-fiddling Field Macros
-------------------------
Expand Down Expand Up @@ -46,3 +47,7 @@ Register bitfield structs
If enabled, each register is represented by a nested union & struct definition.
This allows a register value to be accessed in aggregate, or by its individual
bit-fields.

TODO: Add details. union structure. Overlapping fields

TODO: Add section on wide regs?
4 changes: 2 additions & 2 deletions src/peakrdl_cheader/header_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ def write_bitfields(self, grp_name: str, regwidth: int, fields: List[FieldNode])
self.write(f"uint{regwidth}_t {kwf(field.inst_name)} :{field.width:d};\n")
current_offset -= field.width

if current_offset > 0:
self.write(f"uint{regwidth}_t :{current_offset:d};\n")
if current_offset > -1:
self.write(f"uint{regwidth}_t :{current_offset + 1:d};\n")

self.pop_indent()
self.write(f"}} {grp_name};\n")
Expand Down
19 changes: 14 additions & 5 deletions src/peakrdl_cheader/testcase_generator.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from typing import List, TextIO, Set
from typing import List, TextIO, Set, Match
import os
import re

from systemrdl.walker import RDLListener, RDLWalker, WalkerAction
from systemrdl.walker import RDLListener, RDLWalker
from systemrdl.node import AddrmapNode, RegNode, AddressableNode

from .design_state import DesignState
from . import utils
from .identifier_filter import kw_filter as kwf

class TestcaseGenerator:
def __init__(self, ds: DesignState) -> None:
Expand Down Expand Up @@ -57,6 +59,7 @@ def run(self, f: TextIO, top_nodes: List[AddrmapNode]) -> None:
f.write("static void test_offsets(void){\n")
self.push_indent()
for node in top_nodes:
node.zero_lineage_index()
self.root_node = node
self.root_struct_name = utils.get_struct_name(self.ds, node, node)
RDLWalker(unroll=True).walk(node, self)
Expand Down Expand Up @@ -111,20 +114,26 @@ def enter_Reg(self, node: RegNode) -> None:
else:
member = node.get_rel_path(self.root_node)

# Sanitize keywords
def kwrepl(m: Match) -> str:
return kwf(m.group(0))
member = re.sub(r"\w+", kwrepl, member)

if self.ds.generate_bitfields:
# Reg is defined as a bitfield union. Access entire word member
member += ".w"

regwidth = node.get_property('regwidth')
node_addr = node.absolute_address - self.root_node.absolute_address
if regwidth > 64:
# Reg is split into an array of subwords
n_subwords = regwidth // self.ds.wide_reg_subword_size
stride = self.ds.wide_reg_subword_size // 8
for i in range(n_subwords):
addr = f"{node.absolute_address + i * stride:#x}UL"
addr = f"{node_addr + i * stride:#x}UL"
self.write(f"assert(offsetof({self.root_struct_name}, {member}[{i}]) == {addr});\n")
else:
self.write(f"assert(offsetof({self.root_struct_name}, {member}) == {node.absolute_address:#x}UL);\n")
self.write(f"assert(offsetof({self.root_struct_name}, {member}) == {node_addr:#x}UL);\n")



Expand Down Expand Up @@ -202,7 +211,7 @@ def enter_Reg(self, node: RegNode) -> None:
for field in fields:
field_prefix = prefix + "__" + field.inst_name.upper()
self.write("reg.w = 0;\n")
self.write(f"reg.{grp_name}.{field.inst_name} = {(1 << field.width) - 1:#x};\n")
self.write(f"reg.{grp_name}.{kwf(field.inst_name)} = {(1 << field.width) - 1:#x};\n")
self.write(f"assert(reg.w == {field_prefix}_bm);\n")
self.pop_indent()
self.write("}\n")
19 changes: 4 additions & 15 deletions src/peakrdl_cheader/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,8 @@

def get_node_prefix(ds: DesignState, root_node: AddrmapNode, node: AddressableNode) -> str:
if ds.reuse_typedefs:
prefix = node.inst.get_scope_path("__")
if prefix is not None:
# Complete the scope path
if prefix == "":
prefix = node.type_name
else:
prefix += "__" + node.type_name
else:
prefix = node.get_global_type_name("__")
if prefix is None:
# Unable to determine a reusable type name. Fall back to hierarchical path
# Add prefix to prevent collision when mixing namespace methods
prefix = "xtern__" + node.get_rel_path(
Expand Down Expand Up @@ -46,14 +40,9 @@ def get_friendly_name(ds: DesignState, root_node: AddrmapNode, node: Node) -> st
a comment
"""
if ds.reuse_typedefs:
scope_path = node.inst.get_scope_path()
friendly_name = node.get_global_type_name("::")

if scope_path is not None and node.type_name is not None:
if scope_path == "":
friendly_name = node.type_name
else:
friendly_name = scope_path + "::" + node.type_name
else:
if friendly_name is None:
# Unable to determine a reusable type name. Fall back to hierarchical path
friendly_name = node.get_rel_path(root_node.parent)
else:
Expand Down
20 changes: 20 additions & 0 deletions tests/.coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[run]
branch = True
#relative_files = True

omit =
# to be covered elsewhere
*/__peakrdl__.py

[paths]
source =
../src/peakrdl_cheader/
*/site-packages/*/peakrdl_cheader
*/site-packages/peakrdl_cheader

[report]
exclude_lines =
pragma: no cover
if TYPE_CHECKING:

precision = 1
32 changes: 26 additions & 6 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def get_permutations(spec):
return param_list

class BaseHeaderTestcase(TestCase):
rdl_file = "testcases/basic.rdl"
rdl_file = ""

# Export parameters
std = CStandard.latest
Expand All @@ -24,20 +24,34 @@ class BaseHeaderTestcase(TestCase):
reuse_typedefs = True
wide_reg_subword_size = 32
explode_top = False
instantiate = False

@classmethod
def get_run_dir(cls) -> str:
this_dir = os.path.dirname(__file__)
run_dir = os.path.join(this_dir, cls.__name__ + ".out")
run_dir = os.path.join(this_dir, "test.out", cls.__name__)
return run_dir

@property
def output_dir(self) -> str:
return self.get_run_dir()

@classmethod
def _write_params(cls) -> None:
"""
Write out the class parameters to a file so that it is easier to debug
how a testcase was parameterized
"""
path = os.path.join(cls.get_run_dir(), "params.txt")

with open(path, 'w') as f:
for k, v in cls.__dict__.items():
if k.startswith("_") or callable(v):
continue
f.write(f"{k}: {repr(v)}\n")

def do_export(self):
if not os.path.exists(self.output_dir):
os.mkdir(self.output_dir)
os.makedirs(self.output_dir, exist_ok=True)

rdl_path = os.path.join(os.path.dirname(__file__), self.rdl_file)

Expand All @@ -55,11 +69,13 @@ def do_export(self):
reuse_typedefs=self.reuse_typedefs,
wide_reg_subword_size=self.wide_reg_subword_size,
explode_top=self.explode_top,
instantiate=False,
instantiate=self.instantiate,
inst_offset=0,
testcase=True,
)

self._write_params()

def do_compile(self):
args = [
"gcc",
Expand All @@ -81,7 +97,11 @@ def do_run(self):
print(ret.stderr.decode('utf-8'))
self.assertEqual(ret.returncode, 0)

def test_me(self):
def do_test(self):
self.do_export()
self.do_compile()
self.do_run()


ALL_CSTDS = set(CStandard)
ALL_CSTDS.remove(CStandard.gnu23) # Not available yet
Loading

0 comments on commit 3d1025c

Please sign in to comment.