neorv32/sw/example/demo_emulate_unaligned/main.c

179 lines
7.9 KiB
C

// #################################################################################################
// # << NEORV32 - Demo program for emulating unaligned memory accesses using the NEORV32 RTE >> #
// # ********************************************************************************************* #
// # BSD 3-Clause License #
// # #
// # Copyright (c) 2023, Stephan Nolting. All rights reserved. #
// # #
// # Redistribution and use in source and binary forms, with or without modification, are #
// # permitted provided that the following conditions are met: #
// # #
// # 1. Redistributions of source code must retain the above copyright notice, this list of #
// # conditions and the following disclaimer. #
// # #
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of #
// # conditions and the following disclaimer in the documentation and/or other materials #
// # provided with the distribution. #
// # #
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to #
// # endorse or promote products derived from this software without specific prior written #
// # permission. #
// # #
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS #
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF #
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE #
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED #
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING #
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED #
// # OF THE POSSIBILITY OF SUCH DAMAGE. #
// # ********************************************************************************************* #
// # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
// #################################################################################################
/**********************************************************************//**
* @file demo_emulate_unaligned/main.c
* @author Stephan Nolting
* @brief Demo program for emulating unaligned memory accesses using the NEORV32
* run-time environment (RTE).
**************************************************************************/
#include <neorv32.h>
/**********************************************************************//**
* @name User configuration
**************************************************************************/
/**@{*/
/** UART BAUD rate */
#define BAUD_RATE 19200
/** Show debug info when 1 */
#define DEBUG_INFO 0
/**@}*/
/**********************************************************************//**
* @name Global variables
**************************************************************************/
volatile uint32_t data_block[2];
/**********************************************************************//**
* Emulate unaligned load-word operation
*
* @note This is a RTE "second-level" trap handler.
*
* @warning Compressed load instructions are not supported here!
**************************************************************************/
void trap_handler_emulate_unaligned_lw(void) {
uint32_t inst = neorv32_cpu_csr_read(CSR_MTINST);
// decompose I-type instruction
uint32_t opcode = (inst >> 0) & 0x07f;
uint32_t funct3 = (inst >> 12) & 0x003;
uint32_t rs1_addr = (inst >> 15) & 0x01f;
uint32_t rd_addr = (inst >> 7) & 0x01f;
uint32_t imm12 = (inst >> 20) & 0xfff;
// set opcode bit 1 as the instruction word might be transformed (de-compressed)
opcode |= 1 << 1;
// check if the trap-causing instruction is 'lw' instruction
if ((opcode == 0b0000011) && (funct3 == 0b010)) {
#if (DEBUG_INFO != 0)
neorv32_uart0_printf("\n<< emulating 'lw x%u, %i(x%u)' >>\n", rd_addr, imm12, rs1_addr);
#endif
// get operands from main's context
uint32_t rs1 = neorv32_rte_context_get(rs1_addr);
// emulated function
uint32_t addr = rs1 + imm12;
uint32_t b0 = (uint32_t)neorv32_cpu_load_unsigned_byte(addr + 0);
uint32_t b1 = (uint32_t)neorv32_cpu_load_unsigned_byte(addr + 1);
uint32_t b2 = (uint32_t)neorv32_cpu_load_unsigned_byte(addr + 2);
uint32_t b3 = (uint32_t)neorv32_cpu_load_unsigned_byte(addr + 3);
uint32_t rd = (b3 << 24) | (b2 << 16) | (b1 << 8) | (b0 << 0);
// write result back to main's context
neorv32_rte_context_put(rd_addr, rd);
}
}
/**********************************************************************//**
* Demo program to showcase RTE-based emulation of unaligned memory accesses.
*
* @return Irrelevant.
**************************************************************************/
int main() {
uint32_t addr, data;
// setup NEORV32 runtime environment
neorv32_rte_setup();
// setup UART at default baud rate, no interrupts
neorv32_uart0_setup(BAUD_RATE, 0);
// intro
neorv32_uart0_printf("\n<<< Demo: Emulation of Unaligned Memory Accesses >>>\n");
// show source data block
data_block[0] = 0x00112233;
data_block[1] = 0x44556677;
neorv32_uart0_printf("\nSource data:\n");
neorv32_uart0_printf("MEM[0x%x] = 0x%x\n", (uint32_t)&data_block[0], data_block[0]);
neorv32_uart0_printf("MEM[0x%x] = 0x%x\n", (uint32_t)&data_block[1], data_block[1]);
// ------------------------------------------
// Without emulation: RTE debug handler will show an error
// ------------------------------------------
neorv32_uart0_printf("\nUnaligned load without emulation:\n");
addr = ((uint32_t)&data_block[0]) + 1; // = unaligned address
neorv32_uart0_printf("MEM[0x%x] = ", addr);
// read from unaligned address
data = neorv32_cpu_load_unsigned_word(addr); // this will raise an exception
if (data == 0x77001122) {
neorv32_uart0_printf("0x%x [ok]\n", data);
}
else {
neorv32_uart0_printf("[FAILED]\n");
}
// ------------------------------------------
// With emulation: operation is handled by trap_handler_emulate_unaligned_lw
// ------------------------------------------
neorv32_uart0_printf("\nUnaligned load with emulation:\n");
// install trap handler for "unaligned load address" exception
neorv32_rte_handler_install(RTE_TRAP_L_MISALIGNED, trap_handler_emulate_unaligned_lw);
addr = ((uint32_t)&data_block[0]) + 1; // = unaligned address
neorv32_uart0_printf("MEM[0x%x] = ", addr);
// read from unaligned address
data = neorv32_cpu_load_unsigned_word(addr); // this will raise an exception
if (data == 0x77001122) {
neorv32_uart0_printf("0x%x [ok]\n", data);
}
else {
neorv32_uart0_printf("[FAILED]\n");
}
neorv32_uart0_printf("\nProgram completed.\n");
return 0;
}