Skip to content

Commit 87b9f3b

Browse files
committed
Add regression test
1 parent 7fb25b6 commit 87b9f3b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+555
-828
lines changed

src/peakrdl_halcpp/templates/test.cpp.j2

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,33 @@
11
#include "mock_io.h"
22
#include "{{ top.orig_type_name }}_hal.h"
3-
#include "test_utils.h"
3+
#include "field_test_utils.h"
4+
#include "reg_test_utils.h"
45

56
inline constexpr {{ top.orig_type_name|upper }}_HAL<0> {{ top.orig_type_name }}{};
67

7-
int main (int argc, char *argv[]) {
8+
int main () {
9+
10+
{% for reg in regs %}
11+
test_generic_reg({{ reg|resolve_path_array_refs }}, {{ reg.absolute_address }}, "{{ reg.get_path() }}");
12+
{% if reg.has_sw_readable and reg.has_sw_writable %}
13+
test_rw_reg({{ reg|resolve_path_array_refs }}, "{{ reg.get_path() }}");
14+
{% elif reg.has_sw_readable and not reg.has_sw_writable %}
15+
test_ro_reg({{ reg|resolve_path_array_refs }});
16+
{% elif not reg.has_sw_readable and reg.has_sw_writable %}
17+
test_wo_reg({{ reg|resolve_path_array_refs }});
18+
{% endif %}
19+
20+
{% endfor %}
821

922
{% for field in fields %}
10-
test_generic_field({{ field.get_path() }}, {{ field.width }}, {{ field.parent.absolute_address }}, {{ field.low }}, {{ field.high }}, "{{ field.get_path() }}");
23+
{% set field_ref = field|resolve_path_array_refs %}
24+
test_generic_field({{ field_ref }}, {{ field.width }}, {{ field.parent.absolute_address }}, {{ field.low }}, {{ field.high }}, "{{ field.get_path() }}");
1125
{% if field.is_sw_readable and field.is_sw_writable %}
12-
test_rw_field<decltype({{ field.get_path() }}), {{ field.width }}>({{ field.get_path() }}, "{{ field.get_path() }}");
26+
test_rw_field<decltype({{ field_ref }}), {{ field.width }}>({{ field_ref }}, "{{ field.get_path() }}");
1327
{% elif field.is_sw_readable and not field.is_sw_writable %}
14-
test_ro_field<decltype({{ field.get_path() }}), {{ field.width }}>({{ field.get_path() }}, "{{ field.get_path() }}");
28+
test_ro_field<decltype({{ field_ref }}), {{ field.width }}>({{ field_ref }});
1529
{% elif not field.is_sw_readable and field.is_sw_writable %}
16-
test_wo_field<decltype({{ field.get_path() }}), {{ field.width }}>({{ field.get_path() }}, "{{ field.get_path() }}");
30+
test_wo_field<decltype({{ field_ref }}), {{ field.width }}>({{ field_ref }});
1731
{% endif %}
1832

1933
{% endfor %}

src/peakrdl_halcpp/templates/test_CMakeLists.txt.j2

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ function(hal_test TEST_NAME)
2020
test_utils
2121
)
2222

23+
target_compile_options(${TEST_NAME} PUBLIC
24+
-fno-delete-null-pointer-checks
25+
-Wall -Wextra -Wpedantic -Werror
26+
)
27+
2328
add_test(
2429
NAME ${TEST_NAME}
2530
COMMAND $<TARGET_FILE:${TEST_NAME}>

src/peakrdl_halcpp/test_generator.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
from pathlib import Path
2+
import re
23
import shutil
34
import jinja2 as jj
45
import os
56
from typing import Any, Dict, Optional
6-
from systemrdl.node import AddrmapNode, FieldNode
7+
from systemrdl.node import AddrmapNode, FieldNode, Node, RegNode
78
from systemrdl.walker import RDLListener, RDLWalker, WalkerAction
89

910

1011
class FieldListener(RDLListener):
1112

1213
def __init__(self) -> None:
1314
self.fields: list[FieldNode] = []
15+
self.regs: list[RegNode] = []
1416
self.curr_addrmap: AddrmapNode|None = None
1517

1618
def enter_Field(self, node: FieldNode) -> Optional[WalkerAction]:
1719
self.fields.append(node)
1820

21+
def enter_Reg(self, node: RegNode) -> Optional[WalkerAction]:
22+
self.regs.append(node)
23+
1924
def enter_Addrmap(self, node: AddrmapNode) -> Optional[WalkerAction]:
2025
if self.curr_addrmap is None:
2126
self.curr_addrmap = node
@@ -30,6 +35,27 @@ def __init__(self) -> None:
3035
def enter_Addrmap(self, node: AddrmapNode) -> Optional[WalkerAction]:
3136
self.addrmaps.append(node)
3237

38+
def transform_systemrdl_array_indices_to_halcpp(s):
39+
# Match identifier followed by group of indexes reg0[0][2][4]
40+
pattern = re.compile(r'([a-zA-Z_]\w*)((?:\[\d+\])+)' )
41+
42+
def repl(match):
43+
ident = match.group(1)
44+
brackets = match.group(2)
45+
# extract numbers from [n]
46+
nums = re.findall(r'\[(\d+)\]', brackets)
47+
# replace it with .at<0, 2, 4>()
48+
return f"{ident}.at<{','.join(nums)}>()"
49+
50+
return re.sub(pattern, repl, s)
51+
52+
def resolve_path_array_refs(node: Node) -> str:
53+
path = node.get_path()
54+
# path = path.replace("[", ".template at<")
55+
# path = path.replace("]", ">()")
56+
path = transform_systemrdl_array_indices_to_halcpp(path)
57+
58+
return path
3359

3460
class TestGenerator:
3561

@@ -52,6 +78,7 @@ def export(self,
5278
context: dict[str, Any] = {
5379
"top": node,
5480
"fields": field_listener.fields,
81+
"regs": field_listener.regs,
5582
}
5683
test_content: str = self.process_template(context, "test.cpp.j2")
5784

@@ -103,6 +130,7 @@ def process_template(self,
103130
# Add the base zip function to the env
104131
env.filters.update({
105132
'zip': zip,
133+
"resolve_path_array_refs": resolve_path_array_refs
106134
})
107135
# Render the C++ header text using the jinja2 template and the
108136
# specific context
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
#ifndef __FIELD_TEST_UTILS_H_
2+
#define __FIELD_TEST_UTILS_H_
3+
4+
#include <cstdint>
5+
#include <iostream>
6+
#include <cassert>
7+
#include "test_utils.h"
8+
9+
/****************************/
10+
/***** Field Width test *****/
11+
/****************************/
12+
13+
void assert_field_width(uint32_t expected_width,
14+
uint32_t actual_width,
15+
const char *field_path){
16+
if(expected_width != actual_width){
17+
std::cerr << "Field width test error for " << field_path;
18+
std::cerr << "\n\tExpected width: " << std::dec << expected_width;
19+
std::cerr << "\n\tActual width: " << std::dec << actual_width << std::endl;
20+
assert(expected_width == actual_width);
21+
}
22+
}
23+
24+
template<typename FIELD_T>
25+
void test_field_width(FIELD_T &field, uint32_t width, const char* field_path){
26+
assert_field_width(width, field.get_width(), field_path);
27+
}
28+
29+
/**********************************/
30+
/***** Field Base address test ****/
31+
/**********************************/
32+
33+
void assert_field_base_address(uint32_t expected_base_address,
34+
uint32_t actual_base_address,
35+
const char *field_path){
36+
if(expected_base_address != actual_base_address){
37+
std::cerr << "Field base address test error for " << field_path;
38+
std::cerr << "\n\tExpected base address: 0x" << std::hex << expected_base_address;
39+
std::cerr << "\n\tActual base address: 0x" << std::hex << actual_base_address << std::endl;
40+
assert(expected_base_address == actual_base_address);
41+
}
42+
}
43+
44+
template<typename FIELD_T>
45+
void test_field_base_address(FIELD_T &field, uint32_t base_address, const char* field_path){
46+
assert_field_width(base_address, field.get_abs_addr(), field_path);
47+
}
48+
49+
/**********************************/
50+
/*** Field start/end bit test *****/
51+
/**********************************/
52+
53+
void assert_field_start_end_bit(uint32_t expected_start_bit,
54+
uint32_t actual_start_bit,
55+
uint32_t expected_end_bit,
56+
uint32_t actual_end_bit,
57+
const char *field_path){
58+
if((expected_start_bit != actual_start_bit) or
59+
(expected_end_bit != actual_end_bit)){
60+
std::cerr << "Field start/end test error for " << field_path;
61+
std::cerr << "\n\tExpected start bit index: " << std::dec << expected_start_bit;
62+
std::cerr << "\n\tActual start bit index: " << std::dec << actual_start_bit;
63+
std::cerr << "\n\tExpected end bit index: " << std::dec << expected_end_bit;
64+
std::cerr << "\n\tActual end bit index: " << std::dec << actual_end_bit << std::endl;
65+
assert(expected_start_bit == actual_start_bit);
66+
assert(expected_end_bit == actual_end_bit);
67+
}
68+
}
69+
70+
template<typename FIELD_T>
71+
void test_field_start_end_bit(FIELD_T &field, uint32_t start_bit, uint32_t end_bit, const char* field_path){
72+
uint32_t read_start_bit = field.get_start_bit();
73+
uint32_t read_end_bit = field.get_end_bit();
74+
assert_field_start_end_bit(start_bit, read_start_bit, end_bit, read_end_bit, field_path);
75+
}
76+
77+
/****************************/
78+
/****** RW Field test *******/
79+
/****************************/
80+
81+
void assert_rw(uint32_t exp, uint32_t rec, const char* field_path){
82+
if(exp != rec){
83+
std::cerr << "Field RW test error for " << field_path;
84+
std::cerr << "\n\tWrote: 0x" << std::hex << exp;
85+
std::cerr << "\n\tRead: 0x" << std::hex << rec << "\n";
86+
assert(exp == rec);
87+
}
88+
}
89+
90+
template<typename FIELD_T>
91+
void test_rw_field(uint32_t val, uint32_t exp, FIELD_T &field, const char* field_path){
92+
field = val;
93+
94+
uint32_t result = field;
95+
assert_rw(exp, result, field_path);
96+
}
97+
98+
template<typename FIELD_T>
99+
void test_rw_field_marching_ones(FIELD_T &field, const char* field_path){
100+
uint32_t width = field.get_width();
101+
test_rw_field(0, 0, field, field_path);
102+
for (uint32_t i = 0; i < width; i++) {
103+
uint32_t write_val = 1 << i;
104+
test_rw_field(write_val, write_val, field, field_path);
105+
}
106+
}
107+
108+
template<typename FIELD_T>
109+
void test_rw_field_overflow(FIELD_T &field, const char* field_path){
110+
uint32_t width = field.get_width();
111+
test_rw_field((1 << width), 0, field, field_path);
112+
}
113+
114+
void assert_rw_at(uint32_t bit_idx, uint32_t exp_bit_val, uint32_t exp_field_val, uint32_t actual_field_val, const char* field_path) {
115+
uint32_t mask = 1u << bit_idx;
116+
uint32_t rec_bit = (actual_field_val & mask) ? 1u : 0u;
117+
118+
if ((exp_bit_val != rec_bit) or
119+
(exp_field_val != actual_field_val)) {
120+
std::cerr << "Field RW at() accessor test error for " << field_path;
121+
std::cerr << "\n\tBit index: " << std::dec << bit_idx;
122+
std::cerr << "\n\tExpected: " << exp_bit_val;
123+
std::cerr << "\n\tBut read: " << rec_bit;
124+
std::cerr << "\n\tExpected field value: 0x" << std::hex << exp_field_val;
125+
std::cerr << "\n\tActual field value: 0x" << std::hex << actual_field_val << "\n";
126+
assert(exp_bit_val == rec_bit);
127+
assert(exp_field_val == actual_field_val);
128+
}
129+
}
130+
131+
template<typename FIELD_T, uint32_t WIDTH>
132+
void test_rw_field_at_accessor(FIELD_T &field, const char* field_path){
133+
test_rw_field(0, 0, field, field_path);
134+
uint32_t exp_val = 0;
135+
for_sequence<WIDTH>([&field, &exp_val, &field_path](auto i) {
136+
field.template at<i>() = 1;
137+
exp_val = exp_val | (1 << i);
138+
assert_rw_at(i, 1, exp_val, field.get(), field_path);
139+
});
140+
141+
// Set the last bit of the field to 0, (currently all bits are 1)
142+
field.template at<-1>() = 0;
143+
exp_val = (1 << (WIDTH-1)) - 1;
144+
assert_rw_at(WIDTH-1, 0, exp_val, field.get(), field_path);
145+
}
146+
147+
template<typename FIELD_T, uint32_t WIDTH>
148+
void test_rw_field(FIELD_T &field,
149+
const char* field_path){
150+
test_rw_field_marching_ones(field, field_path);
151+
test_rw_field_overflow(field, field_path);
152+
test_rw_field_at_accessor<FIELD_T, WIDTH>(field, field_path);
153+
}
154+
155+
156+
/****************************/
157+
/****** RO Field test *******/
158+
/****************************/
159+
160+
template<typename FIELD_T, uint32_t WIDTH>
161+
void test_ro_field_at_accessor(FIELD_T &field){
162+
for_sequence<WIDTH>([&field](auto i) {
163+
[[maybe_unused]] volatile uint32_t val = field.template at<i>();
164+
});
165+
[[maybe_unused]] volatile uint32_t val = field.template at<-1>().get();
166+
}
167+
168+
template<typename FIELD_T, uint32_t WIDTH>
169+
void test_ro_field(FIELD_T &field){
170+
[[maybe_unused]] volatile uint32_t read = field;
171+
test_ro_field_at_accessor<FIELD_T, WIDTH>(field);
172+
}
173+
174+
/****************************/
175+
/****** WO Field test *******/
176+
/****************************/
177+
178+
template<typename FIELD_T, uint32_t WIDTH>
179+
void test_wo_field_at_accessor(FIELD_T &field){
180+
for_sequence<WIDTH>([&field](auto i) {
181+
field.template at<i>() = 1;
182+
});
183+
field.template at<-1>() = 0;
184+
}
185+
186+
template<typename FIELD_T, uint32_t WIDTH>
187+
void test_wo_field(FIELD_T &field){
188+
field = 1;
189+
test_wo_field_at_accessor<FIELD_T, WIDTH>(field);
190+
}
191+
192+
/****************************/
193+
/**** Generic Field test ****/
194+
/****************************/
195+
196+
template<typename FIELD_T>
197+
void test_generic_field(FIELD_T &field,
198+
uint32_t width,
199+
size_t base_address,
200+
uint32_t start_bit,
201+
uint32_t end_bit,
202+
const char* field_path){
203+
204+
test_field_width(field, width, field_path);
205+
test_field_base_address(field, base_address, field_path);
206+
test_field_start_end_bit(field, start_bit, end_bit, field_path);
207+
208+
}
209+
210+
#endif

0 commit comments

Comments
 (0)