#include "tb_cxxrtl_io.h" #include "hazard3_csr.h" /*EXPECTED-OUTPUT*************************************************************** Entering test section mcause = 3 Offset into test: 0, 32-bit ebreak mcause = 3 Offset into test: 4, 16-bit ebreak mcause = 3 Offset into test: 6, 32-bit ebreak mcause = 3 Offset into test: 10, 16-bit ebreak Done *******************************************************************************/ // This is naked so we can take its address and get accurate offsets for the // breakpoints, which we can then check. Otherwise, we would have issues with // the size of the prologue potentially varying between builds etc. // // There is also a GCC extension for taking the address of a label, but GCC // takes artistic liberty in deciding where that label actually "is". void __attribute__((naked)) test() { asm volatile ( // Word-aligned word-sized ".option norvc\n" "ebreak\n" ".option rvc\n" // Word-aligned halfword-sized "c.ebreak\n" // Halfword-aligned word-sized ".option norvc\n" "ebreak\n" ".option rvc\n" // Halfword-aligned halfword-sized "c.ebreak\n" "ret\n" ); } int main() { tb_puts("Entering test section\n"); test(); tb_puts("Done\n"); } void __attribute__((interrupt)) handle_exception() { tb_printf("mcause = %u\n", read_csr(mcause)); tb_printf("Offset into test: %u, ", read_csr(mepc) - (uintptr_t)&test); if (*(uint16_t*)read_csr(mepc) & 0x3 == 0x3) { tb_puts("32-bit ebreak\n"); write_csr(mepc, read_csr(mepc) + 4); } else { tb_puts("16-bit ebreak\n"); write_csr(mepc, read_csr(mepc) + 2); } write_csr(mcause, 0); }