Skip to content

Commit 1d5e198

Browse files
authored
🐛 fixing some LR/SC design flaws (#654)
2 parents 984e815 + 01c410c commit 1d5e198

File tree

7 files changed

+140
-69
lines changed

7 files changed

+140
-69
lines changed

CHANGELOG.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
## Project Change Log
22

3-
The most recent version of the **NEORV32** project can be found at the top of this list.
4-
"Stable releases" are linked and highlighted :rocket:. The latest release is
3+
The most recent version of the project can be found at the top of this list.
4+
Releases are linked and highlighted. The latest release is
55
[![release](https://img.shields.io/github/v/release/stnolting/neorv32)](https://github.com/stnolting/neorv32/releases).
66
A list of all releases can be found [here](https://github.com/stnolting/neorv32/releases).
77

@@ -10,14 +10,13 @@ The _version identifier_ uses an additional **custom** element (`MAJOR.MINOR.PAT
1010
to track _individual_ changes. The identifier number is incremented with every core RTL
1111
modification and also by major framework modifications.
1212

13-
The version number is globally defined by the `hw_version_c` constant in the main VHDL
13+
The version identifier is globally defined by the `hw_version_c` constant in the main VHDL
1414
[package file](https://github.com/stnolting/neorv32/blob/main/rtl/core/neorv32_package.vhd).
15-
The processor can determine this version by reading the RISC-V-compatible `mimpid` CSR.
16-
A 8x4-bit BCD representation is used. Examples:
15+
Software can determine this version by reading the RISC-V-compatible `mimpid` CSR, which uses
16+
a 8x4-bit BCD (binary-coded decimal) representation. Example:
1717

1818
```
19-
mimpid = 0x01040312 => Version 01.04.03.12 => v1.4.3.12
20-
mimpid = 0x01080200 => Version 01.08.02.00 => v1.8.2
19+
mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12
2120
```
2221

2322

@@ -33,6 +32,7 @@ mimpid = 0x01080200 => Version 01.08.02.00 => v1.8.2
3332

3433
| Date (*dd.mm.yyyy*) | Version | Comment |
3534
|:-------------------:|:-------:|:--------|
35+
| 24.07.2023 | 1.8.6.10 | :bug: fixing some LR/SC design flaws; [#654](https://github.com/stnolting/neorv32/pull/654) |
3636
| 23.07.2023 | 1.8.6.9 | optimize bus system and customization options; [#653](https://github.com/stnolting/neorv32/pull/653) |
3737
| 22.07.2023 | 1.8.6.8 | minor rtl edits; [#652](https://github.com/stnolting/neorv32/pull/652) |
3838
| 21.07.2023 | 1.8.6.7 | :sparkles: add support for **RISC-V A ISA Extension** (atomic memory accesses; `lr.w`/`sc.w` only!); [#651](https://github.com/stnolting/neorv32/pull/651) |

docs/datasheet/cpu.adoc

+17-7
Original file line numberDiff line numberDiff line change
@@ -326,15 +326,20 @@ instruction stores a word to a word-aligned address only if the reservation set
326326
is executed or if any write access to the _reservated_ address takes place. Traps and/or CPU privilege level changes
327327
do not modify current reservation sets.
328328

329+
.`aq` and `rl` Bits
330+
[NOTE]
331+
The instruction word's `aq` and `lr` memory ordering bits are not evaluated by the hardware at all.
332+
329333
.Atomic Memory Access on Hardware Level
330334
[NOTE]
331335
More information regarding the atomic memory accesses and the according reservation
332336
sets can be found in section <<_reservation_set_controller>>.
333337

334-
.LR/SC Bus Protocol
335-
[NOTE]
336-
More details regarding the LR/SC instruction's bus transactions can be found in section
337-
<<_bus_interface>> / <<_atomic_accesses>>.
338+
.Cache Coherency
339+
[IMPORTANT]
340+
Atomic operations **always bypass** the cache using direct/uncached accesses. Care must be taken
341+
to maintain data cache coherency (e.g. by using the `fence` instruction).
342+
338343

339344

340345
==== `I` ISA Extension
@@ -356,7 +361,12 @@ The `I` ISA extensions is the base RISC-V integer ISA that is always enabled.
356361
| Illegal inst. | - | 3
357362
|=======================
358363

359-
.`fence` Instruction
364+
.`fence` Instruction - Predecessor and Successor Bits
365+
[NOTE]
366+
The `fence` instruction word's _predecessor_ and _successor_ bits (used for memory ordering) are not evaluated
367+
by the hardware at all.
368+
369+
.`fence` Instruction - How it works
360370
[NOTE]
361371
CPU-internally, the `fence` instruction does not perform any operation inside the CPU. It only sets the
362372
top's `d_bus_fence_o` signal high for one cycle to inform the memory system a `fence` instruction has been
@@ -813,7 +823,7 @@ is driven by the _accessed_ device or bus system (i.e. a processor-internal memo
813823
| `ben` | 4 | Byte-enable for each byte in `data`
814824
| `we` | 1 | **Write** request trigger (single-shot)
815825
| `re` | 1 | **Read** request trigger (single-shot)
816-
| `src` | 1 | Access source (`0` = instruction fetch, `1` = data access)
826+
| `src` | 1 | Access source (`0` = instruction fetch, `1` = load/store)
817827
| `priv` | 1 | Set if privileged (M-mode) access
818828
| `rvso` | 1 | Set if current access is a reservation-set operation (atomic `lr` or `sc` instruction)
819829
|=======================
@@ -848,7 +858,7 @@ The figure below shows three exemplary bus accesses:
848858

849859
[start=1]
850860
. A read access to address `A_addr` returning `rdata` after several cycles (slow response; `ACK` arrives after several cycles).
851-
. A word-wide write access to address `B_addr` writing `wdata` (fast response; `ACK` arrives right in the next cycle).
861+
. A write access to address `B_addr` writing `wdata` (fastest response; `ACK` arrives right in the next cycle).
852862
. A failing read access to address `C_addr` (slow response; `ERR` arrives after several cycles).
853863

854864
.Three Exemplary Bus Transactions

docs/datasheet/soc.adoc

+21-15
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,6 @@ monitor starts an internal timer. The accessed module has to respond ("ACK") to
525525
.Internal Bus Timeout Configuration
526526
[source,vhdl]
527527
----
528-
-- "response time window" for processor-internal modules --
529-
-- = cycles after which an *unacknowledged* internal bus access will timeout and trigger a bus fault exception
530528
constant max_proc_int_response_time_c : natural := 15; -- default = 15
531529
----
532530

@@ -550,20 +548,28 @@ explicit specific processor generic. See section <<_processor_external_memory_in
550548
==== Reservation Set Controller
551549

552550
The reservation set controller is responsible for handling the load-reservate and store-conditional bus transaction that
553-
are triggered by the `lr.w` and `sc.w` instructions from the CPU's <<_a_isa_extension>>.
551+
are triggered by the `lr.w` (LR) and `sc.w` (SC) instructions from the CPU's <<_a_isa_extension>>.
554552

555553
A "reservation" defines an address or address range that provides a guarding mechanism to support atomic accesses. A new
556-
reservation is registered by the `lr.w` instruction. The address provided by this instruction defines the memory location
557-
that is now monitored for atomic accesses. The according `sc.w` instruction evaluates the state of this reservation. If
558-
the reservation is still valid the write access triggered by the `sc.w` instruction is finally executed and the instruction
559-
return a "success" state. If the reservation has been invalidated the `sc.w` instructions write access does not take place
560-
and the instruction returns a "failed" state.
554+
reservation is registered by the LR instruction. The address provided by this instruction defines the memory location
555+
that is now monitored for atomic accesses. The according SC instruction evaluates the state of this reservation. If
556+
the reservation is still valid the write access triggered by the SC instruction is finally executed and the instruction
557+
return a "success" state (`rd` = 0). If the reservation has been invalidated the SC instruction will not write to memory
558+
and will return a "failed" state (`rd` = 1).
561559

562560
The reservation is invalidated if...
563561

564-
* ... another `lr.w` instruction is executed.
565-
* ... a normal store access to the reservated address takes place (by the CPU or by the DMA).
566-
* ... a hardware reset is triggered.
562+
* an SC instruction is executed that accesses an address **outside** of the reservation set of the previous LR instruction.
563+
This SC instruction will **fail** (not writing to memory).
564+
* an SC instruction is executed that accesses an address **inside** of the reservation set of the previous LR instruction.
565+
This SC instruction will **succeed** (finally writing to memory).
566+
* a normal store operation accesses an address **inside** of the current reservation set (by the CPU or by the DMA).
567+
* a hardware reset is triggered.
568+
569+
.Consecutive LR Instructions
570+
[NOTE]
571+
If an LR instruction is followed by another LR instruction the reservation set of the former one is overridden
572+
by the reservation set of the latter one.
567573

568574
.Bus Access Errors
569575
[IMPORTANT]
@@ -587,19 +593,19 @@ that the size of the address region has to be a power of two.
587593
The reservation set can be set for _any_ address (only constrained by the configured granularity). This also
588594
includes cached memory, memory-mapped IO devices and processor-external address spaces.
589595

590-
Bus transactions triggered by the `lr.w` instruction register a new reservation set and are delegated to the adressed
591-
memory/device. Bus transactions triggered by the `sc.w` remove a reservation set and are forwarded to the adressed
596+
Bus transactions triggered by the LR instruction register a new reservation set and are delegated to the adressed
597+
memory/device. Bus transactions triggered by the SC remove a reservation set and are forwarded to the adressed
592598
memory/device only if the SC operations succeeds. Otherwise, the access request is not forwarded and a local ACK is
593599
generated to terminate the bus transaction.
594600

595601
.LR/SC Bus Protocol
596602
[NOTE]
597-
More information regarding the /LR/SC bus transactions and the the according protocol can be found in section
603+
More information regarding the LR/SC bus transactions and the the according protocol can be found in section
598604
<<_bus_interface>> / <<_atomic_accesses>>.
599605

600606
.Cache Coherency
601607
[IMPORTANT]
602-
Atomic operations **always bypass** the cache using direct/uncached accesses. HEnce, care must be taken
608+
Atomic operations **always bypass** the cache using direct/uncached accesses. Care must be taken
603609
to maintain data cache coherency (e.g. by using the `fence` instruction).
604610

605611

rtl/core/neorv32_intercon.vhd

+18-4
Original file line numberDiff line numberDiff line change
@@ -920,22 +920,36 @@ begin
920920
case rsvs.state is
921921

922922
when "10" => -- active reservation: wait for condition to invalidate reservation
923-
if (rvs_clear_i = '1') then -- external clear request
923+
-- --------------------------------------------------------------------
924+
if (core_req_i.re = '1') and (core_req_i.rvso = '1') then -- another LR instruction overriding the current reservation
925+
rsvs.addr <= core_req_i.addr(31 downto abb_c);
926+
end if;
927+
--
928+
if (rvs_clear_i = '1') then -- external clear request (highest priority!)
924929
rsvs.state <= "00"; -- invalidate reservation
925-
elsif (core_req_i.we = '1') then
930+
elsif (core_req_i.we = '1') then -- write access
931+
926932
if (core_req_i.rvso = '1') then -- store-conditional instruction
927-
rsvs.state <= "11";
928-
elsif (rsvs.match = '1') then -- store to reservated address
933+
if (rsvs.match = '1') then -- SC to reservated address
934+
rsvs.state <= "11"; -- execute SC instruction (reservation still valid)
935+
else -- SC to any other address (new reservation attempt while the current one is still valid)
936+
rsvs.state <= "00"; -- invalidate reservation
937+
end if;
938+
939+
elsif (rsvs.match = '1') then -- normal write to reservated address
929940
rsvs.state <= "00"; -- invalidate reservation
930941
end if;
942+
931943
end if;
932944

933945
when "11" => -- active reservation: invalidate reservation at the end of bus access
946+
-- --------------------------------------------------------------------
934947
if (sys_rsp_i.ack = '1') or (sys_rsp_i.err = '1') then
935948
rsvs.state <= "00";
936949
end if;
937950

938951
when others => -- "0-" no active reservation: wait for for new registration request
952+
-- --------------------------------------------------------------------
939953
if (core_req_i.re = '1') and (core_req_i.rvso = '1') then -- load-reservate instruction
940954
rsvs.addr <= core_req_i.addr(31 downto abb_c);
941955
rsvs.state <= "10";

rtl/core/neorv32_package.vhd

+26-26
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ package neorv32_package is
5656

5757
-- Architecture Constants -----------------------------------------------------------------
5858
-- -------------------------------------------------------------------------------------------
59-
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080609"; -- hardware version
59+
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080610"; -- hardware version
6060
constant archid_c : natural := 19; -- official RISC-V architecture ID
6161
constant XLEN : natural := 32; -- native data path width, do not change!
6262

@@ -93,17 +93,17 @@ package neorv32_package is
9393

9494
-- IO Address Map --
9595
constant iodev_size_c : natural := 256; -- size of a single IO device (bytes)
96-
--constant base_res_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffe000"; -- reserved
97-
--constant base_res_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffe100"; -- reserved
98-
--constant base_res_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffe200"; -- reserved
99-
--constant base_res_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffe300"; -- reserved
100-
--constant base_res_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffe400"; -- reserved
101-
--constant base_res_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffe500"; -- reserved
102-
--constant base_res_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffe600"; -- reserved
103-
--constant base_res_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffe700"; -- reserved
104-
--constant base_res_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffe800"; -- reserved
105-
--constant base_res_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffe900"; -- reserved
106-
--constant base_res_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffea00"; -- reserved
96+
--constant base_???_c : std_ulogic_vector(31 downto 0) := x"ffffe000"; -- reserved
97+
--constant base_???_c : std_ulogic_vector(31 downto 0) := x"ffffe100"; -- reserved
98+
--constant base_???_c : std_ulogic_vector(31 downto 0) := x"ffffe200"; -- reserved
99+
--constant base_???_c : std_ulogic_vector(31 downto 0) := x"ffffe300"; -- reserved
100+
--constant base_???_c : std_ulogic_vector(31 downto 0) := x"ffffe400"; -- reserved
101+
--constant base_???_c : std_ulogic_vector(31 downto 0) := x"ffffe500"; -- reserved
102+
--constant base_???_c : std_ulogic_vector(31 downto 0) := x"ffffe600"; -- reserved
103+
--constant base_???_c : std_ulogic_vector(31 downto 0) := x"ffffe700"; -- reserved
104+
--constant base_???_c : std_ulogic_vector(31 downto 0) := x"ffffe800"; -- reserved
105+
--constant base_???_c : std_ulogic_vector(31 downto 0) := x"ffffe900"; -- reserved
106+
--constant base_???_c : std_ulogic_vector(31 downto 0) := x"ffffea00"; -- reserved
107107
constant base_io_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffeb00";
108108
constant base_io_slink_c : std_ulogic_vector(31 downto 0) := x"ffffec00";
109109
constant base_io_dma_c : std_ulogic_vector(31 downto 0) := x"ffffed00";
@@ -126,7 +126,7 @@ package neorv32_package is
126126
constant base_io_sysinfo_c : std_ulogic_vector(31 downto 0) := x"fffffe00";
127127
constant base_io_dm_c : std_ulogic_vector(31 downto 0) := x"ffffff00";
128128

129-
-- OCD Debug Module Entry Points --
129+
-- On-Chip Debugger - Debug Module Entry Points (Code ROM) --
130130
constant dm_exc_entry_c : std_ulogic_vector(31 downto 0) := x"ffffff00"; -- = base_io_dm_c + 0, exceptions entry point
131131
constant dm_park_entry_c : std_ulogic_vector(31 downto 0) := x"ffffff08"; -- = base_io_dm_c + 8, normal entry point
132132

@@ -1076,7 +1076,7 @@ package body neorv32_package is
10761076
if (2**i >= input) then
10771077
return i;
10781078
end if;
1079-
end loop; -- i
1079+
end loop;
10801080
return 0;
10811081
end function index_size_f;
10821082

@@ -1143,7 +1143,7 @@ package body neorv32_package is
11431143
tmp_v(input'length-1) := input(input'length-1); -- keep MSB
11441144
for i in input'length-2 downto 0 loop
11451145
tmp_v(i) := input(i) xor input(i+1);
1146-
end loop; -- i
1146+
end loop;
11471147
return tmp_v;
11481148
end function bin_to_gray_f;
11491149

@@ -1155,7 +1155,7 @@ package body neorv32_package is
11551155
tmp_v(input'length-1) := input(input'length-1); -- keep MSB
11561156
for i in input'length-2 downto 0 loop
11571157
tmp_v(i) := tmp_v(i+1) xor input(i);
1158-
end loop; -- i
1158+
end loop;
11591159
return tmp_v;
11601160
end function gray_to_bin_f;
11611161

@@ -1167,7 +1167,7 @@ package body neorv32_package is
11671167
tmp_v := '0';
11681168
for i in a'range loop
11691169
tmp_v := tmp_v or a(i);
1170-
end loop; -- i
1170+
end loop;
11711171
return tmp_v;
11721172
end function or_reduce_f;
11731173

@@ -1179,7 +1179,7 @@ package body neorv32_package is
11791179
tmp_v := '1';
11801180
for i in a'range loop
11811181
tmp_v := tmp_v and a(i);
1182-
end loop; -- i
1182+
end loop;
11831183
return tmp_v;
11841184
end function and_reduce_f;
11851185

@@ -1191,7 +1191,7 @@ package body neorv32_package is
11911191
tmp_v := '0';
11921192
for i in a'range loop
11931193
tmp_v := tmp_v xor a(i);
1194-
end loop; -- i
1194+
end loop;
11951195
return tmp_v;
11961196
end function xor_reduce_f;
11971197

@@ -1233,7 +1233,7 @@ package body neorv32_package is
12331233
for i in 0 to 7 loop
12341234
hex_v := tmp_v(i*4+3 downto i*4+0);
12351235
res_v(i+1) := to_hexchar_f(bit_rev_f(hex_v));
1236-
end loop; -- i
1236+
end loop;
12371237
return res_v;
12381238
end function to_hstring32_f;
12391239

@@ -1244,7 +1244,7 @@ package body neorv32_package is
12441244
begin
12451245
for i in 0 to input'length-1 loop
12461246
output_v(input'length-i-1) := input(i);
1247-
end loop; -- i
1247+
end loop;
12481248
return output_v;
12491249
end function bit_rev_f;
12501250

@@ -1289,7 +1289,7 @@ package body neorv32_package is
12891289
if (input(i) = '1') then
12901290
cnt_v := cnt_v + 1;
12911291
end if;
1292-
end loop; -- i
1292+
end loop;
12931293
return cnt_v;
12941294
end function popcount_f;
12951295

@@ -1305,7 +1305,7 @@ package body neorv32_package is
13051305
else
13061306
exit;
13071307
end if;
1308-
end loop; -- i
1308+
end loop;
13091309
return cnt_v;
13101310
end function leading_zeros_f;
13111311

@@ -1319,9 +1319,9 @@ package body neorv32_package is
13191319
if (init'length > depth) then
13201320
return mem_v;
13211321
end if;
1322-
for idx_v in 0 to init'length-1 loop -- init only in range of source data array
1323-
mem_v(idx_v) := init(idx_v);
1324-
end loop; -- idx_v
1322+
for i in 0 to init'length-1 loop -- init only in range of source data array
1323+
mem_v(i) := init(i);
1324+
end loop;
13251325
return mem_v;
13261326
end function mem32_init_f;
13271327

0 commit comments

Comments
 (0)