#define VBAPI /* Header includes */ #include /********************************* Constants *********************************/ /* Type sizes */ static const uint8_t TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; /********************************** Macros ***********************************/ /* Sign-extend a value of some number of bits to 32 bits */ #define SignExtend(v,b) ( (v) | (((v) & 1 << b - 1) ? ~(int32_t)0 << b : 0) ) /*************************** Subsystem Components ****************************/ /* Component includes */ #include "bus.c" /******************************* API Functions *******************************/ /* Retrieve the value of PC */ uint32_t vbGetProgramCounter(VB *emu, int type) { switch (type) { case VB_PC : return emu->cpu.pc; case VB_PC_FROM: return emu->cpu.pcFrom; case VB_PC_TO : return emu->cpu.pcTo; } return 0; } /* Retrieve the value of a program register */ int32_t vbGetProgramRegister(VB *emu, int id) { return id < 1 || id > 31 ? 0 : emu->cpu.program[id]; } /* Retrieve the ROM buffer */ void* vbGetROM(VB *emu, uint32_t *size) { if (size != NULL) *size = emu->cart.romSize; return emu->cart.rom; } /* Retrieve the SRAM buffer */ void* vbGetSRAM(VB *emu, uint32_t *size) { if (size != NULL) *size = emu->cart.sramSize; return emu->cart.sram; } /* Retrieve the value of a system register */ uint32_t vbGetSystemRegister(VB *emu, int id) { switch (id) { case VB_ADTRE: return emu->cpu.adtre; case VB_CHCW : return emu->cpu.chcw.ice << 1; case VB_EIPC : return emu->cpu.eipc; case VB_EIPSW: return emu->cpu.eipsw; case VB_FEPC : return emu->cpu.fepc; case VB_FEPSW: return emu->cpu.fepsw; case VB_PIR : return 0x00005346; case VB_TKCW : return 0x000000E0; case 29 : return emu->cpu.sr29; case 30 : return 0x00000004; case 31 : return emu->cpu.sr31; case VB_ECR : return (uint32_t) emu->cpu.ecr.fecc << 16 | emu->cpu.ecr.eicc; case VB_PSW : return (uint32_t) emu->cpu.psw.i << 16 | (uint32_t) emu->cpu.psw.np << 15 | (uint32_t) emu->cpu.psw.ep << 14 | (uint32_t) emu->cpu.psw.ae << 13 | (uint32_t) emu->cpu.psw.id << 12 | (uint32_t) emu->cpu.psw.fro << 9 | (uint32_t) emu->cpu.psw.fiv << 8 | (uint32_t) emu->cpu.psw.fzd << 7 | (uint32_t) emu->cpu.psw.fov << 6 | (uint32_t) emu->cpu.psw.fud << 5 | (uint32_t) emu->cpu.psw.fpr << 4 | (uint32_t) emu->cpu.psw.cy << 3 | (uint32_t) emu->cpu.psw.ov << 2 | (uint32_t) emu->cpu.psw.s << 1 | (uint32_t) emu->cpu.psw.z ; } return 0; } /* Prepare a simulation state instance for use */ void vbInit(VB *emu) { /* Cartridge */ emu->cart.rom = NULL; emu->cart.romSize = 0; emu->cart.sram = NULL; emu->cart.sramSize = 0; /* All others */ vbReset(emu); } /* Read a data unit from the bus */ int32_t vbRead(VB *emu, uint32_t address, int type, int debug) { return type < 0 || type >= (int) sizeof TYPE_SIZES ? 0 : busRead(emu, address, type, debug); } /* Simulate a hardware reset */ void vbReset(VB *emu) { uint32_t x; /* Iterator */ /* CPU registers */ emu->cpu.pc = 0xFFFFFFF0; vbSetSystemRegister(emu, VB_ECR, 0x0000FFF0); vbSetSystemRegister(emu, VB_PSW, 0x00008000); /* Extra CPU registers (the hardware does not do this) */ for (x = 0; x < 32; x++) emu->cpu.program[x] = 0x00000000; emu->cpu.adtre = 0x00000000; emu->cpu.eipc = 0x00000000; emu->cpu.eipsw = 0x00000000; emu->cpu.fepc = 0x00000000; emu->cpu.fepsw = 0x00000000; emu->cpu.sr29 = 0x00000000; emu->cpu.sr31 = 0x00000000; emu->cpu.pcFrom = 0xFFFFFFF0; emu->cpu.pcTo = 0xFFFFFFF0; /* WRAM (the hardware does not do this) */ for (x = 0; x < 0x10000; x++) emu->wram[x] = 0x00; } /* Specify a new value for PC */ uint32_t vbSetProgramCounter(VB *emu, uint32_t value) { value &= 0xFFFFFFFE; emu->cpu.pc = value; /* Set stage to fecth=0 */ return value; } /* Specify a new value for a program register */ int32_t vbSetProgramRegister(VB *emu, int id, int32_t value) { return id < 1 || id > 31 ? 0 : (emu->cpu.program[id] = value); } /* Supply a ROM buffer */ int vbSetROM(VB *emu, void *rom, uint32_t size) { /* Check the buffer size */ if (size < 1024 || size > 0x1000000 || ((size - 1) & size) != 0) return 0; /* Configure the ROM buffer */ emu->cart.rom = (uint8_t *) rom; emu->cart.romSize = size; return 1; } /* Supply an SRAM buffer */ int vbSetSRAM(VB *emu, void *sram, uint32_t size) { /* Check the buffer size */ if (size == 0 || ((size - 1) & size) != 0) return 0; /* Configure the SRAM buffer */ emu->cart.sram = (uint8_t *) sram; emu->cart.sramSize = size; return 1; } /* Specify a new value for a system register */ uint32_t vbSetSystemRegister(VB *emu, int id, uint32_t value) { switch (id) { case VB_ADTRE: return emu->cpu.adtre = value & 0xFFFFFFFE; case VB_EIPC : return emu->cpu.eipc = value & 0xFFFFFFFE; case VB_EIPSW: return emu->cpu.eipsw = value & 0x000FF3FF; case VB_FEPC : return emu->cpu.fepc = value & 0xFFFFFFFE; case VB_FEPSW: return emu->cpu.fepsw = value & 0x000FF3FF; case VB_PIR : return 0x00005346; case VB_TKCW : return 0x000000E0; case 29 : return emu->cpu.sr29 = value & 0x00000001; case 31 : return emu->cpu.sr31 = value; case VB_CHCW : emu->cpu.chcw.ice = value >> 1 & 1; return value & 0x00000002; case VB_ECR : emu->cpu.ecr.fecc = value >> 16; emu->cpu.ecr.eicc = value; return value; case VB_PSW : emu->cpu.psw.i = value >> 16 & 15; emu->cpu.psw.np = value >> 15 & 1; emu->cpu.psw.ep = value >> 14 & 1; emu->cpu.psw.ae = value >> 13 & 1; emu->cpu.psw.id = value >> 12 & 1; emu->cpu.psw.fro = value >> 9 & 1; emu->cpu.psw.fiv = value >> 8 & 1; emu->cpu.psw.fzd = value >> 7 & 1; emu->cpu.psw.fov = value >> 6 & 1; emu->cpu.psw.fud = value >> 5 & 1; emu->cpu.psw.fpr = value >> 4 & 1; emu->cpu.psw.cy = value >> 3 & 1; emu->cpu.psw.ov = value >> 2 & 1; emu->cpu.psw.s = value >> 1 & 1; emu->cpu.psw.z = value & 1; return value & 0x000FF3FF; } return 0; } /* Write a data unit to the bus */ void vbWrite(VB *emu, uint32_t address, int type, int32_t value, int debug) { if (type < 0 || type >= (int32_t) sizeof TYPE_SIZES) busWrite(emu, address, type, value, debug); }