Skip to content

Commit efbddcc

Browse files
Sebastien Baillouamykyta3
authored andcommitted
fix: handle error response for overlapped registers with read-only and write-only attributes (#178)
1 parent e1d7b3a commit efbddcc

File tree

4 files changed

+115
-124
lines changed

4 files changed

+115
-124
lines changed

src/peakrdl_regblock/addr_decode.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,23 +141,26 @@ def _add_addressablenode_decoding_flags(self, node: 'AddressableNode') -> None:
141141
readable = node.is_sw_readable
142142
writable = node.is_sw_writable
143143
if readable and writable:
144-
rhs_invalid_rw = "'0"
144+
pass
145145
elif readable and not writable:
146146
rhs = f"{addr_decoding_str} & !cpuif_req_is_wr"
147-
rhs_invalid_rw = f"{addr_decoding_str} & cpuif_req_is_wr"
148147
elif not readable and writable:
149148
rhs = f"{addr_decoding_str} & cpuif_req_is_wr"
150-
rhs_invalid_rw = f"{addr_decoding_str} & !cpuif_req_is_wr"
151149
else:
152150
raise RuntimeError
153151
# Add decoding flags
154152
self.add_content(f"{self.addr_decode.get_external_block_access_strobe(node)} = {rhs};")
155153
self.add_content(f"is_external |= {rhs};")
156-
if self.addr_decode.exp.ds.err_if_bad_addr:
154+
# Also assign is_valid_adddr when err_if_bad_rw is set so that it can be used to catch
155+
# invalid RW accesses on existing registers only.
156+
if self.addr_decode.exp.ds.err_if_bad_addr or self.addr_decode.exp.ds.err_if_bad_rw:
157157
self.add_content(f"is_valid_addr |= {rhs_valid_addr};")
158158
if isinstance(node, MemNode):
159159
if self.addr_decode.exp.ds.err_if_bad_rw:
160-
self.add_content(f"is_invalid_rw |= {rhs_invalid_rw};")
160+
self.add_content(f"is_valid_rw |= {rhs};")
161+
else:
162+
# For external register blocks, all accesses are valid RW
163+
self.add_content(f"is_valid_rw |= {rhs_valid_addr};")
161164

162165

163166
def enter_AddressableComponent(self, node: 'AddressableNode') -> Optional[WalkerAction]:
@@ -206,13 +209,10 @@ def _add_reg_decoding_flags(self,
206209
writable = node.has_sw_writable
207210
if readable and writable:
208211
rhs = addr_decoding_str
209-
rhs_invalid_rw = "'0"
210212
elif readable and not writable:
211213
rhs = f"{addr_decoding_str} & !cpuif_req_is_wr"
212-
rhs_invalid_rw = f"{addr_decoding_str} & cpuif_req_is_wr"
213214
elif not readable and writable:
214215
rhs = f"{addr_decoding_str} & cpuif_req_is_wr"
215-
rhs_invalid_rw = f"{addr_decoding_str} & !cpuif_req_is_wr"
216216
else:
217217
raise RuntimeError
218218
# Add decoding flags
@@ -222,10 +222,12 @@ def _add_reg_decoding_flags(self,
222222
self.add_content(f"{self.addr_decode.get_access_strobe(node)}[{subword_index}] = {rhs};")
223223
if node.external:
224224
self.add_content(f"is_external |= {rhs};")
225-
if self.addr_decode.exp.ds.err_if_bad_addr:
225+
# Also assign is_valid_adddr when err_if_bad_rw is set so that it can be used to catch
226+
# invalid RW accesses on existing registers only.
227+
if self.addr_decode.exp.ds.err_if_bad_addr or self.addr_decode.exp.ds.err_if_bad_rw:
226228
self.add_content(f"is_valid_addr |= {rhs_valid_addr};")
227229
if self.addr_decode.exp.ds.err_if_bad_rw:
228-
self.add_content(f"is_invalid_rw |= {rhs_invalid_rw};")
230+
self.add_content(f"is_valid_rw |= {rhs};")
229231

230232
def enter_Reg(self, node: RegNode) -> None:
231233
regwidth = node.get_property('regwidth')

src/peakrdl_regblock/module_tmpl.sv

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,19 +121,31 @@ module {{ds.module_name}}
121121

122122
always_comb begin
123123
automatic logic is_valid_addr;
124-
automatic logic is_invalid_rw;
124+
automatic logic is_valid_rw;
125125
{%- if ds.has_external_addressable %}
126126
automatic logic is_external;
127127
is_external = '0;
128128
{%- endif %}
129-
{%- if ds.err_if_bad_addr %}
129+
{%- if ds.err_if_bad_addr or ds.err_if_bad_rw %}
130130
is_valid_addr = '0;
131131
{%- else %}
132-
is_valid_addr = '1; // No error checking on valid address access
132+
is_valid_addr = '1; // No valid address check
133+
{%- endif %}
134+
{%- if ds.err_if_bad_rw %}
135+
is_valid_rw = '0;
136+
{%- else %}
137+
is_valid_rw = '1; // No valid RW check
133138
{%- endif %}
134-
is_invalid_rw = '0;
135139
{{address_decode.get_implementation()|indent(8)}}
136-
decoded_err = (~is_valid_addr | is_invalid_rw) & decoded_req;
140+
{%- if ds.err_if_bad_addr and ds.err_if_bad_rw %}
141+
decoded_err = (~is_valid_addr | (is_valid_addr & ~is_valid_rw)) & decoded_req;
142+
{%- elif ds.err_if_bad_addr %}
143+
decoded_err = ~is_valid_addr & decoded_req;
144+
{%- elif ds.err_if_bad_rw %}
145+
decoded_err = (is_valid_addr & ~is_valid_rw) & decoded_req;
146+
{%- else %}
147+
decoded_err = '0;
148+
{%- endif %}
137149
{%- if ds.has_external_addressable %}
138150
decoded_strb_is_external = is_external;
139151
external_req = is_external;

tests/test_cpuif_err_rsp/regblock.rdl

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ addrmap top {
33
default sw=rw;
44
default hw=na;
55

6+
// Internal registers
67
reg {
78
field {
89
sw=rw; hw=na; // Storage element
@@ -13,32 +14,27 @@ addrmap top {
1314
field {
1415
sw=r; hw=na; // Wire/Bus - constant value
1516
} f[31:0] = 80;
16-
} r_r;
17+
} r_ro;
1718

1819
reg {
1920
field {
2021
sw=w; hw=r; // Storage element
2122
} f[31:0] = 100;
22-
} r_w;
23+
} r_wo;
2324

24-
external reg {
25-
field {
26-
sw=rw; hw=na; // Storage element
27-
} f[31:0];
28-
} er_rw;
29-
30-
external reg {
31-
field {
32-
sw=r; hw=na; // Wire/Bus - constant value
33-
} f[31:0];
34-
} er_r;
35-
36-
external reg {
37-
field {
38-
sw=w; hw=na; // Storage element
39-
} f[31:0];
40-
} er_w;
25+
// Combined read-only and write-only register
26+
reg {
27+
default sw = w;
28+
default hw = r;
29+
field {} wvalue[32] = 0;
30+
} writeonly @ 0x1C;
31+
reg {
32+
default sw = r;
33+
default hw = na;
34+
field {} rvalue[32] = 200;
35+
} readonly @ 0x1C;
4136

37+
// External memories
4238
external mem {
4339
memwidth = 32;
4440
mementries = 2;
@@ -48,12 +44,33 @@ addrmap top {
4844
memwidth = 32;
4945
mementries = 2;
5046
sw=r;
51-
} mem_r @ 0x28;
47+
} mem_ro @ 0x28;
5248

5349
external mem {
5450
memwidth = 32;
5551
mementries = 2;
5652
sw=w;
57-
} mem_w @ 0x30;
53+
} mem_wo @ 0x30;
54+
55+
// External block
56+
external regfile {
57+
// Placeholder registers
58+
reg {
59+
field {
60+
sw=rw; hw=na;
61+
} f[31:0] = 40;
62+
} r_rw;
63+
64+
reg {
65+
field {
66+
sw=r; hw=na;
67+
} f[31:0] = 80;
68+
} r_ro;
5869

70+
reg {
71+
field {
72+
sw=w; hw=r;
73+
} f[31:0] = 100;
74+
} r_wo;
75+
} external_rf @ 0x40;
5976
};

tests/test_cpuif_err_rsp/tb_template.sv

Lines changed: 48 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,6 @@
33
{%- block dut_support %}
44
{% sv_line_anchor %}
55

6-
external_reg ext_reg_inst (
7-
.clk(clk),
8-
.rst(rst),
9-
10-
.req(hwif_out.er_rw.req),
11-
.req_is_wr(hwif_out.er_rw.req_is_wr),
12-
.wr_data(hwif_out.er_rw.wr_data),
13-
.wr_biten(hwif_out.er_rw.wr_biten),
14-
.rd_ack(hwif_in.er_rw.rd_ack),
15-
.rd_data(hwif_in.er_rw.rd_data),
16-
.wr_ack(hwif_in.er_rw.wr_ack)
17-
);
18-
19-
external_reg ro_reg_inst (
20-
.clk(clk),
21-
.rst(rst),
22-
23-
.req(hwif_out.er_r.req),
24-
.req_is_wr(hwif_out.er_r.req_is_wr),
25-
.wr_data(32'b0),
26-
.wr_biten(32'b0),
27-
.rd_ack(hwif_in.er_r.rd_ack),
28-
.rd_data(hwif_in.er_r.rd_data),
29-
.wr_ack()
30-
);
31-
32-
external_reg wo_reg_inst (
33-
.clk(clk),
34-
.rst(rst),
35-
36-
.req(hwif_out.er_w.req),
37-
.req_is_wr(hwif_out.er_w.req_is_wr),
38-
.wr_data(hwif_out.er_w.wr_data),
39-
.wr_biten(hwif_out.er_w.wr_biten),
40-
.rd_ack(),
41-
.rd_data(),
42-
.wr_ack(hwif_in.er_w.wr_ack)
43-
);
44-
456
external_block #(
467
.ADDR_WIDTH(3)
478
) mem_rw_inst (
@@ -64,14 +25,14 @@
6425
.clk(clk),
6526
.rst(rst),
6627

67-
.req(hwif_out.mem_r.req),
68-
.req_is_wr(hwif_out.mem_r.req_is_wr),
69-
.addr(hwif_out.mem_r.addr),
28+
.req(hwif_out.mem_ro.req),
29+
.req_is_wr(hwif_out.mem_ro.req_is_wr),
30+
.addr(hwif_out.mem_ro.addr),
7031
.wr_data(32'b0),
7132
.wr_biten(32'b0),
72-
.rd_ack(hwif_in.mem_r.rd_ack),
73-
.rd_data(hwif_in.mem_r.rd_data),
74-
.wr_ack(hwif_in.mem_r.wr_ack)
33+
.rd_ack(hwif_in.mem_ro.rd_ack),
34+
.rd_data(hwif_in.mem_ro.rd_data),
35+
.wr_ack(hwif_in.mem_ro.wr_ack)
7536
);
7637

7738
external_block #(
@@ -80,17 +41,33 @@
8041
.clk(clk),
8142
.rst(rst),
8243

83-
.req(hwif_out.mem_w.req),
84-
.req_is_wr(hwif_out.mem_w.req_is_wr),
85-
.addr(hwif_out.mem_w.addr),
86-
.wr_data(hwif_out.mem_w.wr_data),
87-
.wr_biten(hwif_out.mem_w.wr_biten),
44+
.req(hwif_out.mem_wo.req),
45+
.req_is_wr(hwif_out.mem_wo.req_is_wr),
46+
.addr(hwif_out.mem_wo.addr),
47+
.wr_data(hwif_out.mem_wo.wr_data),
48+
.wr_biten(hwif_out.mem_wo.wr_biten),
8849
.rd_ack(),
8950
.rd_data(),
90-
.wr_ack(hwif_in.mem_w.wr_ack)
51+
.wr_ack(hwif_in.mem_wo.wr_ack)
52+
);
53+
assign hwif_in.mem_wo.rd_ack = '0;
54+
assign hwif_in.mem_wo.rd_data = '0;
55+
56+
external_block #(
57+
.ADDR_WIDTH(4)
58+
) external_rf_inst (
59+
.clk(clk),
60+
.rst(rst),
61+
62+
.req(hwif_out.external_rf.req),
63+
.req_is_wr(hwif_out.external_rf.req_is_wr),
64+
.addr(hwif_out.external_rf.addr),
65+
.wr_data(hwif_out.external_rf.wr_data),
66+
.wr_biten(hwif_out.external_rf.wr_biten),
67+
.rd_ack(hwif_in.external_rf.rd_ack),
68+
.rd_data(hwif_in.external_rf.rd_data),
69+
.wr_ack(hwif_in.external_rf.wr_ack)
9170
);
92-
assign hwif_in.mem_w.rd_ack = '0;
93-
assign hwif_in.mem_w.rd_data = '0;
9471

9572
{%- endblock %}
9673

@@ -102,7 +79,7 @@ logic expected_rd_err;
10279
logic bad_addr_expected_err;
10380
logic bad_rw_expected_wr_err;
10481
logic bad_rw_expected_rd_err;
105-
logic [5:0] addr;
82+
logic [7:0] addr;
10683

10784
{% sv_line_anchor %}
10885
##1;
@@ -139,53 +116,29 @@ logic [5:0] addr;
139116
cpuif.write(addr, 81, .expects_err(expected_wr_err));
140117
cpuif.assert_read(addr, 80, .expects_err(expected_rd_err));
141118

142-
// r_w - sw=w; hw=r; // Storage element
119+
// r_wo - sw=w; hw=r; // Storage element
143120
addr = 'h8;
144121
expected_rd_err = bad_rw_expected_rd_err;
145122
expected_wr_err = 'h0;
146123
cpuif.assert_read(addr, 0, .expects_err(expected_rd_err));
147-
assert(cb.hwif_out.r_w.f.value == 100);
124+
assert(cb.hwif_out.r_wo.f.value == 100);
148125

149126
cpuif.write(addr, 101, .expects_err(expected_wr_err));
150127
cpuif.assert_read(addr, 0, .expects_err(expected_rd_err));
151-
assert(cb.hwif_out.r_w.f.value == 101);
152-
153-
// External registers
154-
// er_rw - sw=rw; hw=na; // Storage element
155-
addr = 'hC;
156-
expected_rd_err = 'h0;
157-
expected_wr_err = 'h0;
158-
ext_reg_inst.value = 'h8C;
159-
cpuif.assert_read(addr, 'h8C, .expects_err(expected_rd_err));
160-
cpuif.write(addr, 'h8D, .expects_err(expected_wr_err));
161-
cpuif.assert_read(addr, 'h8D, .expects_err(expected_rd_err));
162-
163-
// er_r - sw=r; hw=na; // Wire/Bus - constant value
164-
addr = 'h10;
165-
expected_rd_err = 'h0;
166-
expected_wr_err = bad_rw_expected_wr_err;
167-
ro_reg_inst.value = 'hB4;
168-
cpuif.assert_read(addr, 'hB4, .expects_err(expected_rd_err));
169-
cpuif.write(addr, 'hB5, .expects_err(expected_wr_err));
170-
cpuif.assert_read(addr, 'hB4, .expects_err(expected_rd_err));
171-
172-
// er_w - sw=w; hw=r; // Storage element
173-
addr = 'h14;
174-
expected_rd_err = bad_rw_expected_rd_err;
175-
expected_wr_err = 'h0;
176-
wo_reg_inst.value = 'hC8;
177-
cpuif.assert_read(addr, 0, .expects_err(expected_rd_err));
178-
assert(wo_reg_inst.value == 'hC8);
179-
180-
cpuif.write(addr, 'hC9, .expects_err(expected_wr_err));
181-
cpuif.assert_read(addr, 0, .expects_err(expected_rd_err));
182-
assert(wo_reg_inst.value == 'hC9);
128+
assert(cb.hwif_out.r_wo.f.value == 101);
183129

184130
// Reading/writing from/to non existing register
185131
addr = 'h18;
186132
cpuif.assert_read(addr, 0, .expects_err(bad_addr_expected_err));
187133
cpuif.write(addr, 'h8C, .expects_err(bad_addr_expected_err));
188134

135+
// Reading/writing from/to combined read AND write only register
136+
addr = 'h1C;
137+
expected_rd_err = 'h0;
138+
expected_wr_err = 'h0;
139+
cpuif.assert_read(addr, 200, .expects_err(expected_rd_err));
140+
cpuif.write(addr, 'h8C, .expects_err(expected_wr_err));
141+
189142
// External memories
190143
// mem_rw - sw=rw;
191144
addr = 'h20;
@@ -218,4 +171,11 @@ logic [5:0] addr;
218171
cpuif.assert_read(addr, 0, .expects_err(expected_rd_err));
219172
assert(mem_wo_inst.mem[0] == 'hC9);
220173

174+
// External rf;
175+
addr = 'h40;
176+
expected_rd_err = 'h0;
177+
expected_wr_err = 'h0;
178+
cpuif.assert_read(addr, 'h0, .expects_err(expected_rd_err));
179+
cpuif.write(addr, 'hD0, .expects_err(expected_wr_err));
180+
cpuif.assert_read(addr, 'hD0, .expects_err(expected_rd_err));
221181
{% endblock %}

0 commit comments

Comments
 (0)