Add uvm32_useBreak(uvmst, bool) function to enable ebreak handling.

This is used in host-gdbstub to enable the functionality.

This allows the stackoverflow test to continue working. Meter test modified to handle new evt type.
This commit is contained in:
Toby Jaffey 2026-04-16 10:51:08 +01:00
parent faecd6bbef
commit a72737b228
4 changed files with 18 additions and 7 deletions

View file

@ -58,6 +58,7 @@ int main(int argc, char *argv[]) {
} }
uvm32_init(&vmst); uvm32_init(&vmst);
uvm32_useBreak(&vmst, true); // enable ebreak
if (!uvm32_load(&vmst, rom, romlen)) { if (!uvm32_load(&vmst, rom, romlen)) {
fprintf(stderr, "load failed!\n"); fprintf(stderr, "load failed!\n");

View file

@ -40,6 +40,8 @@ uint32_t metered_run(uint32_t num_instr) {
case UVM32_EVT_END: case UVM32_EVT_END:
TEST_ASSERT_EQUAL(0, 1); // trigger an assert, we didn't get to 100000 yet TEST_ASSERT_EQUAL(0, 1); // trigger an assert, we didn't get to 100000 yet
break; break;
case UVM32_EVT_BREAK:
break;
} }
} }

View file

@ -313,14 +313,15 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter)
setStatusErr(vmst, UVM32_ERR_MEM_WR); setStatusErr(vmst, UVM32_ERR_MEM_WR);
setup_err_evt(vmst, evt); setup_err_evt(vmst, evt);
break; break;
case 3: // ebreak default:
if (vmst->useBreak && ret == 3) { // ebreak
vmst->_ioevt.typ = UVM32_EVT_BREAK; vmst->_ioevt.typ = UVM32_EVT_BREAK;
setStatus(vmst, UVM32_STATUS_PAUSED); setStatus(vmst, UVM32_STATUS_PAUSED);
break; } else {
default:
// unhandled exception // unhandled exception
setStatusErr(vmst, UVM32_ERR_INTERNAL_CORE); setStatusErr(vmst, UVM32_ERR_INTERNAL_CORE);
setup_err_evt(vmst, evt); setup_err_evt(vmst, evt);
}
break; break;
} }
@ -351,6 +352,10 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter)
} }
} }
void uvm32_useBreak(uvm32_state_t *vmst, bool enabled) {
vmst->useBreak = enabled;
}
bool uvm32_hasEnded(const uvm32_state_t *vmst) { bool uvm32_hasEnded(const uvm32_state_t *vmst) {
return vmst->_status == UVM32_STATUS_ENDED; return vmst->_status == UVM32_STATUS_ENDED;
} }

View file

@ -151,6 +151,7 @@ typedef struct {
uint32_t _extramLen; /*! Length of external RAM */ uint32_t _extramLen; /*! Length of external RAM */
bool _extramDirty; /*! Flag to indicate VM code has modified extram since last run */ bool _extramDirty; /*! Flag to indicate VM code has modified extram since last run */
uint32_t garbage; /*! Used for returning valid pointer when operations fail */ uint32_t garbage; /*! Used for returning valid pointer when operations fail */
bool useBreak; /*! produce UVM32_EVT_BREAK */
} uvm32_state_t; } uvm32_state_t;
/*! Initialise a VM instance */ /*! Initialise a VM instance */
@ -196,6 +197,8 @@ uvm32_slice_t uvm32_arg_getslice(uvm32_state_t *vmst, uvm32_evt_t *evt, uvm32_ar
/*! Read a syscall argument pointer as a slice of known length */ /*! Read a syscall argument pointer as a slice of known length */
uvm32_slice_t uvm32_arg_getslice_fixed(uvm32_state_t *vmst, uvm32_evt_t *evt, uvm32_arg_t arg, uint32_t len); uvm32_slice_t uvm32_arg_getslice_fixed(uvm32_state_t *vmst, uvm32_evt_t *evt, uvm32_arg_t arg, uint32_t len);
/*! Allow ebreak in code, will generate UVM32_EVT_BREAK */
void uvm32_useBreak(uvm32_state_t *vmst, bool enabled);
/*! Setup a block of memory to act as external RAM, it will be available on in VM code at address `UVM32_EXTRAM_BASE`. The memory is not copied, so the caller must ensure it remains available until `uvm32_extram()` is called to setup a different region or the VM is ended. */ /*! Setup a block of memory to act as external RAM, it will be available on in VM code at address `UVM32_EXTRAM_BASE`. The memory is not copied, so the caller must ensure it remains available until `uvm32_extram()` is called to setup a different region or the VM is ended. */
void uvm32_extram(uvm32_state_t *vmst, uint8_t *extram, uint32_t len); void uvm32_extram(uvm32_state_t *vmst, uint8_t *extram, uint32_t len);