175 lines
5.3 KiB
C
175 lines
5.3 KiB
C
#define VUEAPI
|
|
#include <vue.h>
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* Macros *
|
|
*****************************************************************************/
|
|
|
|
/* Sign-extend a value */
|
|
#define SIGN_EXTEND(bits, value) \
|
|
((value) & 1 << (bits - 1) ? (value) | (~(1 << bits) + 1) : (value))
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* Constants *
|
|
*****************************************************************************/
|
|
|
|
/* Memory access type sizes */
|
|
static const int TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* Component Includes *
|
|
*****************************************************************************/
|
|
|
|
#include "bus.c"
|
|
#include "cpu.c"
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* Library Functions *
|
|
*****************************************************************************/
|
|
|
|
/* Retrieve the value of a register */
|
|
int32_t vueGetRegister(VUE *vue, int index, vbool system) {
|
|
|
|
/* Error checking */
|
|
if (vue == NULL)
|
|
return 0;
|
|
|
|
/* Non-indexed registers */
|
|
if (system && index < 0) switch (index) {
|
|
case VUE_JUMP_FROM:
|
|
return vue->cpu.jumpFrom[vue->cpu.psw_np ? 2 : vue->cpu.psw_ep];
|
|
case VUE_JUMP_TO :
|
|
return vue->cpu.jumpTo [vue->cpu.psw_np ? 2 : vue->cpu.psw_ep];
|
|
case VUE_PC : return vue->cpu.pc;
|
|
}
|
|
|
|
/* Indexed registers */
|
|
return
|
|
index < 0 || index > 31 ? 0 :
|
|
system ? cpuGetSystemRegister(vue, index) :
|
|
vue->cpu.program[index]
|
|
;
|
|
}
|
|
|
|
/* Prepare an emulation state context for use */
|
|
void vueInitialize(VUE *vue) {
|
|
if (vue == NULL)
|
|
return;
|
|
vue->bus.rom = NULL;
|
|
vue->bus.sram = NULL;
|
|
}
|
|
|
|
/* Read bytes from the CPU bus */
|
|
vbool vueRead(VUE *vue, uint32_t address, uint8_t *dest, uint32_t length) {
|
|
uint32_t count; /* Bytes to read in one iteration */
|
|
|
|
/* Error checking */
|
|
if (vue == NULL || dest == NULL)
|
|
return VUE_FALSE;
|
|
|
|
/* Perform the operation */
|
|
for (; length > 0; address += count, length -= count, dest += count) {
|
|
|
|
/* Determine the maximum number of bytes to process at once */
|
|
count = 0x01000000 - (address & 0x00FFFFFF);
|
|
if (count > length)
|
|
count = length;
|
|
|
|
/* Process by component */
|
|
switch (address >> 24 & 7) {
|
|
case 1: /* Fallthrough */ /* VSU (write-only) */
|
|
case 3: /* Fallthrough */ /* Unmapped */
|
|
case 4: /* Cartridge expansion (not supported) */
|
|
busReadBytes(NULL, dest, address, 0, count);
|
|
break;
|
|
case 5: busReadBytes(vue->bus.wram, dest, /* System WRAM */
|
|
address, 0x10000 , count);
|
|
break;
|
|
case 6: busReadBytes(vue->bus.sram, dest, /* Cartridge RAM */
|
|
address, vue->bus.sramSize, count);
|
|
break;
|
|
case 7: busReadBytes(vue->bus.rom , dest, /* Cartridge ROM */
|
|
address, vue->bus.romSize , count);
|
|
break;
|
|
}
|
|
|
|
};
|
|
return VUE_TRUE;
|
|
}
|
|
|
|
/* Initialize all system components */
|
|
void vueReset(VUE *vue) {
|
|
if (vue == NULL)
|
|
return;
|
|
busReset(vue);
|
|
cpuReset(vue);
|
|
}
|
|
|
|
/* Specify a value for a register */
|
|
int32_t vueSetRegister(VUE *vue, int index, vbool system, int32_t value) {
|
|
return vue == NULL ? 0 :
|
|
index == VUE_PC && system ? vue->cpu.pc = value & 0xFFFFFFFE :
|
|
index < 0 || index > 31 ? 0 :
|
|
system ? cpuSetSystemRegister(vue, index, value, VUE_TRUE) :
|
|
index == 0 ? 0 : (vue->cpu.program[index] = value)
|
|
;
|
|
}
|
|
|
|
/* Specify a new ROM buffer */
|
|
vbool vueSetROM(VUE *vue, uint8_t *rom, uint32_t size) {
|
|
|
|
/* Error checking */
|
|
if (
|
|
vue == NULL ||
|
|
rom == NULL ||
|
|
size < 1024 || size > 0x01000000 ||
|
|
(size & (size - 1)) != 0
|
|
) return VUE_FALSE;
|
|
|
|
/* Accept the new ROM buffer */
|
|
vue->bus.rom = rom;
|
|
vue->bus.romSize = size;
|
|
return VUE_TRUE;
|
|
}
|
|
|
|
/* Write bytes to the CPU bus */
|
|
vbool vueWrite(VUE *vue, uint32_t address, uint8_t *src, uint32_t length) {
|
|
uint32_t count; /* Bytes to write in one iteration */
|
|
|
|
/* Error checking */
|
|
if (vue == NULL || src == NULL)
|
|
return VUE_FALSE;
|
|
|
|
/* Perform the operation */
|
|
for (; length > 0; address += count, length -= count, src += count) {
|
|
|
|
/* Determine the maximum number of bytes to process at once */
|
|
count = 0x01000000 - (address & 0x00FFFFFF);
|
|
if (count > length)
|
|
count = length;
|
|
|
|
/* Process by component */
|
|
switch (address >> 24 & 7) {
|
|
case 5: /* System WRAM */
|
|
busWriteBytes(vue->bus.wram, src, address, 0x10000, count);
|
|
break;
|
|
case 6: busWriteBytes(vue->bus.sram, src, /* Cartridge RAM */
|
|
address, vue->bus.sramSize, count);
|
|
break;
|
|
case 7: busWriteBytes(vue->bus.rom , src, /* Cartridge ROM */
|
|
address, vue->bus.romSize , count);
|
|
break;
|
|
}
|
|
|
|
};
|
|
return VUE_TRUE;
|
|
}
|