#define VUEAPI #include /***************************************************************************** * 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 uint32_t TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; /***************************************************************************** * Component Includes * *****************************************************************************/ #include "cpu.c" #include "gamepak.c" /***************************************************************************** * Module Functions * *****************************************************************************/ /* Read a value from a byte buffer */ static int32_t readBuffer(uint8_t *data, uint32_t datlen, uint32_t address, int32_t type) { uint32_t size = TYPE_SIZES[type]; /* Size of data type */ int32_t value = 0; /* Error checking */ if (data == NULL) return 0; /* Common processing */ address &= (~size + 1) & (datlen - 1); /* The host is little-endian */ #ifndef VUE_BIGENDIAN switch (type) { case VUE_S8 : value = *( int8_t *)&data[address]; break; case VUE_U8 : value = *(uint8_t *)&data[address]; break; case VUE_S16: value = *( int16_t *)&data[address]; break; case VUE_U16: value = *(uint16_t *)&data[address]; break; case VUE_S32: value = *( int32_t *)&data[address]; break; } /* The host is big-endian */ #else switch (type) { case VUE_S32: value = data[address + 3] << 24 | (data[address + 2] & 0xFF) << 16; /* Fallthrough */ case VUE_S16: /* Fallthrough */ case VUE_U16: value |= (data[address + 1] & 0xFF) << 8; /* Fallthrough */ case VUE_S8 : /* Fallthrough */ case VUE_U8 : value |= data[address ] & 0xFF; } /* Sign-extend the value if appropriate */ if ((type & 1) == 0) { size <<= 3; value = SIGN_EXTEND(size, value); } #endif return value; } /* Read bytes from a byte buffer */ static void readBytes(uint8_t *data, uint32_t datlen, uint32_t address, uint8_t *dest, uint32_t length) { /* The source does not exist */ if (data == NULL) { while (length--) *dest++ = 0; return; } /* Transfer bytes from the source as a circular buffer */ while (length--) *dest++ = data[address++ & (datlen - 1)]; } /* Write a value to a byte buffer */ static void writeBuffer(uint8_t *data, uint32_t datlen, uint32_t address, int32_t type, int32_t value) { uint32_t size = TYPE_SIZES[type]; /* Size of data type */ /* Error checking */ if (data == NULL) return; /* Common processing */ address &= (~size + 1) & (datlen - 1); /* The host is big-endian */ #ifdef VUE_BIGENDIAN switch (type) { case VUE_S32: value = (value >> 16 & 0x0000FFFF) | value << 16; /* Fallthrough */ case VUE_S16: /* Fallthrough */ case VUE_U16: value = (value >> 8 & 0x00FF00FF) | (value << 8 & 0xFF00FF00); } #endif /* Processing by data type */ switch (type) { case VUE_S8 : /* Fallthrough */ case VUE_U8 : *(int8_t *)&data[address] = (int8_t ) value; break; case VUE_S16: /* Fallthrough */ case VUE_U16: *(int16_t *)&data[address] = (int16_t ) value; break; case VUE_S32: *(int32_t *)&data[address] = (int32_t ) value; break; } } /* Write bytes to a byte buffer */ static void writeBytes(uint8_t *data, uint32_t datlen, uint32_t address, uint8_t *src, uint32_t length) { /* The destination does not exist */ if (data == NULL) return; /* Transfer bytes to the destination as a circular buffer */ while (length--) data[address++ & (datlen - 1)] = *src++; } /***************************************************************************** * Library Functions * *****************************************************************************/ /* Process the simulation */ int32_t vueEmulate(Vue *vue, int32_t maxCycles) { int32_t cycles; /* Number of cycles to process */ /* Process up to the given number of cycles */ do { /* Determine the number of cycles during which nothing will happen */ cycles = -1; /*cycles = padUntil (vue, cycles);*/ /*cycles = linkUntil (vue, cycles);*/ /*cycles = timerUntil(vue, cycles);*/ /*cycles = vipUntil (vue, cycles);*/ /*cycles = vsuUntil (vue, cycles);*/ cycles = cpuUntil (vue, cycles); /* Range checking */ if (cycles == -1) /* No activity on any component */ break; if (maxCycles >= 0) /* Restrict to given number of cycles */ cycles = cycles < maxCycles ? cycles : maxCycles; /* Process all system components */ vue->breakCode = 0; /*padEmulate (vue, cycles);*/ /*pakEmulate (vue, cycles);*/ /*linkEmulate (vue, cycles);*/ /*timerEmulate(vue, cycles);*/ /*vipEmulate (vue, cycles);*/ /*vsuEmulate (vue, cycles);*/ cpuEmulate (vue, cycles); /* An application break was requested */ if (vue->breakCode != 0) break; /* Update the number of cycles remaining */ if (maxCycles >= 0) maxCycles -= cycles; } while (maxCycles != 0); /* A break condition has occurred */ return maxCycles; } /* Retrieve the application break code */ int32_t vueGetBreakCode(Vue *vue) { return vue == NULL ? 0 : vue->breakCode; } /* Retrieve the value of a register */ int32_t vueGetRegister(Vue *vue, int32_t 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->onException = NULL; vue->onExecute = NULL; vue->onRead = NULL; vue->onWrite = NULL; vue->pak.ram = NULL; vue->pak.rom = NULL; } /* Read a value from the CPU bus */ int32_t vueRead(Vue *vue, uint32_t address, int32_t type) { /* Error checking */ if (vue == NULL) return 0; /* Perform the operation */ switch (address >> 24 & 7) { case 5: return readBuffer(vue->wram , 0x10000,address,type); case 6: return readBuffer(vue->pak.ram,vue->pak.ramSize,address,type); case 7: return readBuffer(vue->pak.rom,vue->pak.romSize,address,type); } return 0; } /* Read bytes from the CPU bus */ vbool vueReadBytes(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 */ while (length > 0) { count = 0x01000000 - (address & 0x00FFFFFF); if (length < count) count = length; switch (address >> 24 & 7) { case 5: readBytes(vue->wram , 0x10000, address, dest, count); break; case 6: readBytes(vue->pak.ram, vue->pak.ramSize, address, dest, count); break; case 7: readBytes(vue->pak.rom, vue->pak.romSize, address, dest, count); break; default: for (address += count, length -= count; count--;) *dest++ = 0; continue; } address += count; length -= count; dest += count; } return VUE_TRUE; } /* Initialize all system components */ void vueReset(Vue *vue) { uint32_t x; /* Iterator */ /* Error checking */ if (vue == NULL) return; /* Reset state */ cpuReset(vue); pakReset(vue); for (x = 0; x < 0x1000; x++) vue->wram[x] = 0; } /* Specify an exception breakpoint callback */ void vueSetException(Vue *vue, VueOnException callback) { if (vue != NULL) vue->onException = callback; } /* Specify an execute breakpoint callback */ void vueSetExecute(Vue *vue, VueOnExecute callback) { if (vue != NULL) vue->onExecute = callback; } /* Specify a read breakpoint callback */ void vueSetRead(Vue *vue, VueOnRead callback) { if (vue != NULL) vue->onRead = callback; } /* Specify a value for a register */ int32_t vueSetRegister(Vue *vue, int32_t 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->pak.rom = rom; vue->pak.romSize = size; return VUE_TRUE; } /* Specify a write breakpoint callback */ void vueSetWrite(Vue *vue, VueOnRead callback) { if (vue != NULL) vue->onWrite = callback; } /* Write a value to the CPU bus */ void vueWrite(Vue *vue, uint32_t address, int32_t type, int32_t value) { /* Error checking */ if (vue == NULL) return; /* Perform the operation */ switch (address >> 24 & 7) { case 5: writeBuffer(vue->wram , 0x1000, address, type, value); break; case 6: writeBuffer(vue->pak.ram, vue->pak.ramSize, address, type, value); break; case 7: writeBuffer(vue->pak.rom, vue->pak.romSize, address, type, value); break; } } /* Write bytes to the CPU bus */ vbool vueWriteBytes(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 */ while (length > 0) { count = 0x01000000 - (address & 0x00FFFFFF); if (length < count) count = length; switch (address >> 24 & 7) { case 5: writeBytes(vue->wram , 0x10000, address, src, count); break; case 6: writeBytes(vue->pak.ram, vue->pak.ramSize, address, src, count); break; case 7: writeBytes(vue->pak.rom, vue->pak.ramSize, address, src, count); break; } address += count; length -= count; src += count; } return VUE_TRUE; }