From 7a1656ab10ad865a270fed94ff3d76ac311e386b Mon Sep 17 00:00:00 2001 From: Toby Jaffey Date: Thu, 11 Dec 2025 10:33:45 +0000 Subject: [PATCH] Handle 8, 16 and 32 bit accesses to extram. --- test/extram/rom/rom.c | 25 +++++++++-- test/extram/shared.h | 6 +++ test/extram/test/tests.c | 93 ++++++++++++++++++++++++++++++++++++++++ uvm32/uvm32.c | 43 +++++++++++++++++-- uvm32/uvm32.h | 8 ++-- 5 files changed, 163 insertions(+), 12 deletions(-) diff --git a/test/extram/rom/rom.c b/test/extram/rom/rom.c index bbd627f..9b8367e 100644 --- a/test/extram/rom/rom.c +++ b/test/extram/rom/rom.c @@ -13,19 +13,36 @@ void main(void) { } break; case TEST2: { uint32_t *p = (uint32_t *)UVM32_EXTRAM_BASE; - printdec(p[32]); // past the end + printdec(p[32]); // word read } break; case TEST3: { uint32_t *p = (uint32_t *)UVM32_EXTRAM_BASE; - p[32] = 1234; // past the end + p[32] = 1234; // past the end, out of bounds } break; case TEST4: { uint32_t *p = (uint32_t *)UVM32_EXTRAM_BASE; - p[0] = 1234; // good write + p[0] = 1234; // word write yield(0); } break; + case TEST5: { + uint8_t *p = (uint8_t *)UVM32_EXTRAM_BASE; + p[7] = 0xAB; // single byte write + yield(0); + } break; + case TEST6: { + uint8_t *p = (uint8_t *)UVM32_EXTRAM_BASE; + printdec(p[7]); // single byte read + } break; + case TEST7: { + uint16_t *p = (uint16_t *)UVM32_EXTRAM_BASE; + p[7] = 0xABCD; // short write + yield(0); + } break; + case TEST8: { + uint16_t *p = (uint16_t *)UVM32_EXTRAM_BASE; + printdec(p[7]); // short read + } break; } - } diff --git a/test/extram/shared.h b/test/extram/shared.h index 25f918c..f916cfe 100644 --- a/test/extram/shared.h +++ b/test/extram/shared.h @@ -6,5 +6,11 @@ enum { TEST2, TEST3, TEST4, + TEST5, + TEST6, + TEST7, + TEST8, + TEST9, + TEST10, }; diff --git a/test/extram/test/tests.c b/test/extram/test/tests.c index d961f7c..a045d15 100644 --- a/test/extram/test/tests.c +++ b/test/extram/test/tests.c @@ -97,3 +97,96 @@ void test_extram_out_of_bounds_dirty_flag(void) { TEST_ASSERT_EQUAL(false, uvm32_extramDirty(&vmst)); } +void test_extram_byte_write(void) { + // run the vm + uvm32_run(&vmst, &evt, 100); + TEST_ASSERT_EQUAL(false, uvm32_extramDirty(&vmst)); + + // check for picktest syscall + TEST_ASSERT_EQUAL(evt.typ, UVM32_EVT_SYSCALL); + TEST_ASSERT_EQUAL(evt.data.syscall.code, SYSCALL_PICKTEST); + uvm32_setval(&vmst, &evt, RET, TEST5); + + uvm32_run(&vmst, &evt, 100); + TEST_ASSERT_EQUAL(true, uvm32_extramDirty(&vmst)); + + // check that byte 7 only of extram has changed + uint8_t *p = (uint8_t *)extram; + for (int i=0;iextram != UVM32_NULL) { if (addr < vmst->extramLen) { - return ((uint32_t *)vmst->extram)[addr / 4]; + switch(accessTyp) { + case 0: + return ((int8_t *)vmst->extram)[addr]; + break; + case 1: + return ((int16_t *)vmst->extram)[addr/2]; + break; + case 2: + return ((uint32_t *)vmst->extram)[addr / 4]; + break; + case 4: + return ((uint8_t *)vmst->extram)[addr]; + break; + case 5: + return ((uint16_t *)vmst->extram)[addr/2]; + break; + default: + setStatusErr(vmst, UVM32_ERR_MEM_RD); + return 0; + break; + } } else { setStatusErr(vmst, UVM32_ERR_MEM_RD); } @@ -339,12 +361,25 @@ uint32_t uvm32_extramLoad(void *userdata, uint32_t addr) { return 0; } -uint32_t uvm32_extramStore(void *userdata, uint32_t addr, uint32_t val ) { +uint32_t uvm32_extramStore(void *userdata, uint32_t addr, uint32_t val, uint32_t accessTyp) { uvm32_state_t *vmst = (uvm32_state_t *)userdata; addr -= UVM32_EXTRAM_BASE; if (vmst->extram != UVM32_NULL) { if (addr < vmst->extramLen) { - ((uint32_t *)vmst->extram)[addr / 4] = val; + switch(accessTyp) { + case 0: + ((uint8_t *)vmst->extram)[addr] = val; + break; + case 1: + ((uint16_t *)vmst->extram)[addr/2] = val; + break; + case 2: + ((uint32_t *)vmst->extram)[addr/4] = val; + break; + default: + setStatusErr(vmst, UVM32_ERR_MEM_WR); + break; + } vmst->extramDirty = true; } else { setStatusErr(vmst, UVM32_ERR_MEM_WR); diff --git a/uvm32/uvm32.h b/uvm32/uvm32.h index 3b63f46..f0e7a52 100644 --- a/uvm32/uvm32.h +++ b/uvm32/uvm32.h @@ -55,10 +55,10 @@ typedef struct { #define MINIRV32_DECORATE static #define MINI_RV32_RAM_SIZE UVM32_MEMORY_SIZE #define MINIRV32_POSTEXEC(pc, ir, retval) {if (retval > 0) return retval;} -uint32_t uvm32_extramLoad(void *userdata, uint32_t addr); -uint32_t uvm32_extramStore(void *userdata, uint32_t addr, uint32_t val); -#define MINIRV32_HANDLE_MEM_LOAD_CONTROL( addy, rval ) rval = uvm32_extramLoad(userdata, addy); -#define MINIRV32_HANDLE_MEM_STORE_CONTROL( addy, val ) if( uvm32_extramStore(userdata, addy, val) ) return val; +uint32_t uvm32_extramLoad(void *userdata, uint32_t addr, uint32_t accessTyp); +uint32_t uvm32_extramStore(void *userdata, uint32_t addr, uint32_t val, uint32_t accessTyp); +#define MINIRV32_HANDLE_MEM_LOAD_CONTROL( addy, rval ) rval = uvm32_extramLoad(userdata, addy, ( ir >> 12 ) & 0x7); +#define MINIRV32_HANDLE_MEM_STORE_CONTROL( addy, val ) if( uvm32_extramStore(userdata, addy, val, ( ir >> 12 ) & 0x7) ) return val; #ifndef MINIRV32_IMPLEMENTATION #define MINIRV32_STEPPROTO