Skip to content

Commit ec90994

Browse files
authored
Update RTE to support easy emulation of instructions (#673)
2 parents 7a98239 + 7ab61f4 commit ec90994

File tree

8 files changed

+370
-15
lines changed

8 files changed

+370
-15
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12
3232

3333
| Date (*dd.mm.yyyy*) | Version | Comment |
3434
|:-------------------:|:-------:|:--------|
35+
| 19.08.2023 | 1.8.8.1 | update RTE to support easy emulation of instructions; add example program to showcase how to emulate unaligned memory accesses; [#673](https://github.com/stnolting/neorv32/pull/673) |
3536
| 18.08.2023 | [**:rocket:1.8.8**](https://github.com/stnolting/neorv32/releases/tag/v1.8.8) | **New release** |
3637
| 17.08.2023 | 1.8.7.9 | minor rtl edits and cleanups; [#672](https://github.com/stnolting/neorv32/pull/672) |
3738
| 13.08.2023 | 1.8.7.8 | :warning: constrain/optimize `mtval` and `mcounteren` CSRs; [#671](https://github.com/stnolting/neorv32/pull/671) |

docs/datasheet/cpu.adoc

+4-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ recommended that the trap handler software provides a means of accessing the pla
4444
[IMPORTANT]
4545
The CPU does not support resolving unaligned memory access by the hardware (this is not a
4646
RISC-V-incompatibility issue but an important thing to know!). Any kind of unaligned memory access
47-
will raise an exception to allow a _software-based_ emulation provided by the application.
47+
will raise an exception to allow a _software-based_ emulation provided by the application. However, unaligned memory
48+
access can be **emulated** using the NEORV32 runtime environment. See section <<_application_context_handling>>
49+
for more information.
4850

4951
.No Atomic Read-Modify-Write Operations
5052
[IMPORTANT]
@@ -128,6 +130,7 @@ effect maximal operation frequency.
128130
[WARNING]
129131
The CPU does not support a hardware-based handling of unaligned memory accesses! Any unaligned access will raise a bus load/store unaligned
130132
address exception. The exception handler can be used to _emulate_ unaligned memory accesses in software.
133+
See the NEORV32 Runtime Environment's <<_application_context_handling>> section for more information.
131134

132135

133136
:sectnums:

docs/datasheet/software_rte.adoc

+32
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,35 @@ obtained from the <<_mcause>> CSR (see <<_neorv32_trap_listing>>). A full list o
212212
| "Fast IRQ 0x0000000f" | `0x8000001f`
213213
| "Unknown trap cause" | undefined
214214
|=======================
215+
216+
217+
==== Application Context Handling
218+
219+
Upon trap entry the RTE backups the _entire_ application context (i.e. all `x` general purpose registers)
220+
to the stack. The context is restored automatically after trap completion. The base address of the according
221+
stack frame is copied to the <<_mscratch>> CSR. By having this information available, the RTE provides dedicated
222+
functions for accessing and _altering_ the application context:
223+
224+
.Context Access Functions
225+
[source,c]
226+
----
227+
// Prototypes
228+
uint32_t neorv32_rte_context_get(int x); // read register x
229+
void neorv32_rte_context_put(int x, uint32_t data); write data to register x
230+
231+
// Examples
232+
uint32_t tmp = neorv32_rte_context_get(9); // read register 'x9'
233+
neorv32_rte_context_put(28, tmp); // write 'tmp' to register 'x28'
234+
----
235+
236+
.RISC-V `E` Extension
237+
[NOTE]
238+
Registers `x16..x31` are not available if the RISC-V <<_e_isa_extension>> is enabled.
239+
240+
The context access functions can be used by application-specific trap handlers to emulate unsupported
241+
CPU / SoC features like unimplemented IO modules, unsupported instructions and even unaligned memory accesses.
242+
243+
.Demo Program: Emulate Unaligned Memory Access
244+
[TIP]
245+
A demo program, which showcases how to emulate unaligned memory accesses using the NEORV32 runtime environment
246+
can be found in `sw/example/demo_emulate_unaligned`.

rtl/core/neorv32_package.vhd

+1-1
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"01080800"; -- hardware version
59+
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080801"; -- 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

+196
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
// #################################################################################################
2+
// # << NEORV32 - Demo program for emulating unaligned memory accesses using the NEORV32 RTE >> #
3+
// # ********************************************************************************************* #
4+
// # BSD 3-Clause License #
5+
// # #
6+
// # Copyright (c) 2023, Stephan Nolting. All rights reserved. #
7+
// # #
8+
// # Redistribution and use in source and binary forms, with or without modification, are #
9+
// # permitted provided that the following conditions are met: #
10+
// # #
11+
// # 1. Redistributions of source code must retain the above copyright notice, this list of #
12+
// # conditions and the following disclaimer. #
13+
// # #
14+
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of #
15+
// # conditions and the following disclaimer in the documentation and/or other materials #
16+
// # provided with the distribution. #
17+
// # #
18+
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to #
19+
// # endorse or promote products derived from this software without specific prior written #
20+
// # permission. #
21+
// # #
22+
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS #
23+
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF #
24+
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE #
25+
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #
26+
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
27+
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED #
28+
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING #
29+
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED #
30+
// # OF THE POSSIBILITY OF SUCH DAMAGE. #
31+
// # ********************************************************************************************* #
32+
// # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
33+
// #################################################################################################
34+
35+
36+
/**********************************************************************//**
37+
* @file demo_emulate_unaligned/main.c
38+
* @author Stephan Nolting
39+
* @brief Demo program for emulating unaligned memory accesses using the NEORV32
40+
* run-time environment (RTE).
41+
**************************************************************************/
42+
43+
#include <neorv32.h>
44+
45+
46+
/**********************************************************************//**
47+
* @name User configuration
48+
**************************************************************************/
49+
/**@{*/
50+
/** UART BAUD rate */
51+
#define BAUD_RATE 19200
52+
/**@}*/
53+
54+
55+
/**********************************************************************//**
56+
* @name Global variables
57+
**************************************************************************/
58+
volatile uint32_t data_block[2];
59+
60+
61+
/**********************************************************************//**
62+
* Emulate unaligned load-word operation
63+
*
64+
* @note This is a RTE "second-level" trap handler.
65+
*
66+
* @warning Compressed load instructions are not supported here!
67+
**************************************************************************/
68+
void trap_handler_emulate_unaligned_lw(void) {
69+
70+
uint32_t mepc = neorv32_cpu_csr_read(CSR_MEPC);
71+
72+
// this function assumes that the exception is raised by an UNCOMPRESSED load operation
73+
uint32_t inst = neorv32_cpu_load_unsigned_word(mepc);
74+
75+
// decompose I-type instruction
76+
uint32_t opcode = (inst >> 0) & 0x007;
77+
uint32_t funct3 = (inst >> 12) & 0x003;
78+
uint32_t rs1_addr = (inst >> 15) & 0x01f;
79+
uint32_t rd_addr = (inst >> 7) & 0x01f;
80+
uint32_t imm12 = (inst >> 20) & 0xfff;
81+
82+
// check if the trap-causing instruction is 'lw' instruction
83+
if ((opcode == 0b0000011) && (funct3 == 0b010)) {
84+
85+
// neorv32_uart0_printf("\n<< emulating 'lw x%u, %i(x%u)' >>\n", rd_addr, imm12, rs1_addr);
86+
87+
// get operands from main's context
88+
uint32_t rs1 = neorv32_rte_context_get(rs1_addr);
89+
90+
// emulated function
91+
uint32_t addr = rs1 + imm12;
92+
uint32_t b0 = (uint32_t)neorv32_cpu_load_unsigned_byte(addr + 0);
93+
uint32_t b1 = (uint32_t)neorv32_cpu_load_unsigned_byte(addr + 1);
94+
uint32_t b2 = (uint32_t)neorv32_cpu_load_unsigned_byte(addr + 2);
95+
uint32_t b3 = (uint32_t)neorv32_cpu_load_unsigned_byte(addr + 3);
96+
uint32_t rd = (b3 << 24) | (b2 << 16) | (b1 << 8) | (b0 << 0);
97+
98+
// write result back to main's context
99+
neorv32_rte_context_put(rd_addr, rd);
100+
101+
}
102+
}
103+
104+
105+
/**********************************************************************//**
106+
* Load 32-bit data from memory. This wrapper function is used to ensure the emitted
107+
* load instruction is UNCOMPRESSED.
108+
*
109+
* @param[in] addr Address (32-bit).
110+
* @return Read data word (32-bit).
111+
**************************************************************************/
112+
uint32_t lw32(uint32_t addr) {
113+
114+
uint32_t reg_addr = addr;
115+
uint32_t reg_data;
116+
117+
asm volatile (
118+
".option push \n"
119+
".option norvc \n" // make sure this emits uncompressed code
120+
"lw %[da], 0(%[ad]) \n"
121+
".option pop \n"
122+
: [da] "=r" (reg_data) : [ad] "r" (reg_addr)
123+
);
124+
125+
return reg_data;
126+
}
127+
128+
129+
/**********************************************************************//**
130+
* Demo program to showcase RTE-based emulation of unaligned memory accesses.
131+
*
132+
* @return Irrelevant.
133+
**************************************************************************/
134+
int main() {
135+
136+
uint32_t addr, data;
137+
138+
// setup NEORV32 runtime environment
139+
neorv32_rte_setup();
140+
141+
// setup UART at default baud rate, no interrupts
142+
neorv32_uart0_setup(BAUD_RATE, 0);
143+
144+
// intro
145+
neorv32_uart0_printf("\n<<< Demo: Emulation of Unaligned Memory Accesses >>>\n");
146+
147+
// show source data block
148+
data_block[0] = 0x00112233;
149+
data_block[1] = 0x44556677;
150+
neorv32_uart0_printf("\nSource data:\n");
151+
neorv32_uart0_printf("MEM[0x%x] = 0x%x\n", (uint32_t)&data_block[0], data_block[0]);
152+
neorv32_uart0_printf("MEM[0x%x] = 0x%x\n", (uint32_t)&data_block[1], data_block[1]);
153+
154+
155+
// ------------------------------------------
156+
// Without emulation: RTE debug handler will show an error
157+
// ------------------------------------------
158+
neorv32_uart0_printf("\nUnaligned load without emulation:\n");
159+
160+
addr = ((uint32_t)&data_block[0]) + 1; // = unaligned address
161+
neorv32_uart0_printf("MEM[0x%x] = ", addr);
162+
163+
data = lw32(addr); // this will raise an exception
164+
165+
if (data == 0x77001122) {
166+
neorv32_uart0_printf("0x%x [ok]\n", data);
167+
}
168+
else {
169+
neorv32_uart0_printf("[FAILED]\n");
170+
}
171+
172+
173+
// ------------------------------------------
174+
// With emulation: operation is handled by trap_handler_emulate_unaligned_lw
175+
// ------------------------------------------
176+
neorv32_uart0_printf("\nUnaligned load with emulation:\n");
177+
178+
// install trap handler for "unaligned load address" exception
179+
neorv32_rte_handler_install(RTE_TRAP_L_MISALIGNED, trap_handler_emulate_unaligned_lw);
180+
181+
addr = ((uint32_t)&data_block[0]) + 1; // = unaligned address
182+
neorv32_uart0_printf("MEM[0x%x] = ", addr);
183+
184+
data = lw32(addr); // this will raise an exception
185+
186+
if (data == 0x77001122) {
187+
neorv32_uart0_printf("0x%x [ok]\n", data);
188+
}
189+
else {
190+
neorv32_uart0_printf("[FAILED]\n");
191+
}
192+
193+
194+
neorv32_uart0_printf("\nProgram completed.\n");
195+
return 0;
196+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
2+
NEORV32_HOME ?= ../../..
3+
4+
include $(NEORV32_HOME)/sw/common/common.mk

sw/lib/include/neorv32_rte.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,11 @@ enum NEORV32_RTE_TRAP_enum {
8888
* @name Prototypes
8989
**************************************************************************/
9090
/**@{*/
91-
void neorv32_rte_setup(void);
92-
int neorv32_rte_handler_install(int id, void (*handler)(void));
93-
int neorv32_rte_handler_uninstall(int id);
91+
void neorv32_rte_setup(void);
92+
int neorv32_rte_handler_install(int id, void (*handler)(void));
93+
int neorv32_rte_handler_uninstall(int id);
94+
uint32_t neorv32_rte_context_get(int x);
95+
void neorv32_rte_context_put(int x, uint32_t data);
9496

9597
void neorv32_rte_print_hw_config(void);
9698
void neorv32_rte_print_hw_version(void);

0 commit comments

Comments
 (0)