mirror of
https://github.com/ringtailsoftware/uvm32.git
synced 2026-06-05 22:43:39 +00:00
Make load and store use a packed union for safe alignment, rather than memcpy.
Remove some pointless initialisation which is already done through memset
This commit is contained in:
parent
17208a5112
commit
d04811a3c5
2 changed files with 39 additions and 65 deletions
|
|
@ -45,7 +45,7 @@ SOFTWARE.
|
||||||
|
|
||||||
#ifndef UVM32_MEMCPY
|
#ifndef UVM32_MEMCPY
|
||||||
#define UVM32_MEMCPY uvm32_memcpy
|
#define UVM32_MEMCPY uvm32_memcpy
|
||||||
void *uvm32_memcpy(void *dst, const void *src, size_t len) {
|
static inline void *uvm32_memcpy(void *dst, const void *src, size_t len) {
|
||||||
uint8_t *d = (uint8_t *)dst;
|
uint8_t *d = (uint8_t *)dst;
|
||||||
const uint8_t *s = (const uint8_t *)src;
|
const uint8_t *s = (const uint8_t *)src;
|
||||||
while(len--) {
|
while(len--) {
|
||||||
|
|
@ -57,7 +57,7 @@ void *uvm32_memcpy(void *dst, const void *src, size_t len) {
|
||||||
|
|
||||||
#ifndef UVM32_MEMSET
|
#ifndef UVM32_MEMSET
|
||||||
#define UVM32_MEMSET uvm32_memset
|
#define UVM32_MEMSET uvm32_memset
|
||||||
void *uvm32_memset(void *buf, int c, size_t len) {
|
static inline void *uvm32_memset(void *buf, int c, size_t len) {
|
||||||
uint8_t *b = (uint8_t *)buf;
|
uint8_t *b = (uint8_t *)buf;
|
||||||
while(len--) {
|
while(len--) {
|
||||||
*(b++) = c;
|
*(b++) = c;
|
||||||
|
|
@ -101,11 +101,12 @@ static void setStatusErr(uvm32_state_t *vmst, uvm32_err_t err) {
|
||||||
|
|
||||||
void uvm32_init(uvm32_state_t *vmst) {
|
void uvm32_init(uvm32_state_t *vmst) {
|
||||||
UVM32_MEMSET(vmst, 0x00, sizeof(uvm32_state_t));
|
UVM32_MEMSET(vmst, 0x00, sizeof(uvm32_state_t));
|
||||||
vmst->_status = UVM32_STATUS_PAUSED;
|
|
||||||
|
|
||||||
vmst->_extramLen = 0;
|
// handled by memset
|
||||||
vmst->_extram = (uint8_t *)NULL;
|
// vmst->_status = UVM32_STATUS_PAUSED;
|
||||||
vmst->_extramDirty = false;
|
// vmst->_extramLen = 0;
|
||||||
|
// vmst->_extram = (uint8_t *)NULL;
|
||||||
|
// vmst->_extramDirty = false;
|
||||||
|
|
||||||
vmst->_core.pc = MINIRV32_RAM_IMAGE_OFFSET;
|
vmst->_core.pc = MINIRV32_RAM_IMAGE_OFFSET;
|
||||||
// https://projectf.io/posts/riscv-cheat-sheet/
|
// https://projectf.io/posts/riscv-cheat-sheet/
|
||||||
|
|
@ -113,8 +114,9 @@ void uvm32_init(uvm32_state_t *vmst) {
|
||||||
// la sp, _sstack
|
// la sp, _sstack
|
||||||
// addi sp,sp,-16
|
// addi sp,sp,-16
|
||||||
vmst->_core.regs[2] = ((MINIRV32_RAM_IMAGE_OFFSET + UVM32_MEMORY_SIZE) & ~0xF) - 16; // 16 byte align stack
|
vmst->_core.regs[2] = ((MINIRV32_RAM_IMAGE_OFFSET + UVM32_MEMORY_SIZE) & ~0xF) - 16; // 16 byte align stack
|
||||||
vmst->_core.regs[10] = 0x00; //hart ID
|
// handled by memset
|
||||||
vmst->_core.regs[11] = 0;
|
// vmst->_core.regs[10] = 0x00; //hart ID
|
||||||
|
//vmst->_core.regs[11] = 0;
|
||||||
vmst->_core.extraflags |= 3; // Machine-mode.
|
vmst->_core.extraflags |= 3; // Machine-mode.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -411,6 +413,7 @@ uvm32_slice_t uvm32_arg_getslice_fixed(uvm32_state_t *vmst, uvm32_evt_t *evt, uv
|
||||||
static uint32_t _uvm32_extramLoad(void *userdata, uint32_t addr, uint32_t accessTyp) {
|
static uint32_t _uvm32_extramLoad(void *userdata, uint32_t addr, uint32_t accessTyp) {
|
||||||
uvm32_state_t *vmst = (uvm32_state_t *)userdata;
|
uvm32_state_t *vmst = (uvm32_state_t *)userdata;
|
||||||
addr -= UVM32_EXTRAM_BASE;
|
addr -= UVM32_EXTRAM_BASE;
|
||||||
|
const uvm32_val_t *v = ((uvm32_val_t *)(&((uint8_t *)vmst->_extram)[addr]));
|
||||||
|
|
||||||
if (vmst->_extram != NULL) {
|
if (vmst->_extram != NULL) {
|
||||||
if (addr < vmst->_extramLen) {
|
if (addr < vmst->_extramLen) {
|
||||||
|
|
@ -418,24 +421,23 @@ static uint32_t _uvm32_extramLoad(void *userdata, uint32_t addr, uint32_t access
|
||||||
// Any other value will have caused UVM32_ERR_INTERNAL_CORE
|
// Any other value will have caused UVM32_ERR_INTERNAL_CORE
|
||||||
switch(accessTyp) {
|
switch(accessTyp) {
|
||||||
case 0:
|
case 0:
|
||||||
return _uvm32_load1s(vmst->_extram, addr);
|
return v->i8;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
return _uvm32_load2s(vmst->_extram, addr);
|
return v->i16;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
return _uvm32_load4(vmst->_extram, addr);
|
return v->u32;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
return _uvm32_load2(vmst->_extram, addr);
|
return v->u16;
|
||||||
break;
|
break;
|
||||||
// have a default case to keep coverage check happy
|
// have a default case to keep coverage check happy
|
||||||
// no other values are possible here
|
// no other values are possible here
|
||||||
default: // fall through
|
default: // fall through
|
||||||
case 4:
|
case 4:
|
||||||
return _uvm32_load1(vmst->_extram, addr);
|
return v->u8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Out of bounds
|
// Out of bounds
|
||||||
|
|
@ -448,19 +450,21 @@ static uint32_t _uvm32_extramLoad(void *userdata, uint32_t addr, uint32_t access
|
||||||
static uint32_t _uvm32_extramStore(void *userdata, uint32_t addr, uint32_t val, uint32_t accessTyp) {
|
static uint32_t _uvm32_extramStore(void *userdata, uint32_t addr, uint32_t val, uint32_t accessTyp) {
|
||||||
uvm32_state_t *vmst = (uvm32_state_t *)userdata;
|
uvm32_state_t *vmst = (uvm32_state_t *)userdata;
|
||||||
addr -= UVM32_EXTRAM_BASE;
|
addr -= UVM32_EXTRAM_BASE;
|
||||||
|
uvm32_val_t *v = ((uvm32_val_t *)(&((uint8_t *)vmst->_extram)[addr]));
|
||||||
|
|
||||||
if (vmst->_extram != NULL) {
|
if (vmst->_extram != NULL) {
|
||||||
if (addr < vmst->_extramLen) {
|
if (addr < vmst->_extramLen) {
|
||||||
switch(accessTyp) {
|
switch(accessTyp) {
|
||||||
case 1:
|
case 1:
|
||||||
_uvm32_store2(vmst->_extram, addr, val);
|
v->u16 = val;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
_uvm32_store4(vmst->_extram, addr, val);
|
v->u32 = val;
|
||||||
break;
|
break;
|
||||||
// no other values are valid here and will be stopped above
|
// no other values are valid here and will be stopped above
|
||||||
default: // fall through
|
default: // fall through
|
||||||
case 0:
|
case 0:
|
||||||
_uvm32_store1(vmst->_extram, addr, val);
|
v->u8 = val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
vmst->_extramDirty = true;
|
vmst->_extramDirty = true;
|
||||||
|
|
@ -488,35 +492,4 @@ uint32_t uvm32_getProgramCounter(const uvm32_state_t *vmst) {
|
||||||
return vmst->_core.pc;
|
return vmst->_core.pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access of memory bus in alignment safe way
|
|
||||||
static void _uvm32_store4(void *p, uint32_t off, uint32_t val) {
|
|
||||||
UVM32_MEMCPY((uint8_t *)p + off, &val, 4);
|
|
||||||
}
|
|
||||||
static void _uvm32_store2(void *p, uint32_t off, uint16_t val) {
|
|
||||||
UVM32_MEMCPY((uint8_t *)p + off, &val, 2);
|
|
||||||
}
|
|
||||||
static void _uvm32_store1(void *p, uint32_t off, uint8_t val) {
|
|
||||||
((uint8_t *)p)[off] = val;
|
|
||||||
}
|
|
||||||
static uint32_t _uvm32_load4(void *p, uint32_t off) {
|
|
||||||
uint32_t v;
|
|
||||||
UVM32_MEMCPY(&v, (uint8_t *)p + off, 4);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
static uint16_t _uvm32_load2(void *p, uint32_t off) {
|
|
||||||
uint16_t v;
|
|
||||||
UVM32_MEMCPY(&v, (uint8_t *)p + off, 2);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
static uint8_t _uvm32_load1(void *p, uint32_t off) {
|
|
||||||
return ((uint8_t *)p)[off];
|
|
||||||
}
|
|
||||||
static int16_t _uvm32_load2s(void *p, uint32_t off) {
|
|
||||||
int16_t v;
|
|
||||||
UVM32_MEMCPY(&v, (uint8_t *)p + off, 2);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
static int8_t _uvm32_load1s(void *p, uint32_t off) {
|
|
||||||
return ((int8_t *)p)[off];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,15 @@ SOFTWARE.
|
||||||
// Include definitions for required syscalls
|
// Include definitions for required syscalls
|
||||||
#include "uvm32_sys.h"
|
#include "uvm32_sys.h"
|
||||||
|
|
||||||
|
typedef union __attribute__((packed)) {
|
||||||
|
uint32_t u32;
|
||||||
|
uint16_t u16;
|
||||||
|
uint8_t u8;
|
||||||
|
int8_t i8;
|
||||||
|
int16_t i16;
|
||||||
|
int32_t i32;
|
||||||
|
} uvm32_val_t;
|
||||||
|
|
||||||
// Setup and hooks for mini-rv32ima emulator core
|
// Setup and hooks for mini-rv32ima emulator core
|
||||||
#define MINIRV32_DECORATE static
|
#define MINIRV32_DECORATE static
|
||||||
#define MINIRV32_RETURN_TRAP
|
#define MINIRV32_RETURN_TRAP
|
||||||
|
|
@ -50,27 +59,19 @@ SOFTWARE.
|
||||||
#define MINIRV32_HANDLE_MEM_LOAD_CONTROL( addy, rval ) rval = _uvm32_extramLoad(userdata, addy, ( ir >> 12 ) & 0x7);
|
#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;
|
#define MINIRV32_HANDLE_MEM_STORE_CONTROL( addy, val ) if( _uvm32_extramStore(userdata, addy, val, ( ir >> 12 ) & 0x7) ) return val;
|
||||||
#define MINIRV32_CUSTOM_MEMORY_BUS
|
#define MINIRV32_CUSTOM_MEMORY_BUS
|
||||||
#define MINIRV32_STORE4( ofs, val ) _uvm32_store4(image, ofs, val)
|
#define MINIRV32_STORE4( ofs, val ) ((uvm32_val_t *)(&image[ofs]))->u32 = val
|
||||||
#define MINIRV32_STORE2( ofs, val ) _uvm32_store2(image, ofs, val)
|
#define MINIRV32_STORE2( ofs, val ) ((uvm32_val_t *)(&image[ofs]))->u16 = val
|
||||||
#define MINIRV32_STORE1( ofs, val ) _uvm32_store1(image, ofs, val)
|
#define MINIRV32_STORE1( ofs, val ) ((uvm32_val_t *)(&image[ofs]))->u8 = val
|
||||||
#define MINIRV32_LOAD4( ofs ) _uvm32_load4(image, ofs)
|
#define MINIRV32_LOAD4( ofs ) ((uvm32_val_t *)(&image[ofs]))->u32
|
||||||
#define MINIRV32_LOAD2( ofs ) _uvm32_load2(image, ofs)
|
#define MINIRV32_LOAD2( ofs ) ((uvm32_val_t *)(&image[ofs]))->u16
|
||||||
#define MINIRV32_LOAD1( ofs ) _uvm32_load1(image, ofs)
|
#define MINIRV32_LOAD1( ofs ) ((uvm32_val_t *)(&image[ofs]))->u8
|
||||||
#define MINIRV32_LOAD2_SIGNED( ofs ) _uvm32_load2s(image, ofs)
|
#define MINIRV32_LOAD2_SIGNED( ofs ) ((uvm32_val_t *)(&image[ofs]))->i16
|
||||||
#define MINIRV32_LOAD1_SIGNED( ofs ) _uvm32_load1s(image, ofs)
|
#define MINIRV32_LOAD1_SIGNED( ofs ) ((uvm32_val_t *)(&image[ofs]))->i8
|
||||||
#ifndef MINIRV32_IMPLEMENTATION
|
#ifndef MINIRV32_IMPLEMENTATION
|
||||||
#define MINIRV32_STEPPROTO
|
#define MINIRV32_STEPPROTO
|
||||||
#else
|
#else
|
||||||
static uint32_t _uvm32_extramLoad(void *userdata, uint32_t addr, uint32_t accessTyp);
|
static uint32_t _uvm32_extramLoad(void *userdata, uint32_t addr, uint32_t accessTyp);
|
||||||
static uint32_t _uvm32_extramStore(void *userdata, uint32_t addr, uint32_t val, uint32_t accessTyp);
|
static uint32_t _uvm32_extramStore(void *userdata, uint32_t addr, uint32_t val, uint32_t accessTyp);
|
||||||
static void _uvm32_store4(void *p, uint32_t off, uint32_t val);
|
|
||||||
static void _uvm32_store2(void *p, uint32_t off, uint16_t val);
|
|
||||||
static void _uvm32_store1(void *p, uint32_t off, uint8_t val);
|
|
||||||
static uint32_t _uvm32_load4(void *p, uint32_t off);
|
|
||||||
static uint16_t _uvm32_load2(void *p, uint32_t off);
|
|
||||||
static uint8_t _uvm32_load1(void *p, uint32_t off);
|
|
||||||
static int16_t _uvm32_load2s(void *p, uint32_t off);
|
|
||||||
static int8_t _uvm32_load1s(void *p, uint32_t off);
|
|
||||||
#endif
|
#endif
|
||||||
#include "mini-rv32ima.h"
|
#include "mini-rv32ima.h"
|
||||||
|
|
||||||
|
|
@ -127,7 +128,7 @@ typedef struct {
|
||||||
|
|
||||||
/*! Internal state of uvm32 */
|
/*! Internal state of uvm32 */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UVM32_STATUS_PAUSED,
|
UVM32_STATUS_PAUSED = 0,
|
||||||
UVM32_STATUS_RUNNING,
|
UVM32_STATUS_RUNNING,
|
||||||
UVM32_STATUS_ERROR,
|
UVM32_STATUS_ERROR,
|
||||||
UVM32_STATUS_ENDED,
|
UVM32_STATUS_ENDED,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue