diff --git a/core/bus.c b/core/bus.c index 3e37709..3a25aa8 100644 Binary files a/core/bus.c and b/core/bus.c differ diff --git a/core/cpu.c b/core/cpu.c index fb3d1ee..441feb2 100644 --- a/core/cpu.c +++ b/core/cpu.c @@ -5,1376 +5,56 @@ /********************************* Constants *********************************/ -/* Operations states */ +/* Pipeline stages */ #define CPU_FETCH 0 -#define CPU_EXECUTE 1 -#define CPU_EXCEPTION 2 -#define CPU_HALTED 3 +#define CPU_EXECUTE_A 1 +#define CPU_EXECUTE_B 2 +#define CPU_HALT 3 #define CPU_FATAL 4 -/* Instruction IDs */ -#define CPU_ILLEGAL -1 -#define CPU_ADD_IMM 0 -#define CPU_ADD_REG 1 -#define CPU_ADDF_S 2 -#define CPU_ADDI 3 -#define CPU_AND 4 -#define CPU_ANDBSU 5 -#define CPU_ANDI 6 -#define CPU_ANDNBSU 7 -#define CPU_BCOND 8 -#define CPU_CAXI 9 -#define CPU_CLI 10 -#define CPU_CMP_IMM 11 -#define CPU_CMP_REG 12 -#define CPU_CMPF_S 13 -#define CPU_CVT_SW 14 -#define CPU_CVT_WS 15 -#define CPU_DIV 16 -#define CPU_DIVF_S 17 -#define CPU_DIVU 18 -#define CPU_HALT 19 -#define CPU_IN_B 20 -#define CPU_IN_H 21 -#define CPU_IN_W 22 -#define CPU_JAL 23 -#define CPU_JMP 24 -#define CPU_JR 25 -#define CPU_LD_B 26 -#define CPU_LD_H 27 -#define CPU_LD_W 28 -#define CPU_LDSR 29 -#define CPU_MOV_IMM 30 -#define CPU_MOV_REG 31 -#define CPU_MOVBSU 32 -#define CPU_MOVEA 33 -#define CPU_MOVHI 34 -#define CPU_MPYHW 35 -#define CPU_MUL 36 -#define CPU_MULF_S 37 -#define CPU_MULU 38 -#define CPU_NOT 39 -#define CPU_NOTBSU 40 -#define CPU_OR 41 -#define CPU_ORBSU 42 -#define CPU_ORI 43 -#define CPU_ORNBSU 44 -#define CPU_OUT_B 45 -#define CPU_OUT_H 46 -#define CPU_OUT_W 47 -#define CPU_RETI 48 -#define CPU_REV 49 -#define CPU_SAR_IMM 50 -#define CPU_SAR_REG 51 -#define CPU_SCH0BSD 52 -#define CPU_SCH0BSU 53 -#define CPU_SCH1BSD 54 -#define CPU_SCH1BSU 55 -#define CPU_SEI 56 -#define CPU_SETF 57 -#define CPU_SHL_IMM 58 -#define CPU_SHL_REG 59 -#define CPU_SHR_IMM 60 -#define CPU_SHR_REG 61 -#define CPU_ST_B 62 -#define CPU_ST_H 63 -#define CPU_ST_W 64 -#define CPU_STSR 65 -#define CPU_SUB 66 -#define CPU_SUBF_S 67 -#define CPU_TRAP 68 -#define CPU_TRNC_SW 69 -#define CPU_XB 70 -#define CPU_XH 71 -#define CPU_XOR 72 -#define CPU_XORBSU 73 -#define CPU_XORI 74 -#define CPU_XORNBSU 75 -#define CPU_BITSTRING 76 -#define CPU_FLOATENDO 77 -/* Mapping for opcodes to operation IDs */ -static const int8_t CPU_OPCODES[] = { - CPU_MOV_REG, CPU_ADD_REG, CPU_SUB , CPU_CMP_REG , - CPU_SHL_REG, CPU_SHR_REG, CPU_JMP , CPU_SAR_REG , - CPU_MUL , CPU_DIV , CPU_MULU , CPU_DIVU , - CPU_OR , CPU_AND , CPU_XOR , CPU_NOT , - CPU_MOV_IMM, CPU_ADD_IMM, CPU_SETF , CPU_CMP_IMM , - CPU_SHL_IMM, CPU_SHR_IMM, CPU_CLI , CPU_SAR_IMM , - CPU_TRAP , CPU_RETI , CPU_HALT , CPU_ILLEGAL , - CPU_LDSR , CPU_STSR , CPU_SEI , CPU_BITSTRING, - CPU_BCOND , CPU_BCOND , CPU_BCOND , CPU_BCOND , - CPU_BCOND , CPU_BCOND , CPU_BCOND , CPU_BCOND , - CPU_MOVEA , CPU_ADDI , CPU_JR , CPU_JAL , - CPU_ORI , CPU_ANDI , CPU_XORI , CPU_MOVHI , - CPU_LD_B , CPU_LD_H , CPU_ILLEGAL , CPU_LD_W , - CPU_ST_B , CPU_ST_H , CPU_ILLEGAL , CPU_ST_W , - CPU_IN_B , CPU_IN_H , CPU_CAXI , CPU_IN_W , - CPU_OUT_B , CPU_OUT_H , CPU_FLOATENDO, CPU_OUT_W -}; -/* Mapping for bit string sub-opcodes */ -static const int8_t CPU_BITSTRINGS[] = { - CPU_SCH0BSU, CPU_SCH0BSD, CPU_SCH1BSU, CPU_SCH1BSD, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ORBSU , CPU_ANDBSU , CPU_XORBSU , CPU_MOVBSU , - CPU_ORNBSU , CPU_ANDNBSU, CPU_XORNBSU, CPU_NOTBSU , - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL -}; +/*********************************** Types ***********************************/ -/* Mapping for floating-point/Nintendo sub-opcodes */ -static const int8_t CPU_FLOATENDOS[] = { - CPU_CMPF_S , CPU_ILLEGAL, CPU_CVT_WS , CPU_CVT_SW , - CPU_ADDF_S , CPU_SUBF_S , CPU_MULF_S , CPU_DIVF_S , - CPU_XB , CPU_XH , CPU_REV , CPU_TRNC_SW, - CPU_MPYHW , CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, - CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL, CPU_ILLEGAL -}; +/* Handler types */ +typedef int (*ExecuteAProc )(VB *); +typedef void (*ExecuteBProc )(VB *); +typedef void (*OperationProc)(VB *, int32_t *, int32_t); +typedef int32_t (*OperandProc )(VB *); -/* Instruction sizes by opcode */ -static const uint8_t CPU_SIZES[] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 2, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4 -}; +/* Opcode descriptor */ +typedef struct { + ExecuteAProc executeA; /* Execute handler (no state change) */ + ExecuteBProc executeB; /* Execute handler (update state) */ + OperationProc operation; /* Operation handler */ + OperandProc operand; /* Operand handler */ + uint8_t size; /* Total size in halfwords */ + uint8_t aux; /* Number of clocks or access data type */ +} OpDef; + +/* Floating-point auxiliary memory */ +typedef struct { + float f32; /* 32-bit result */ + double f64; /* 64-bit result */ +} FloatAux; /***************************** Utility Functions *****************************/ -/* Read a data unit from the bus */ -static int cpuRead(VB *sim, uint32_t address, int8_t type) { - - /* TODO: Determine clock count here */ - sim->cpu.access.clocks = 0; - - /* Not using a breakpoint callback */ - if (sim->onRead == NULL) { - sim->cpu.access.value = busRead(sim, address, type, 0); - return 0; - } - - /* Invoke the breakpoint callback */ - sim->cpu.access.address = address; - sim->cpu.access.type = type; - return sim->onRead(sim, &sim->cpu.access); -} - -/* Read a data unit from the bus for the purpose of an instruction fetch */ -static int cpuReadFetch(VB *sim, uint32_t address) { - - /* TODO: Determine clock count here */ - sim->cpu.access.clocks = 0; - - /* Not using a breakpoint callback */ - if (sim->onFetch == NULL) { - sim->cpu.access.value = busRead(sim, address, VB_U16, 0); - return 0; - } - - /* Invoke the breakpoint callback */ - sim->cpu.access.address = address; - sim->cpu.access.type = VB_U16; - return sim->onFetch(sim, sim->cpu.fetch, &sim->cpu.access); -} - -/* Write a data unit to the bus */ -static int cpuWrite(VB *sim, uint32_t address, int8_t type, int32_t value) { - - /* TODO: Determine clock count here */ - sim->cpu.access.clocks = 0; - sim->cpu.access.type = type; - - /* Using a breakpoint callback */ - if (sim->onWrite != NULL) { - sim->cpu.access.address = address; - sim->cpu.access.value = value; - if (sim->onWrite(sim, &sim->cpu.access)) - return 1; - } - - /* Write the value if the operation wasn't cancelled */ - if (sim->cpu.access.type != VB_CANCEL) - busWrite(sim, address, type, value, 0); - return 0; -} - - - -/**************************** Instruction Helpers ****************************/ - -/* Add two numbers and update the flags */ -static int32_t cpuAdd(VB *sim, int32_t left, int32_t right) { - int32_t result = left + right; - sim->cpu.clocks = 1; - sim->cpu.psw.cy = (uint32_t) result < (uint32_t) left; - sim->cpu.psw.ov = (~(left ^ right) & (left ^ result)) >> 31 & 1; - sim->cpu.psw.s = result < 0; - sim->cpu.psw.z = result == 0; - return result; -} - -/* Bit string search */ -static int cpuBitSearch(VB *sim, int32_t bit, int32_t dir) { - int32_t offset; /* Bit offset in source word */ - int32_t value; /* Alias of source word */ - - /* Read the source word */ - if (sim->cpu.busWait == 0) { - - /* Initialize state */ - sim->cpu.program[30] &= 0xFFFFFFFC; - sim->cpu.program[27] &= 0x0000001F; - sim->cpu.psw.z = 1; - - /* The bit string is of zero length */ - if (sim->cpu.program[28] == 0) { - sim->cpu.clocks = dir == 1 ? 13 : 15; - return 0; - } - - /* Read the data unit from the bus */ - if (cpuRead(sim, sim->cpu.program[30], VB_S32)) - return 1; - - /* Update state */ - sim->cpu.busWait = 1; - sim->cpu.clocks = sim->cpu.access.clocks; - - /* Wait for the bus access to complete */ - if (sim->cpu.clocks > 0) - return 0; - } - - /* Update state */ - sim->cpu.busWait = 0; - sim->cpu.substring = 0; - - /* Search the bit string */ - for ( - offset = sim->cpu.program[27], value = sim->cpu.access.value; - sim->cpu.program[28] != 0 && (offset & 31) == offset; - offset += dir, sim->cpu.program[28]--, sim->cpu.program[29]++ - ) { - - /* The current bit does not match */ - if ((value >> offset & 1) != bit) - continue; - - /* The current bit matches */ - sim->cpu.program[27] = offset; - sim->cpu.clocks = dir == 1 ? 45 : 50; - sim->cpu.psw.z = 0; - return 0; - } - - /* No bit in the current word matches */ - sim->cpu.program[27] = offset & 31; - if (sim->cpu.program[27] != offset) - sim->cpu.program[30] += (uint32_t) dir << 2; - if (sim->cpu.program[28] != 0) { - sim->cpu.substring = 1; - sim->cpu.clocks = 5; - } else sim->cpu.clocks = dir == 1 ? 46 : 51; - return 0; -} - -/* Bit string bitwise operation */ -static int cpuBitString(VB *sim, VB_INSTRUCTION *inst) { - uint64_t bits; /* Shift register */ - int32_t dest; /* Destination word value */ - int32_t mask; /* Bit mask */ - int32_t src; /* Source word value */ - - /* Initial invocation */ - if (sim->cpu.busWait == 0) { - - /* Initialize state */ - sim->cpu.program[30] &= 0xFFFFFFFC; - sim->cpu.program[29] &= 0xFFFFFFFC; - sim->cpu.program[27] &= 0x0000001F; - sim->cpu.program[26] &= 0x0000001F; - - /* The bit string is of zero length */ - if (sim->cpu.program[28] == 0) { - sim->cpu.clocks = 20; - return 0; - } - - /* Read the data unit from the bus */ - if (cpuRead(sim, sim->cpu.program[30], VB_S32)) - return 1; - - /* Update state */ - inst->aux[0] = sim->cpu.access.value; - sim->cpu.busWait = 1; - sim->cpu.clocks = sim->cpu.access.clocks; - - /* Wait for the bus access to complete */ - if (sim->cpu.clocks > 0) - return 0; - } - - /* Read the next source word */ - if (sim->cpu.busWait == 1) { - - /* Read the data unit from the bus */ - if (cpuRead(sim, sim->cpu.program[30] + 4, VB_S32)) - return 1; - - /* Update state */ - inst->aux[1] = sim->cpu.access.value; - sim->cpu.busWait = 2; - sim->cpu.clocks = sim->cpu.access.clocks; - - /* Wait for the bus access to complete */ - if (sim->cpu.clocks > 0) - return 0; - } - - /* Read the destination word */ - if (sim->cpu.busWait == 2) { - - /* Read the data unit from the bus */ - if (cpuRead(sim, sim->cpu.program[29], VB_S32)) - return 1; - - /* Update state */ - sim->cpu.busWait = 3; - sim->cpu.clocks = sim->cpu.access.clocks; - - /* Wait for the bus access to complete */ - if (sim->cpu.clocks > 0) - return 0; - } - - /* Compute and store the destination word */ - if (sim->cpu.busWait == 3) { - bits = ((uint64_t) inst->aux[1] << 32 | (uint32_t) inst->aux[0]); - dest = sim->cpu.access.value; - src = sim->cpu.program[27] <= sim->cpu.program[26] ? - bits << (sim->cpu.program[26] - sim->cpu.program[27]) : - bits >> (sim->cpu.program[27] - sim->cpu.program[26]) - ; - - /* Perform the operation */ - switch (inst->bits[0] & 7) { - case 0 : dest |= src; break; /* ORBSU */ - case 1 : dest &= src; break; /* ANDBSU */ - case 2 : dest ^= src; break; /* XORBSU */ - case 3 : dest = src; break; /* MOVBSU */ - case 4 : dest |= ~src; break; /* ORNBSU */ - case 5 : dest &= ~src; break; /* ANDNBSU */ - case 6 : dest ^= ~src; break; /* XORNBSU */ - default: dest = ~src; break; /* NOTBSU */ - } - - /* Incorporate only the bits occupied by the bit string */ - mask = (uint32_t) 0xFFFFFFFF << sim->cpu.program[26]; - if ((uint32_t)sim->cpu.program[28] < (uint32_t)32-sim->cpu.program[26]) - mask &= (1 << (sim->cpu.program[28] + sim->cpu.program[26])) - 1; - dest = (dest & mask) | (sim->cpu.access.value & ~mask); - - /* Write the data unit to the bus */ - if (cpuWrite(sim, sim->cpu.program[29], VB_S32, dest)) - return 1; - - /* Update state */ - sim->cpu.busWait = 4; - sim->cpu.clocks = sim->cpu.access.clocks; - - /* Wait for the bus access to complete */ - if (sim->cpu.clocks > 0) - return 0; - } - - /* Working variables */ - mask = 32 - sim->cpu.program[26]; /* Bits processed this invocation */ - if ((uint32_t) sim->cpu.program[28] < (uint32_t) mask) - mask = sim->cpu.program[28]; - dest = sim->cpu.program[26] + mask; /* New destination bit offset */ - src = sim->cpu.program[27] + mask; /* New source bit offset */ - - /* Update state */ - sim->cpu.busWait = 0; - sim->cpu.substring = mask != sim->cpu.program[28]; - sim->cpu.program[26] = dest & 31; - sim->cpu.program[27] = src & 31; - sim->cpu.program[28] -= mask; - if (dest >= 32) - sim->cpu.program[29] += 4; - if (src >= 32) - sim->cpu.program[30] += 4; - if (sim->cpu.substring) { - sim->cpu.busWait = 1; - sim->cpu.clocks = 6; - inst->aux[0] = inst->aux[1]; - } else { - sim->cpu.busWait = 0; - sim->cpu.clocks = 36; - } - return 0; -} - -/* Common processing for most bitwise operations */ -static int32_t cpuBitwise(VB *sim, int32_t result) { - sim->cpu.clocks = 1; - sim->cpu.psw.ov = 0; - sim->cpu.psw.s = result < 0; - sim->cpu.psw.z = result == 0; - return result; -} - -/* Test a condition code */ -static int cpuCondition(VB *sim, int cond) { - - /* Falsey condition */ - if (cond > 7) - return !cpuCondition(sim, cond & 7); - - /* Truthy condition */ - switch (cond) { - case 0: return sim->cpu.psw.ov; /* V */ - case 1: return sim->cpu.psw.cy; /* L */ - case 2: return sim->cpu.psw.z; /* Z */ - case 3: return sim->cpu.psw.cy | sim->cpu.psw.z; /* NH */ - case 4: return sim->cpu.psw.s; /* N */ - case 5: return 1; /* T */ - case 6: return sim->cpu.psw.ov ^ sim->cpu.psw.s; /* LT */ - default:return(sim->cpu.psw.ov^sim->cpu.psw.s)|sim->cpu.psw.z; /* LE */ - } - -} - -/* Check for a floating-point reserved operand */ -static int cpuFloatReserved(VB *sim, int32_t bits) { - uint8_t e = bits >> 23; /* Exponent field */ - - /* Not reserved */ - if (e != 0xFF && (e != 0x00 || (bits & 0x007FFFFF) == 0)) - return 0; - - /* Reserved */ - sim->cpu.causeCode = 0xFF60; - sim->cpu.psw.fro = 1; - return 1; -} - -/* Convert a 32-bit integer to the represented floating-point value */ -static double cpuFloatOperand(VB *sim, int32_t bits) { - return cpuFloatReserved(sim, bits) ? 0 : (double) *(float *) &bits; -} - -/* Convert a floating-point result to bits as a 32-bit integer */ -static int32_t cpuFloatResult(VB *sim, double resultd) { - float resultf; /* 32-bit conversion of result */ - int32_t ret; /* Output value */ - - /* Overflow */ - if (resultd < -FLT_MAX || resultd > FLT_MAX) { - sim->cpu.causeCode = 0xFF64; - sim->cpu.psw.fov = 1; - return 0; - } - - /* Underflow */ - if (resultd > -FLT_MIN && resultd < FLT_MIN) { - sim->cpu.psw.fud = 1; - ret = 0; - } - - /* Normalized */ - else { - resultf = (float) resultd; - ret = *(int32_t *) &resultf; - if (ret == INT32_MIN) - ret = 0; /* Prevent negative zero */ - - /* Precision degradation */ - if (resultf != resultd) - sim->cpu.psw.fpr = 1; - } - - /* Update state */ - sim->cpu.psw.cy = ret < 0; - sim->cpu.psw.ov = 0; - sim->cpu.psw.s = ret < 0; - sim->cpu.psw.z = ret == 0; - return ret; -} - -/* Convert a floating-point value to a word value */ -static void cpuFloatToWord(VB *sim, VB_INSTRUCTION *inst, int truncate) { - int32_t bits = sim->cpu.program[inst->bits[0] & 0x1F]; - int32_t result; /* Output value */ - int32_t x; /* Working variable */ - int32_t y; /* Working variable */ - - /* Zero */ - if ((bits & 0x7FFFFFFF) == 0) - result = 0; - - /* Minimum value */ - else if (bits == (int32_t) 0xCF000000) - result = INT32_MIN; - - /* Conversion */ - else { - x = bits >> 23 & 0xFF; /* Exponent field */ - - /* Reserved operand */ - if (x == 0xFF || x == 0x00) { - sim->cpu.causeCode = 0xFF60; - sim->cpu.psw.fro = 1; - return; - } - - /* Invalid operation */ - if (x >= 158) { - sim->cpu.causeCode = 0xFF70; - sim->cpu.psw.fiv = 1; - return; - } - - /* Parse significand bits */ - result = (bits & 0x007FFFFF) | 0x00800000; - - /* Left shift */ - if (x >= 150) - result <<= x - 150; - - /* Right shift */ - else { - y = result; /* Significant bits */ - x = 150 - x; /* Number of bits to shift */ - result >>= x; /* Update state */ - - /* Precision degradation */ - if ((y & ((1 << x) - 1)) != 0) { - sim->cpu.psw.fpr = 1; - - /* Apply rounding */ - if (!truncate) - result += y >> (x - 1) & 1; - } - - } - - /* Incorporate sign */ - if (bits < 0) - result = -result; - } - - /* Update state */ - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = result; - sim->cpu.psw.ov = 0; - sim->cpu.psw.s = result < 0; - sim->cpu.psw.z = result == 0; - sim->cpu.clocks = 14; -} - -/* Perform a jump */ -static void cpuJump(VB *sim, VB_INSTRUCTION *inst, uint32_t address) { - sim->cpu.pc = address & 0xFFFFFFFE; - sim->cpu.clocks = 3; - inst->size = 0; -} - -/* Perform an input or load */ -static int cpuLoad(VB *sim,VB_INSTRUCTION *inst,uint8_t type,uint32_t clocks) { - - /* Initiate the read */ - if (sim->cpu.busWait == 0) { - - /* Read the data unit from the bus */ - if (cpuRead( - sim, - sim->cpu.program[inst->bits[0] & 0x1F] + - SignExtend((int32_t) inst->bits[1], 16), - type - )) return 1; - - /* Update state */ - sim->cpu.busWait = 1; - sim->cpu.clocks = sim->cpu.access.clocks; - - /* Wait for the bus access to complete */ - if (sim->cpu.clocks > 0) - return 0; - } - - /* Complete the read */ - sim->cpu.busWait = 0; - sim->cpu.clocks = clocks; - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = sim->cpu.access.value; - return 0; -} - -/* Specify a new value for a system register */ -static uint32_t cpuSetSystemRegister(VB *sim,int id,uint32_t value,int debug) { - switch (id) { - case VB_ADTRE: return sim->cpu.adtre = value & 0xFFFFFFFE; - case VB_EIPC : return sim->cpu.eipc = value & 0xFFFFFFFE; - case VB_EIPSW: return sim->cpu.eipsw = value & 0x000FF3FF; - case VB_FEPC : return sim->cpu.fepc = value & 0xFFFFFFFE; - case VB_FEPSW: return sim->cpu.fepsw = value & 0x000FF3FF; - case VB_PIR : return 0x00005346; - case VB_TKCW : return 0x000000E0; - case 29 : return sim->cpu.sr29 = value & 0x00000001; - case 30 : return 0x00000004; - case 31 : - if (!debug && (int32_t) value < 0) - value = ~value + 1; - return sim->cpu.sr31 = value; - case VB_CHCW : - sim->cpu.chcw.ice = value >> 1 & 1; - /* TODO: Perform dump/restore operations */ - return value & 0x00000002; - case VB_ECR : - if (!debug) - return (uint32_t) sim->cpu.ecr.fecc << 16 | sim->cpu.ecr.eicc; - sim->cpu.ecr.fecc = value >> 16; - sim->cpu.ecr.eicc = value; - return value; - case VB_PSW : - sim->cpu.psw.i = value >> 16 & 15; - sim->cpu.psw.np = value >> 15 & 1; - sim->cpu.psw.ep = value >> 14 & 1; - sim->cpu.psw.ae = value >> 13 & 1; - sim->cpu.psw.id = value >> 12 & 1; - sim->cpu.psw.fro = value >> 9 & 1; - sim->cpu.psw.fiv = value >> 8 & 1; - sim->cpu.psw.fzd = value >> 7 & 1; - sim->cpu.psw.fov = value >> 6 & 1; - sim->cpu.psw.fud = value >> 5 & 1; - sim->cpu.psw.fpr = value >> 4 & 1; - sim->cpu.psw.cy = value >> 3 & 1; - sim->cpu.psw.ov = value >> 2 & 1; - sim->cpu.psw.s = value >> 1 & 1; - sim->cpu.psw.z = value & 1; - return value & 0x000FF3FF; - } - return 0; -} - -/* Perform a right shift */ -static int cpuShiftRight(VB *sim, int32_t value, int bits, int arithmetic) { - if (bits != 0) { - sim->cpu.psw.cy = (value >> (bits - 1)) & 1; - value = value >> bits & (((uint32_t) 1 << (32 - bits)) - 1); - if (arithmetic) - value = SignExtend(value, 32 - bits); - } else sim->cpu.psw.cy = 0; - return cpuBitwise(sim, value); -} - -/* Perform an output or store */ -static int cpuStore(VB *sim,VB_INSTRUCTION *inst,uint8_t type,uint32_t clocks){ - - /* Initiate the write */ - if (sim->cpu.busWait == 0) { - - /* Write the data unit to the bus */ - if (cpuWrite( - sim, - sim->cpu.program[inst->bits[0] & 0x1F] + - SignExtend((int32_t) inst->bits[1], 16), - type, - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] - )) return 1; - - /* Update state */ - sim->cpu.busWait = 1; - sim->cpu.clocks = sim->cpu.access.clocks; - - /* Wait for the bus access to complete */ - if (sim->cpu.clocks > 0) - return 0; - } - - /* Complete the write */ - sim->cpu.busWait = 0; - sim->cpu.clocks = clocks; - return 0; -} - -/* Subtract two numbers and update the flags */ -static int32_t cpuSubtract(VB *sim, int32_t left, int32_t right) { - int32_t result = left - right; - sim->cpu.clocks = 1; - sim->cpu.psw.cy = (uint32_t) result > (uint32_t) left; - sim->cpu.psw.ov = ((left ^ right) & (left ^ result)) >> 31 & 1; - sim->cpu.psw.s = result < 0; - sim->cpu.psw.z = result == 0; - return result; -} - - - -/************************ Instruction Implementations ************************/ - -/* Add Immediate */ -static void cpuADD_IMM(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - int32_t right = inst->bits[0] & 0x1F; - *reg2 = cpuAdd(sim, *reg2, SignExtend(right, 5)); -} - -/* Add Register */ -static void cpuADD_REG(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - *reg2 = cpuAdd(sim, *reg2, sim->cpu.program[inst->bits[0] & 0x1F]); -} - -/* Add Floating Short */ -static void cpuADDF_S(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - double left = cpuFloatOperand(sim, *reg2); - double right = cpuFloatOperand(sim,sim->cpu.program[inst->bits[0]&0x1F]); - int32_t result; /* Output bits */ - - /* Perform the operation */ - if (sim->cpu.causeCode == 0) - result = cpuFloatResult(sim, left + right); - if (sim->cpu.causeCode != 0) - return; - - /* Update state */ - *reg2 = result; - sim->cpu.clocks = 28; -} - -/* Add Immediate */ -static void cpuADDI(VB *sim, VB_INSTRUCTION *inst) { - int32_t right = inst->bits[1]; - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = cpuAdd(sim, - sim->cpu.program[inst->bits[0] & 0x1F], SignExtend(right, 16)); -} - -/* And */ -static void cpuAND(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - *reg2 = cpuBitwise(sim, *reg2 & sim->cpu.program[inst->bits[0] & 0x1F]); -} - -/* And Bit String Upward */ -#define cpuANDBSU(sim, inst) cpuBitString(sim, inst) - -/* And Immediate */ -static void cpuANDI(VB *sim, VB_INSTRUCTION *inst) { - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = cpuBitwise(sim, - sim->cpu.program[inst->bits[0] & 0x1F] & inst->bits[1]); -} - -/* And Not Bit String Upward */ -#define cpuANDNBSU(sim, inst) cpuBitString(sim, inst) - -/* Conditional Branch */ -static void cpuBCOND(VB *sim, VB_INSTRUCTION *inst) { - int32_t disp; /* Target address displacement */ - - /* Branch to the target address */ - if (cpuCondition(sim, inst->bits[0] >> 9 & 15)) { - disp = inst->bits[0] & 0x1FF; - cpuJump(sim, inst, sim->cpu.pc + SignExtend(disp, 9)); - } - - /* Do not branch */ - else sim->cpu.clocks = 1; -} - -/* Compare And Exchahge Interlocked */ -static int cpuCAXI(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2; /* Program register reg2 */ - - /* Read the lock word */ - if (sim->cpu.busWait == 0) { - - /* Compute the address of the lock word */ - inst->aux[0] = sim->cpu.program[inst->bits[0] & 0x1F] + - SignExtend((int32_t) inst->bits[1], 16); - - /* Read the data unit from the bus */ - if (cpuRead(sim, inst->aux[0], VB_S32)) - return 1; - - /* Update state */ - sim->cpu.busWait = 1; - sim->cpu.clocks = sim->cpu.access.clocks; - - /* Wait for the bus access to complete */ - if (sim->cpu.clocks > 0) - return 0; - } - - /* Compare and exchange */ - if (sim->cpu.busWait == 1) { - - /* Process the lock word */ - reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - cpuSubtract(sim, *reg2, sim->cpu.access.value); - *reg2 = sim->cpu.access.value; - - /* Store the exchange value to the bus */ - if (cpuWrite(sim, inst->aux[0], VB_S32, - sim->cpu.psw.z ? sim->cpu.program[30] : sim->cpu.access.value)) - return 1; - - /* Update state */ - sim->cpu.clocks = sim->cpu.access.clocks; - sim->cpu.busWait = 2; - - /* Wait for the bus access to complete */ - if (sim->cpu.clocks > 0) - return 0; - } - - /* Update state */ - sim->cpu.busWait = 0; - sim->cpu.clocks = 26; - return 0; -} - -/* Clear Interrupt Disable Flag */ -static void cpuCLI(VB *sim) { - sim->cpu.psw.id = 0; - sim->cpu.clocks = 12; -} - -/* Compare Immediate */ -static void cpuCMP_IMM(VB *sim, VB_INSTRUCTION *inst) { - int32_t right = inst->bits[0] & 0x1F; - cpuSubtract(sim, sim->cpu.program[inst->bits[0] >> 5 & 0x1F], - SignExtend(right, 5)); -} - -/* Compare Register */ -static void cpuCMP_REG(VB *sim, VB_INSTRUCTION *inst) { - cpuSubtract(sim, sim->cpu.program[inst->bits[0] >> 5 & 0x1F], - sim->cpu.program[inst->bits[0] & 0x1F]); -} - -/* Compare Floating Short */ -static void cpuCMPF_S(VB *sim, VB_INSTRUCTION *inst) { - double left =cpuFloatOperand(sim,sim->cpu.program[inst->bits[0]>>5&0x1F]); - double right=cpuFloatOperand(sim,sim->cpu.program[inst->bits[0] &0x1F]); - - /* Perform the operation */ - if (sim->cpu.causeCode == 0) - cpuFloatResult(sim, left - right); - if (sim->cpu.causeCode != 0) - return; - - /* Update state */ - sim->cpu.clocks = 10; -} - -/* Convert Short Floating to Word Integer */ -#define cpuCVT_SW(sim, inst) cpuFloatToWord(sim, inst, 0) - -/* Convert Word Integer to Short Floating */ -static void cpuCVT_WS(VB *sim, VB_INSTRUCTION *inst) { - int32_t value = sim->cpu.program[inst->bits[0] & 0x1F]; - float result = (float) value; - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = *(int32_t *) &result; - if (result != value) - sim->cpu.psw.fpr = 1; - sim->cpu.psw.cy = result < 0; - sim->cpu.psw.ov = 0; - sim->cpu.psw.s = result < 0; - sim->cpu.psw.z = result == 0; - sim->cpu.clocks = 16; -} - -/* Divide */ -static void cpuDIV(VB *sim, VB_INSTRUCTION *inst) { - int32_t right = sim->cpu.program[inst->bits[0] & 0x1F]; - int32_t *r30; /* Program register r30 */ - int32_t *reg2; /* Program register reg2 */ - - /* Zero division */ - if (right == 0) { - sim->cpu.causeCode = 0xFF80; - return; - } - - /* Special case */ - reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - if (*reg2 == INT32_MIN && right == -1) { - sim->cpu.program[30] = 0; - sim->cpu.psw.ov = 1; - } - - /* Perform the operation */ - else { - r30 = &sim->cpu.program[30]; - *r30 = *reg2 % right; - if ((*r30 ^ *reg2) < 0) - *r30 = -*r30; - *reg2 /= right; - sim->cpu.psw.ov = 0; - } - - /* Update state */ - sim->cpu.psw.s = *reg2 < 0; - sim->cpu.psw.z = *reg2 == 0; - sim->cpu.clocks = 38; -} - -/* Divide Floating Short */ -static void cpuDIVF_S(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - double left = cpuFloatOperand(sim, *reg2); - double right = cpuFloatOperand(sim,sim->cpu.program[inst->bits[0]&0x1F]); - int32_t result; /* Output bits */ - - /* Reserved operand */ - if (sim->cpu.causeCode != 0) - return; - - /* Zero division */ - if (right == 0) { - - /* Invalid operation */ - if (left == 0) { - sim->cpu.causeCode = 0xFF70; - sim->cpu.psw.fiv = 1; - } - - /* Zero division */ - else { - sim->cpu.causeCode = 0xFF68; - sim->cpu.psw.fzd = 1; - } - - return; - } - - /* Perform the operation */ - result = cpuFloatResult(sim, left / right); - if (sim->cpu.causeCode != 0) - return; - - /* Update state */ - *reg2 = result; - sim->cpu.clocks = 44; -} - -/* Divide Unsigned */ -static void cpuDIVU(VB *sim, VB_INSTRUCTION *inst) { - uint32_t right = sim->cpu.program[inst->bits[0] & 0x1F]; - uint32_t *reg2; /* Program register reg2 */ - - /* Zero division */ - if (right == 0) { - sim->cpu.causeCode = 0xFF80; - return; - } - - /* Perform the operation */ - reg2 = (uint32_t *) &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - sim->cpu.program[30] = *reg2 % right; - *reg2 /= right; - - /* Update state */ - sim->cpu.psw.ov = 0; - sim->cpu.psw.s = *reg2 >> 31 & 1; - sim->cpu.psw.z = *reg2 == 0; - sim->cpu.clocks = 36; -} - -/* Halt */ -static void cpuHALT(VB *sim) { - sim->cpu.state = CPU_HALTED; - /* sim->cpu.clocks = ? */ -} - -/* Input Byte */ -#define cpuIN_B(sim, inst) cpuLoad(sim, inst, VB_U8, 5) - -/* Input Halfword */ -#define cpuIN_H(sim, inst) cpuLoad(sim, inst, VB_U16, 5) - -/* Input Word */ -#define cpuIN_W(sim, inst) cpuLoad(sim, inst, VB_S32, 5) - -/* Jump and Link */ -static void cpuJAL(VB *sim, VB_INSTRUCTION *inst) { - int32_t disp = ((int32_t) inst->bits[0]<<16 | inst->bits[1]) & 0x03FFFFFF; - sim->cpu.program[31] = sim->cpu.pc + 4; - cpuJump(sim, inst, sim->cpu.pc + SignExtend(disp, 26)); -} - -/* Jump Register */ -#define cpuJMP(sim,inst) cpuJump(sim,inst,sim->cpu.program[inst->bits[0]&0x1F]) - -/* Jump Relative */ -static void cpuJR(VB *sim, VB_INSTRUCTION *inst) { - int32_t disp = ((int32_t) inst->bits[0]<<16 | inst->bits[1]) & 0x03FFFFFF; - cpuJump(sim, inst, sim->cpu.pc + SignExtend(disp, 26)); -} - -/* Load Byte */ -#define cpuLD_B(sim, inst) cpuLoad(sim, inst, VB_S8, 5) - -/* Load Halfword */ -#define cpuLD_H(sim, inst) cpuLoad(sim, inst, VB_S16, 5) - -/* Load Word */ -#define cpuLD_W(sim, inst) cpuLoad(sim, inst, VB_S32, 5) - -/* Load to System Register */ -static void cpuLDSR(VB *sim, VB_INSTRUCTION *inst) { - cpuSetSystemRegister(sim, inst->bits[0] & 0x1F, - sim->cpu.program[inst->bits[0] >> 5 & 0x1F], 0); - sim->cpu.clocks = 8; -} - -/* Move Immediate */ -static void cpuMOV_IMM(VB *sim, VB_INSTRUCTION *inst) { - int32_t value = inst->bits[0] & 0x1F; - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = SignExtend(value, 5); - sim->cpu.clocks = 1; -} - -/* Move Register */ -static void cpuMOV_REG(VB *sim, VB_INSTRUCTION *inst) { - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = - sim->cpu.program[inst->bits[0] & 0x1F]; - sim->cpu.clocks = 1; -} - -/* Move Bit String Upward */ -#define cpuMOVBSU(sim, inst) cpuBitString(sim, inst) - -/* Add */ -static void cpuMOVEA(VB *sim, VB_INSTRUCTION *inst) { - int32_t right = inst->bits[1]; - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = - sim->cpu.program[inst->bits[0] & 0x1F] + SignExtend(right, 16); - sim->cpu.clocks = 1; -} - -/* Add */ -static void cpuMOVHI(VB *sim, VB_INSTRUCTION *inst) { - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = - sim->cpu.program[inst->bits[0] & 0x1F] + ((int32_t)inst->bits[1]<<16); - sim->cpu.clocks = 1; -} - -/* Multiply Halfword */ -static void cpuMPYHW(VB *sim, VB_INSTRUCTION *inst) { - int32_t right = sim->cpu.program[inst->bits[0] & 0x1F] & 0x0001FFFF; - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] *= SignExtend(right, 17); - sim->cpu.clocks = 9; -} - -/* Multiply */ -static void cpuMUL(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - int64_t result = (int64_t) *reg2 * - sim->cpu.program[inst->bits[0] & 0x1F]; - sim->cpu.program[30] = result >> 32; - *reg2 = result; - sim->cpu.psw.ov = *reg2 != result; - sim->cpu.psw.s = *reg2 < 0; - sim->cpu.psw.z = *reg2 == 0; - sim->cpu.clocks = 13; -} - -/* Multiply Floating Short */ -static void cpuMULF_S(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - double left = cpuFloatOperand(sim, *reg2); - double right = cpuFloatOperand(sim,sim->cpu.program[inst->bits[0]&0x1F]); - int32_t result; /* Output bits */ - - /* Perform the operation */ - if (sim->cpu.causeCode == 0) - result = cpuFloatResult(sim, left * right); - if (sim->cpu.causeCode != 0) - return; - - /* Update state */ - *reg2 = result; - sim->cpu.clocks = 30; -} - -/* Multiply Unsigned */ -static void cpuMULU(VB *sim, VB_INSTRUCTION *inst) { - uint32_t *reg2 = (uint32_t *) &sim->cpu.program[inst->bits[0]>>5&0x1F]; - uint64_t result = (uint64_t) *reg2 * - (uint32_t) sim->cpu.program[inst->bits[0] & 0x1F]; - sim->cpu.program[30] = result >> 32; - *reg2 = result; - sim->cpu.psw.ov = *reg2 != result; - sim->cpu.psw.s = *reg2 >> 31 & 1; - sim->cpu.psw.z = *reg2 == 0; - sim->cpu.clocks = 13; -} - -/* Not */ -static void cpuNOT(VB *sim, VB_INSTRUCTION *inst) { - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = - cpuBitwise(sim, ~sim->cpu.program[inst->bits[0] & 0x1F]); -} - -/* Not Bit String Upward */ -#define cpuNOTBSU(sim, inst) cpuBitString(sim, inst) - -/* Or */ -static void cpuOR(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - *reg2 = cpuBitwise(sim, *reg2 | sim->cpu.program[inst->bits[0] & 0x1F]); -} - -/* Or Bit String Upward */ -#define cpuORBSU(sim, inst) cpuBitString(sim, inst) - -/* Or Immediate */ -static void cpuORI(VB *sim, VB_INSTRUCTION *inst) { - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = cpuBitwise(sim, - sim->cpu.program[inst->bits[0] & 0x1F] | inst->bits[1]); -} - -/* Or Not Bit String Upward */ -#define cpuORNBSU(sim, inst) cpuBitString(sim, inst) - -/* Output Byte */ -#define cpuOUT_B(sim, inst) cpuStore(sim, inst, VB_U8, 4) - -/* Output Halfword */ -#define cpuOUT_H(sim, inst) cpuStore(sim, inst, VB_U16, 4) - -/* Output Word */ -#define cpuOUT_W(sim, inst) cpuStore(sim, inst, VB_S32, 4) - -/* Return from Trap or Interrupt */ -static void cpuRETI(VB *sim, VB_INSTRUCTION *inst) { - - /* Duplexed exception */ - if (sim->cpu.psw.np) { - sim->cpu.pc = sim->cpu.fepc; - cpuSetSystemRegister(sim, VB_PSW, sim->cpu.fepsw, 0); - } - - /* Non-duplexed exception */ - else { - sim->cpu.pc = sim->cpu.eipc; - cpuSetSystemRegister(sim, VB_PSW, sim->cpu.eipsw, 0); - } - - /* Update state */ - sim->cpu.clocks = 10; - inst->size = 0; -} - -/* Reverse Bits in Word */ -static void cpuREV(VB *sim, VB_INSTRUCTION *inst) { - int32_t value = sim->cpu.program[inst->bits[0] & 0x1F]; - value = (value >> 16 & 0x0000FFFF) | (value << 16 & (int32_t) 0xFFFF0000); - value = (value >> 8 & 0x00FF00FF) | (value << 8 & (int32_t) 0xFF00FF00); - value = (value >> 4 & 0x0F0F0F0F) | (value << 4 & (int32_t) 0xF0F0F0F0); - value = (value >> 2 & 0x33333333) | (value << 2 & (int32_t) 0xCCCCCCCC); - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = - (value >> 1 & 0x55555555) | (value << 1 & (int32_t) 0xAAAAAAAA); - sim->cpu.clocks = 22; -} - -/* Shift Arithmetic Right by Immediate */ -static void cpuSAR_IMM(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - *reg2 = cpuShiftRight(sim, *reg2, inst->bits[0] & 0x1F, 1); -} - -/* Shift Arithmetic Right by Register */ -static void cpuSAR_REG(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - *reg2 = cpuShiftRight(sim, *reg2, - sim->cpu.program[inst->bits[0] & 0x1F] & 0x1F, 1); -} - -/* Search Bit 0 Downward */ -#define cpuSCH0BSD(sim) cpuBitSearch(sim, 0, -1) - -/* Search Bit 0 Upward */ -#define cpuSCH0BSU(sim) cpuBitSearch(sim, 0, 1) - -/* Search Bit 1 Downward */ -#define cpuSCH1BSD(sim) cpuBitSearch(sim, 1, -1) - -/* Search Bit 1 Upward */ -#define cpuSCH1BSU(sim) cpuBitSearch(sim, 1, 1) - -/* Set Interrupt Disable Flag */ -static void cpuSEI(VB *sim) { - sim->cpu.psw.id = 1; - sim->cpu.clocks = 12; -} - -/* Set Flag Condition */ -static void cpuSETF(VB *sim, VB_INSTRUCTION *inst) { - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = - cpuCondition(sim, inst->bits[0] & 15); - sim->cpu.clocks = 1; -} - -/* Shift Logical Left by Immediate */ -static void cpuSHL_IMM(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - int32_t bits = inst->bits[0] & 0x1F; - sim->cpu.psw.cy = bits == 0 ? 0 : *reg2 >> (32 - bits) & 1; - *reg2 = cpuBitwise(sim, *reg2 << bits); -} - -/* Shift Logical Left by Register */ -static void cpuSHL_REG(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - int32_t bits = sim->cpu.program[inst->bits[0] & 0x1F] & 0x1F; - sim->cpu.psw.cy = bits == 0 ? 0 : *reg2 >> (32 - bits) & 1; - *reg2 = cpuBitwise(sim, *reg2 << bits); -} - -/* Shift Logical Right by Immediate */ -static void cpuSHR_IMM(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - *reg2 = cpuShiftRight(sim, *reg2, inst->bits[0] & 0x1F, 0); -} - -/* Shift Logical Right by Register */ -static void cpuSHR_REG(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - *reg2 = cpuShiftRight(sim, *reg2, - sim->cpu.program[inst->bits[0] & 0x1F] & 0x1F, 0); -} - -/* Store Byte */ -#define cpuST_B(sim, inst) cpuStore(sim, inst, VB_S8, 4) - -/* Store Halfword */ -#define cpuST_H(sim, inst) cpuStore(sim, inst, VB_S16, 4) - -/* Store Word */ -#define cpuST_W(sim, inst) cpuStore(sim, inst, VB_S32, 4) - -/* Store Contents of System Register */ -static void cpuSTSR(VB *sim, VB_INSTRUCTION *inst) { - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = - vbGetSystemRegister(sim, inst->bits[0] & 0x1F); - sim->cpu.clocks = 8; -} - -/* Subtract */ -static void cpuSUB(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - *reg2 = cpuSubtract(sim, *reg2, sim->cpu.program[inst->bits[0] & 0x1F]); -} - -/* Subtract Floating Short */ -static void cpuSUBF_S(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - double left = cpuFloatOperand(sim, *reg2); - double right = cpuFloatOperand(sim,sim->cpu.program[inst->bits[0]&0x1F]); - int32_t result; /* Output bits */ - - /* Perform the operation */ - if (sim->cpu.causeCode == 0) - result = cpuFloatResult(sim, left - right); - if (sim->cpu.causeCode != 0) - return; - - /* Update state */ - *reg2 = result; - sim->cpu.clocks = 28; -} - -/* Trap */ -static void cpuTRAP(VB *sim, VB_INSTRUCTION *inst) { - sim->cpu.causeCode = 0xFFA0 + (inst->bits[0] & 0x1F); - sim->cpu.clocks = 15; - sim->cpu.pc += 2; -} - -/* Truncate Short Floating to Word Integer */ -#define cpuTRNC_SW(sim, inst) cpuFloatToWord(sim, inst, 1) - -/* Exchange Byte */ -static void cpuXB(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - *reg2 = - (*reg2 >> 8 & (int32_t) 0x000000FF) | - (*reg2 << 8 & (int32_t) 0x0000FF00) | - (*reg2 & (int32_t) 0xFFFF0000) - ; - sim->cpu.clocks = 6; -} - -/* Exchange Halfword */ -static void cpuXH(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - *reg2 = (*reg2 >> 16 & 0x0000FFFF) | *reg2 << 16; - sim->cpu.clocks = 1; -} - -/* Exclusive Or */ -static void cpuXOR(VB *sim, VB_INSTRUCTION *inst) { - int32_t *reg2 = &sim->cpu.program[inst->bits[0] >> 5 & 0x1F]; - *reg2 = cpuBitwise(sim, *reg2 ^ sim->cpu.program[inst->bits[0] & 0x1F]); -} - -/* Exclusive Or Bit String Upward */ -#define cpuXORBSU(sim, inst) cpuBitString(sim, inst) - -/* Exclusive Or Immediate */ -static void cpuXORI(VB *sim, VB_INSTRUCTION *inst) { - sim->cpu.program[inst->bits[0] >> 5 & 0x1F] = cpuBitwise(sim, - sim->cpu.program[inst->bits[0] & 0x1F] ^ inst->bits[1]); -} - -/* Exclusive Or Not Bit String Upward */ -#define cpuXORNBSU(sim, inst) cpuBitString(sim, inst) - - - -/***************************** Module Functions ******************************/ - -/* Check for interrupts */ -static int cpuCheckIRQs(VB *sim) { +/* Check for an interrupt exception condition */ +static int cpuCheckIRQs(VB *vb) { int x; /* Iterator */ /* Interrupts are masked */ - if (sim->cpu.psw.np || sim->cpu.psw.ep || sim->cpu.psw.id) + if (vb->cpu.psw.id || vb->cpu.psw.ep || vb->cpu.psw.np) return 0; - /* Check for interrupts */ - for (x = 4; x >= sim->cpu.psw.i; x--) { - - /* The interrupt request line is low */ - if (!sim->cpu.irq[x]) + /* Check for interrupt requests */ + for (x = 4; x >= vb->cpu.psw.i; x--) { + if (!vb->cpu.irq[x]) continue; - - /* Cause a pending HALT instruction to complete */ - if (sim->cpu.state == CPU_HALTED) - sim->cpu.pc += 2; - - /* Trigger an interrupt */ - sim->cpu.causeCode = 0xFE00 | x << 4; - sim->cpu.state = CPU_EXCEPTION; + vb->cpu.exception = 0xFE00 | x << 4; return 1; } @@ -1382,323 +62,1588 @@ static int cpuCheckIRQs(VB *sim) { return 0; } -/* Perform instruction execute operations */ -static int cpuExecute(VB *sim) { - int broke; /* Application break occurred */ - VB_INSTRUCTION *inst; /* Shorthand reference */ +/* Test a condition */ +static int cpuCondition(VB *vb, int index) { + switch (index) { + case 0: return vb->cpu.psw.ov; /* V */ + case 1: return vb->cpu.psw.cy; /* C, L */ + case 2: return vb->cpu.psw.z; /* E, Z */ + case 3: return vb->cpu.psw.cy | vb->cpu.psw.z; /* NH */ + case 4: return vb->cpu.psw.s; /* N */ + case 5: return 1; /* T */ + case 6: return vb->cpu.psw.ov ^ vb->cpu.psw.s; /* LT */ + case 7: return (vb->cpu.psw.ov^vb->cpu.psw.s)|vb->cpu.psw.z; /* LE */ + } + return !cpuCondition(vb, index - 8); +} - /* Check for address trap */ - if (sim->cpu.psw.ae && sim->cpu.adtre == sim->cpu.pc) { - sim->cpu.causeCode = 0xFFC0; - sim->cpu.state = CPU_EXCEPTION; - return 0; +/* Retrieve the value of a system register */ +static uint32_t cpuGetSystemRegister(VB *vb, int id) { + switch (id) { + case VB_ADTRE: return vb->cpu.adtre; + case VB_EIPC : return vb->cpu.eipc; + case VB_EIPSW: return vb->cpu.eipsw; + case VB_FEPC : return vb->cpu.fepc; + case VB_FEPSW: return vb->cpu.fepsw; + case VB_PIR : return 0x00005346; + case VB_TKCW : return 0x000000E0; + case 29 : return vb->cpu.sr29; + case 30 : return 0x00000004; + case 31 : return vb->cpu.sr31; + case VB_CHCW : return + (uint32_t) vb->cpu.chcw.ice << 1 + ; + case VB_ECR : return + (uint32_t) vb->cpu.ecr.fecc << 16 | + (uint32_t) vb->cpu.ecr.eicc + ; + case VB_PSW : return + (uint32_t) vb->cpu.psw.i << 16 | + (uint32_t) vb->cpu.psw.np << 15 | + (uint32_t) vb->cpu.psw.ep << 14 | + (uint32_t) vb->cpu.psw.ae << 13 | + (uint32_t) vb->cpu.psw.id << 12 | + (uint32_t) vb->cpu.psw.fro << 9 | + (uint32_t) vb->cpu.psw.fiv << 8 | + (uint32_t) vb->cpu.psw.fzd << 7 | + (uint32_t) vb->cpu.psw.fov << 6 | + (uint32_t) vb->cpu.psw.fud << 5 | + (uint32_t) vb->cpu.psw.fpr << 4 | + (uint32_t) vb->cpu.psw.cy << 3 | + (uint32_t) vb->cpu.psw.ov << 2 | + (uint32_t) vb->cpu.psw.s << 1 | + (uint32_t) vb->cpu.psw.z + ; + } + return 0; /* Invalid ID */ +} + +/* Read a memory value from the bus */ +static int cpuRead(VB *vb, uint32_t address, int type, int32_t *value) { + VBAccess access; /* Bus access descriptor */ + + /* Retrieve the value from the simulation state */ + access.clocks = 0; /* TODO: Needs research */ + access.value = busRead(vb, address, type); + + /* Call the breakpoint handler */ + if (vb->onRead != NULL) { + access.address = address; + access.type = type; + if (vb->onRead(vb, &access)) + return 1; } - /* Prepare state */ - sim->cpu.causeCode = 0; - inst = &sim->cpu.inst; + /* Post-processing */ + vb->cpu.clocks += access.clocks; + *value = access.value; + return 0; +} - /* Check for application break */ - if (sim->onExecute != NULL && sim->onExecute(sim, inst)) - return 1; +/* Fetch an instruction code unit from the bus */ +static int cpuReadFetch(VB *vb) { + VBAccess access; /* Bus access descriptor */ - /* Processing by ID */ - broke = 0; - switch (inst->id) { - case CPU_ADD_IMM: cpuADD_IMM(sim, inst); break; - case CPU_ADD_REG: cpuADD_REG(sim, inst); break; - case CPU_ADDF_S : cpuADDF_S (sim, inst); break; - case CPU_ADDI : cpuADDI (sim, inst); break; - case CPU_AND : cpuAND (sim, inst); break; - case CPU_ANDBSU : broke = cpuANDBSU (sim, inst); break; - case CPU_ANDI : cpuANDI (sim, inst); break; - case CPU_ANDNBSU: broke = cpuANDNBSU(sim, inst); break; - case CPU_BCOND : cpuBCOND (sim, inst); break; - case CPU_CAXI : broke = cpuCAXI (sim, inst); break; - case CPU_CLI : cpuCLI (sim ); break; - case CPU_CMP_IMM: cpuCMP_IMM(sim, inst); break; - case CPU_CMP_REG: cpuCMP_REG(sim, inst); break; - case CPU_CMPF_S : cpuCMPF_S (sim, inst); break; - case CPU_CVT_SW : cpuCVT_SW (sim, inst); break; - case CPU_CVT_WS : cpuCVT_WS (sim, inst); break; - case CPU_DIV : cpuDIV (sim, inst); break; - case CPU_DIVF_S : cpuDIVF_S (sim, inst); break; - case CPU_DIVU : cpuDIVU (sim, inst); break; - case CPU_HALT : cpuHALT (sim ); break; - case CPU_IN_B : broke = cpuIN_B (sim, inst); break; - case CPU_IN_H : broke = cpuIN_H (sim, inst); break; - case CPU_IN_W : broke = cpuIN_W (sim, inst); break; - case CPU_JAL : cpuJAL (sim, inst); break; - case CPU_JMP : cpuJMP (sim, inst); break; - case CPU_JR : cpuJR (sim, inst); break; - case CPU_LD_B : broke = cpuLD_B (sim, inst); break; - case CPU_LD_H : broke = cpuLD_H (sim, inst); break; - case CPU_LD_W : broke = cpuLD_W (sim, inst); break; - case CPU_LDSR : cpuLDSR (sim, inst); break; - case CPU_MOV_IMM: cpuMOV_IMM(sim, inst); break; - case CPU_MOV_REG: cpuMOV_REG(sim, inst); break; - case CPU_MOVBSU : broke = cpuMOVBSU (sim, inst); break; - case CPU_MOVEA : cpuMOVEA (sim, inst); break; - case CPU_MOVHI : cpuMOVHI (sim, inst); break; - case CPU_MPYHW : cpuMPYHW (sim, inst); break; - case CPU_MUL : cpuMUL (sim, inst); break; - case CPU_MULF_S : cpuMULF_S (sim, inst); break; - case CPU_MULU : cpuMULU (sim, inst); break; - case CPU_NOT : cpuNOT (sim, inst); break; - case CPU_NOTBSU : broke = cpuNOTBSU (sim, inst); break; - case CPU_OR : cpuOR (sim, inst); break; - case CPU_ORBSU : broke = cpuORBSU (sim, inst); break; - case CPU_ORI : cpuORI (sim, inst); break; - case CPU_ORNBSU : broke = cpuORNBSU (sim, inst); break; - case CPU_OUT_B : broke = cpuOUT_B (sim, inst); break; - case CPU_OUT_H : broke = cpuOUT_H (sim, inst); break; - case CPU_OUT_W : broke = cpuOUT_W (sim, inst); break; - case CPU_RETI : cpuRETI (sim, inst); break; - case CPU_REV : cpuREV (sim, inst); break; - case CPU_SAR_IMM: cpuSAR_IMM(sim, inst); break; - case CPU_SAR_REG: cpuSAR_REG(sim, inst); break; - case CPU_SCH0BSD: cpuSCH0BSD(sim ); break; - case CPU_SCH0BSU: cpuSCH0BSU(sim ); break; - case CPU_SCH1BSD: cpuSCH1BSD(sim ); break; - case CPU_SCH1BSU: cpuSCH1BSU(sim ); break; - case CPU_SEI : cpuSEI (sim ); break; - case CPU_SETF : cpuSETF (sim, inst); break; - case CPU_SHL_IMM: cpuSHL_IMM(sim, inst); break; - case CPU_SHL_REG: cpuSHL_REG(sim, inst); break; - case CPU_SHR_IMM: cpuSHR_IMM(sim, inst); break; - case CPU_SHR_REG: cpuSHR_REG(sim, inst); break; - case CPU_ST_B : broke = cpuST_B (sim, inst); break; - case CPU_ST_H : broke = cpuST_H (sim, inst); break; - case CPU_ST_W : broke = cpuST_W (sim, inst); break; - case CPU_STSR : cpuSTSR (sim, inst); break; - case CPU_SUB : cpuSUB (sim, inst); break; - case CPU_SUBF_S : cpuSUBF_S (sim, inst); break; - case CPU_TRAP : cpuTRAP (sim, inst); break; - case CPU_TRNC_SW: cpuTRNC_SW(sim, inst); break; - case CPU_XB : cpuXB (sim, inst); break; - case CPU_XH : cpuXH (sim, inst); break; - case CPU_XOR : cpuXOR (sim, inst); break; - case CPU_XORBSU : broke = cpuXORBSU (sim, inst); break; - case CPU_XORI : cpuXORI (sim, inst); break; - case CPU_XORNBSU: broke = cpuXORNBSU(sim, inst); break; - default: /* CPU_ILLEGAL */ sim->cpu.causeCode = 0xFF90; + /* Retrieve the value from the simulation state */ + access.address = vb->cpu.pc + (vb->cpu.step << 1); + access.clocks = 0; /* TODO: Prefetch makes this tricky */ + access.value = busRead(vb, access.address, VB_U16); + + /* Call the breakpoint handler */ + if (vb->onFetch != NULL) { + access.type = VB_U16; + if (vb->onFetch(vb, vb->cpu.step, &access)) + return 1; } - /* Instructions cannot modify r0 */ - sim->cpu.program[0] = 0x00000000; + /* Post-processing */ + vb->cpu.clocks += access.clocks; + vb->cpu.inst.code[vb->cpu.step++] = access.value; + return 0; +} - /* An application break was requested */ - if (broke) - return 1; +/* Detect a floating-point reserved operand */ +#define cpuFRO(x) ( \ + ( \ + ((x) & 0x007FFFFF) != 0x00000000 && /* Is not zero */ \ + ((x) & 0x7F800000) == 0x00000000 /* Is denormal */ \ + ) || ((x) & 0x7F800000) == 0x7F800000 /* Is indefinite/NaN */ \ +) - /* Post-instruction tasks */ - if (sim->cpu.causeCode == 0 && sim->cpu.busWait == 0) { +/* Specify a value for a system register */ +static uint32_t cpuSetSystemRegister(VB *vb,int id,uint32_t value,int debug) { + switch (id) { + case VB_ADTRE: return vb->cpu.adtre = value & 0xFFFFFFFE; + case VB_EIPC : return vb->cpu.eipc = value & 0xFFFFFFFE; + case VB_EIPSW: return vb->cpu.eipsw = value & 0x000FF3FF; + case VB_FEPC : return vb->cpu.fepc = value & 0xFFFFFFFE; + case VB_FEPSW: return vb->cpu.fepsw = value & 0x000FF3FF; + case VB_PIR : return 0x00005346; + case VB_TKCW : return 0x000000E0; + case 29 : return vb->cpu.sr29 = value; + case 30 : return 0x00000004; + case 31 : return + vb->cpu.sr31 = debug || value < (uint32_t) 0x80000000 ? + value : (uint32_t) -(int32_t)value; + case VB_CHCW: + /* TODO: Manage cache functions */ + vb->cpu.chcw.ice = value >> 1 & 1; + return value & 0x00000002; + case VB_ECR: + if (debug) { + vb->cpu.ecr.fecc = value >> 16 & 0xFFFF; + vb->cpu.ecr.eicc = value & 0xFFFF; + } + return (uint32_t) vb->cpu.ecr.fecc << 16 | vb->cpu.ecr.eicc; + case VB_PSW: + vb->cpu.psw.i = value >> 16 & 15; + vb->cpu.psw.np = value >> 15 & 1; + vb->cpu.psw.ep = value >> 14 & 1; + vb->cpu.psw.ae = value >> 13 & 1; + vb->cpu.psw.id = value >> 12 & 1; + vb->cpu.psw.fro = value >> 9 & 1; + vb->cpu.psw.fiv = value >> 8 & 1; + vb->cpu.psw.fzd = value >> 7 & 1; + vb->cpu.psw.fov = value >> 6 & 1; + vb->cpu.psw.fud = value >> 5 & 1; + vb->cpu.psw.fpr = value >> 4 & 1; + vb->cpu.psw.cy = value >> 3 & 1; + vb->cpu.psw.ov = value >> 2 & 1; + vb->cpu.psw.s = value >> 1 & 1; + vb->cpu.psw.z = value & 1; + return value & 0x000FF3FF; + } + return 0; /* Invalid ID */ +} - /* Advance to next instruction */ - if (sim->cpu.state != CPU_HALTED && !sim->cpu.substring) - sim->cpu.pc += inst->size; +/* Prepare to write a memory value to the bus */ +static int cpuWritePre(VB *vb,uint32_t *address,int32_t *type,int32_t *value) { + VBAccess access; /* Bus access descriptor */ - /* Check for interrupts */ - cpuCheckIRQs(sim); + /* Determine how many clocks the access will take */ + access.clocks = 0; /* TODO: Needs research */ + + /* Call the breakpoint handler */ + if (vb->onWrite != NULL) { + + /* Query the application */ + access.address = *address; + access.value = *value; + access.type = *type; + if (vb->onWrite(vb, &access)) + return 1; + + /* Apply changes */ + *address = access.address; + *value = access.value; + if (access.type <= VB_S32) + *type = access.type; } - /* An exception or interrupt occurred */ - if (sim->cpu.causeCode != 0) { - sim->cpu.state = CPU_EXCEPTION; - sim->cpu.substring = 0; + /* Post-processing */ + vb->cpu.clocks += access.clocks; + return 0; +} + + + +/**************************** Execute A Handlers *****************************/ + +/* Standard two-operand instruction */ +static int exaStdTwo(VB *vb) { + OpDef *def = (OpDef *) vb->cpu.inst.def; + vb->cpu.inst.aux[0] = def->operand(vb); + vb->cpu.clocks += def->aux; + return 0; +} + +/* Standard three-operand instruction */ +static int exaStdThree(VB *vb) { + OpDef *def = (OpDef *) vb->cpu.inst.def; + vb->cpu.inst.aux[0] = def->operand(vb); + vb->cpu.inst.aux[1] = vb->cpu.program[vb->cpu.inst.code[0] & 31]; + vb->cpu.clocks += def->aux; + return 0; +} + +/* Bit string bitwise */ +static int exaBitBitwise(VB *vb) { + int32_t bits; /* Working shift amount and bit mask */ + uint32_t length; /* Number of bits remaining in bit string */ + int32_t offDest; /* Bit offset of destination bit string */ + int32_t offSrc; /* Bit offset of source bit string */ + uint32_t result; /* Output wrdvalue */ + uint32_t valDest; /* Destination word value */ + + /* Initial invocation */ + if (vb->cpu.step == 0) + vb->cpu.step = vb->cpu.bitstring + 1; + + /* Read the low-order 32 source bits */ + if (vb->cpu.step == 1) { + if (cpuRead(vb, vb->cpu.program[30], VB_S32, &vb->cpu.inst.aux[0])) + return 1; + vb->cpu.clocks += 4; /* TODO: Needs research */ + vb->cpu.step = 2; } - /* Switch to fetch mode */ - else if (sim->cpu.state != CPU_HALTED && - sim->cpu.busWait == 0 && !sim->cpu.substring) { - sim->cpu.state = CPU_FETCH; + /* Read the high-order 32 source bits */ + if (vb->cpu.step == 2) { + if (cpuRead(vb, vb->cpu.program[30] + 4, VB_S32, &vb->cpu.inst.aux[1])) + return 1; + vb->cpu.clocks += 4; /* TODO: Needs research */ + vb->cpu.step = 3; + } + + /* Read the destination bits */ + if (vb->cpu.step == 3) { + if (cpuRead(vb, vb->cpu.program[29], VB_S32, &vb->cpu.inst.aux[2])) + return 1; + vb->cpu.clocks += 4; /* TODO: Needs research */ + vb->cpu.step = 4; + } + + /* Compute the result */ + if (vb->cpu.step == 4) { + length = vb->cpu.program[28]; + offDest = vb->cpu.program[26] & 31; + offSrc = vb->cpu.program[27] & 31; + result = vb->cpu.inst.aux[0]; + valDest = vb->cpu.inst.aux[2]; + bits = offDest - offSrc; + + /* Compose the source value */ + if (bits > 0) + result <<= bits; + else if (bits < 0) { + result >>= -bits; + #ifndef VB_SIGNED_PROPAGATE + result &= ((uint32_t) 1 << (32 + bits)) - 1; + #endif + result |= vb->cpu.inst.aux[1] << (32 + bits); + } + + /* Compose the destination value */ + ((OpDef *) vb->cpu.inst.def) + ->operation(vb, (int32_t *) &result, valDest); + bits = (1 << offDest) - 1; + if (length < 32 && offDest + length < 32) + bits |= (uint32_t) 0xFFFFFFFF << (offDest + length); + vb->cpu.inst.aux[2] = (result & ~bits) | (valDest & bits); + + /* Prepare to write the result */ + vb->cpu.inst.aux[3] = vb->cpu.program[29] & 0xFFFFFFFC; + vb->cpu.inst.aux[4] = VB_S32; + if (cpuWritePre(vb, (uint32_t *) &vb->cpu.inst.aux[3], + &vb->cpu.inst.aux[4], &vb->cpu.inst.aux[2])) + return 1; + vb->cpu.clocks += 4; /* TODO: Needs research */ } return 0; } -/* Enter an exception state */ -static int cpuException(VB *sim) { - uint16_t causeCode = sim->cpu.causeCode; - int irq = causeCode < 0xFF00; +/* Bit string search */ +static int exaBitSearch(VB *vb) { + if (cpuRead(vb, vb->cpu.program[30], VB_S32, &vb->cpu.inst.aux[0])) + return 1; + vb->cpu.clocks += 4; /* TODO: Needs research */ + return 0; +} + +/* Branch on condition */ +static int exaBCOND(VB *vb) { + if (cpuCondition(vb, vb->cpu.inst.code[0] >> 9 & 15)) { + vb->cpu.inst.aux[0] = + (vb->cpu.pc + SignExtend(vb->cpu.inst.code[0], 9)) & 0xFFFFFFFE; + vb->cpu.clocks += 3; + } else { + vb->cpu.inst.aux[0] = vb->cpu.pc + vb->cpu.inst.size; + vb->cpu.clocks += 1; + } + return 0; +} + +/* Compare and exchange interlocked */ +static int exaCAXI(VB *vb) { + + /* First invocation */ + if (vb->cpu.step == 0) { + exaStdThree(vb); + vb->cpu.inst.aux[0] += vb->cpu.inst.aux[1]; /* Address */ + vb->cpu.inst.aux[1] = VB_S32; /* Write type */ + vb->cpu.inst.aux[3] = vb->cpu.program[vb->cpu.inst.code[0] >> 5 & 31]; + vb->cpu.step = 1; + } + + /* Read the lock word and determine the exchange value */ + if (vb->cpu.step == 1) { + if (cpuRead(vb, vb->cpu.inst.aux[0], VB_S32, &vb->cpu.inst.aux[4])) + return 1; + vb->cpu.inst.aux[2] = vb->cpu.inst.aux[3] == vb->cpu.inst.aux[4] ? + vb->cpu.program[30] : vb->cpu.inst.aux[4]; + vb->cpu.step = 2; + } + + /* Prepare to write the exchange value */ + if (vb->cpu.step == 2) { + if (cpuWritePre(vb, (uint32_t *) &vb->cpu.inst.aux[0], + &vb->cpu.inst.aux[1], &vb->cpu.inst.aux[2])) + return 1; + } + + return 0; +} + +/* No special action */ +static int exaDefault(VB *vb) { + vb->cpu.clocks += ((OpDef *) vb->cpu.inst.def)->aux; + return 0; +} + +/* Division */ +static int exaDivision(VB *vb) { + exaStdTwo(vb); + if (vb->cpu.inst.aux[0] == 0) { + vb->cpu.clocks = 0; /* exaStdTwo adds clocks */ + vb->cpu.exception = 0xFF80; /* Zero division */ + } + return 0; +} + +/* Exception */ +static int exaException(VB *vb) { + VBException exception; /* Exception descriptor */ + + /* Initial invocation */ + if (vb->cpu.step == 0) { + + /* Call the breakpoint handler */ + if (vb->onException != NULL) { + + /* Query the application */ + exception.address = vb->cpu.inst.aux[0]; + exception.code = vb->cpu.exception; + exception.cancel = 0; + if (vb->onException(vb, &exception)) + return 1; + + /* The application canceled the exception */ + if (exception.cancel) { + vb->cpu.exception = 0; + vb->cpu.stage = CPU_FETCH; + return 0; + } + + /* Apply changes */ + vb->cpu.inst.aux[0] = exception.address; + vb->cpu.exception = exception.code; + } + + /* Fatal exception: stage values for writing */ + if (vb->cpu.psw.np) { + vb->cpu.inst.aux[0] = 0x00000000; + vb->cpu.inst.aux[1] = VB_S32; + vb->cpu.inst.aux[2] = 0xFFFF0000 | vb->cpu.exception; + vb->cpu.inst.aux[3] = 0x00000004; + vb->cpu.inst.aux[4] = VB_S32; + vb->cpu.inst.aux[5] = cpuGetSystemRegister(vb, VB_PSW); + vb->cpu.inst.aux[6] = 0x00000008; + vb->cpu.inst.aux[7] = VB_S32; + vb->cpu.inst.aux[8] = vb->cpu.pc; + vb->cpu.step = 1; + } + + /* Other exception */ + else vb->cpu.step = 10; + } + + /* Prepare to dump fatal exception diagnostic values to memory */ + for (; vb->cpu.step < 10; vb->cpu.step += 3) { + if (cpuWritePre(vb, (uint32_t *) + &vb->cpu.inst.aux[vb->cpu.step - 1], + &vb->cpu.inst.aux[vb->cpu.step ], + &vb->cpu.inst.aux[vb->cpu.step + 1] + )) return 1; + } + + /* Common processing */ + vb->cpu.bitstring = 0; + vb->cpu.clocks += 1; /* TODO: Needs research */ + return 0; +} + +/* One-operand floating-point instruction */ +static int exaFloating1(VB *vb) { + int bits; /* Number of bits to shift */ + int32_t reg1; /* Left operand */ + int32_t result; /* Operation result */ + int32_t subop; /* Sub-opcode */ + + /* Reserved operand */ + reg1 = vb->cpu.program[vb->cpu.inst.code[0] & 31]; + if (cpuFRO(reg1)) { + vb->cpu.fp_flags = 0x00000200; /* FRO */ + vb->cpu.exception = 0xFF60; + return 0; + } + + /* Working variables */ + bits = (reg1 >> 23 & 0xFF) - 150; + result = (reg1 & 0x007FFFFF) | 0x00800000; + subop = vb->cpu.inst.code[1] >> 10 & 63; + + /* Zero */ + if ((reg1 & 0x7FFFFFFF) == 0x00000000) + result = 0; + + /* Minimum negative value */ + else if (bits == 8 && result == 0x00800000 && reg1 < 0) + result = INT32_MIN; + + /* Shifting left */ + else if (bits > 0) { + + /* Invalid operation */ + if (bits > 7) { + vb->cpu.fp_flags = 0x00000100; /* FIV */ + vb->cpu.exception = 0xFF70; + return 0; + } + + /* Compute result */ + result <<= bits; + } + + /* Shifting right */ + else if (bits < 0) { + result = + bits < -24 ? 0 : /* All bits shifted out */ + subop == 0x0B ? result >> -bits : /* Truncate */ + ((result >> (-bits - 1)) + 1) >> 1 /* Round */ + ; + } + + /* Result is negative */ + if (reg1 < 0 && result != INT32_MIN) + result = -result; + + /* Stage updates */ + vb->cpu.fp_flags = result == *(float *)®1 ? 0 : 0x00000010; /* FPR */ + vb->cpu.inst.aux[0] = result; + vb->cpu.inst.aux[1] = subop; + vb->cpu.clocks += ((OpDef *) vb->cpu.inst.def)->aux; + return 0; +} + +/* Two-operand floating-point instruction */ +static int exaFloating2(VB *vb) { + FloatAux *aux; /* Floating-point auxiliary memory */ + int32_t bits; /* Bits of testing value */ + int32_t reg1; /* Right operand */ + int32_t reg2; /* Left operand */ + float test; /* Floating-point testing value */ + OpDef *def = (OpDef *) vb->cpu.inst.def; + + /* Reserved operand */ + reg1 = vb->cpu.program[vb->cpu.inst.code[0] & 31]; + reg2 = vb->cpu.program[vb->cpu.inst.code[0] >> 5 & 31]; + if (cpuFRO(reg1) || cpuFRO(reg2)) { + vb->cpu.fp_flags = 0x00000200; /* FRO */ + vb->cpu.exception = 0xFF60; + return 0; + } + + /* Perform the operation */ + def->operation(vb, ®2, reg1); + if (vb->cpu.exception != 0) + return 0; /* Handled in opDIVF_S() */ + aux = (FloatAux *) &vb->cpu.inst.aux; + + /* Overflow */ + bits = 0x7F7FFFFF; /* Maximum value */ + test = *(float *)&bits; + if (aux->f64 > test || aux->f64 < -test) { + vb->cpu.fp_flags = 0x00000040; /* FOV */ + vb->cpu.exception = 0xFF64; + return 0; + } + + /* Process result */ + bits = *(int32_t *)&aux->f32; + vb->cpu.fp_flags = 0; + + /* Zero */ + if ((bits & 0x7FFFFFFF) == 0x00000000) + aux->f32 = bits = 0; + + /* Underflow */ + else if ((bits & 0x7F800000) == 0x00000000) { + vb->cpu.fp_flags = 0x00000020; /* FUD */ + aux->f32 = bits = 0; + } + + /* Precision degradation */ + if (aux->f32 != aux->f64) + vb->cpu.fp_flags |= 0x00000010; /* FPR */ + + /* Other state */ + vb->cpu.inst.aux[0] = bits; + vb->cpu.inst.aux[1] = vb->cpu.inst.code[1] >> 10 & 63; + vb->cpu.clocks += def->aux; + return 0; +} + +/* Illegal opcode */ +static int exaIllegal(VB *vb) { + vb->cpu.exception = 0xFF90; /* Illegal opcode */ + return 0; +} + +/* Jump relative, jump and link */ +static int exaJR(VB *vb) { + vb->cpu.inst.aux[0] = 0xFFFFFFFE & (vb->cpu.pc + SignExtend( + (int32_t) vb->cpu.inst.code[0] << 16 | vb->cpu.inst.code[1], 26)); + vb->cpu.clocks += 3; + return 0; +} + +/* Memory read */ +static int exaRead(VB *vb) { + + /* First invocation */ + if (vb->cpu.step == 0) { + exaStdThree(vb); + vb->cpu.inst.aux[1] += vb->cpu.inst.aux[0]; /* Address */ + vb->cpu.clocks += 5; /* TODO: Needs research */ + vb->cpu.step = 1; + } + + /* Read the value */ + return cpuRead(vb, vb->cpu.inst.aux[1], + ((OpDef *) vb->cpu.inst.def)->aux, &vb->cpu.inst.aux[0]); +} + +/* Trap */ +static int exaTRAP(VB *vb) { + /* TODO: Clocks is less 1 here because exaException adds 1 */ + vb->cpu.clocks += ((OpDef *) vb->cpu.inst.def)->aux - 1; + vb->cpu.exception = 0xFFA0 | (vb->cpu.inst.code[0] & 31); + return 0; +} + +/* Memory write */ +static int exaWrite(VB *vb) { + + /* First invocation */ + if (vb->cpu.step == 0) { + exaStdThree(vb); + vb->cpu.inst.aux[0] += vb->cpu.inst.aux[1]; + vb->cpu.inst.aux[1] = ((OpDef *) vb->cpu.inst.def)->aux; /* Type */ + vb->cpu.inst.aux[2] = vb->cpu.program[vb->cpu.inst.code[0] >> 5 & 31]; + vb->cpu.clocks += 4; /* TODO: Needs research */ + vb->cpu.step = 1; + } + + /* Write the value */ + return cpuWritePre(vb, (uint32_t *) &vb->cpu.inst.aux[0], + &vb->cpu.inst.aux[1], &vb->cpu.inst.aux[2]); +} + + + +/**************************** Execute B Handlers *****************************/ + +/* Bit string bitwise */ +static void exbBitBitwise(VB *vb) { + int32_t bits; + + /* Write the output value */ + if (vb->cpu.program[28] != 0) { + busWrite(vb, vb->cpu.inst.aux[3], + vb->cpu.inst.aux[4], vb->cpu.inst.aux[2], 0); + } + + /* Prepare registers */ + vb->cpu.program[26] &= 0x0000001F; + vb->cpu.program[27] &= 0x0000001F; + vb->cpu.program[29] &= 0xFFFFFFFC; + vb->cpu.program[30] &= 0xFFFFFFFC; + + /* Determine how many bits of output have been processed */ + bits = 32 - vb->cpu.program[26]; + if ((uint32_t) vb->cpu.program[28] <= (uint32_t) bits) + bits = vb->cpu.program[28]; + + /* Update source */ + vb->cpu.program[27] += bits; + if (vb->cpu.program[27] >= 32) { + vb->cpu.program[27] &= 31; + vb->cpu.program[30] += 4; + vb->cpu.inst.aux[0] = vb->cpu.inst.aux[1]; + vb->cpu.bitstring = 1; /* Read next source word */ + } else vb->cpu.bitstring = 2; /* Skip source reads */ + + /* Update destination */ + vb->cpu.program[26] += bits; + if (vb->cpu.program[26] >= 32) { + vb->cpu.program[26] &= 31; + vb->cpu.program[29] += 4; + } + + /* Update length */ + vb->cpu.program[28] -= bits; + + /* Advance to the next instruction */ + if (vb->cpu.program[28] == 0) { + vb->cpu.bitstring = 0; + vb->cpu.pc += vb->cpu.inst.size; + } + +} + +/* Bit string search */ +static void exbBitSearch(VB *vb) { + int32_t dir = ((~vb->cpu.inst.code[0] & 1) << 1) - 1; + int32_t test = vb->cpu.inst.code[0] >> 1 & 1; + + /* Prepare registers */ + vb->cpu.program[27] &= 0x0000001F; + vb->cpu.program[30] &= 0xFFFFFFFC; + vb->cpu.psw.z = 1; + vb->cpu.bitstring = 1; + + /* Process all remaining bits in the current word */ + while (vb->cpu.psw.z && vb->cpu.program[28] != 0) { + + /* The bit does not match */ + if ( + (vb->cpu.inst.aux[0] & 1 << vb->cpu.program[27]) != + test << vb->cpu.program[27] + ) vb->cpu.program[29]++; + + /* A match was found */ + else vb->cpu.psw.z = 0; + + /* Advance to the next bit */ + vb->cpu.program[28]--; + vb->cpu.program[27] += dir; + if (vb->cpu.program[27] & 0x00000020) { + vb->cpu.program[27] &= 0x0000001F; + vb->cpu.program[30] += dir << 2; + break; + } + + } + + /* Advance to the next instruction */ + if (!vb->cpu.psw.z || vb->cpu.program[28] == 0) { + vb->cpu.bitstring = 0; + vb->cpu.pc += vb->cpu.inst.size; + } + +} + +/* Compare and exchange interlocked */ +static void exbCAXI(VB *vb) { + int32_t left = vb->cpu.inst.aux[3]; + int32_t right = vb->cpu.inst.aux[4]; + int32_t result = left - right; + vb->cpu.psw.cy = (uint32_t) left < (uint32_t) right; + vb->cpu.psw.ov = (int32_t) ((left ^ right) & (left ^ result)) < 0; + vb->cpu.psw.s = result < 0; + vb->cpu.psw.z = result == 0; + vb->cpu.pc += vb->cpu.inst.size; + vb->cpu.program[vb->cpu.inst.code[0] >> 5 & 31] = right; + busWrite(vb, vb->cpu.inst.aux[0], + vb->cpu.inst.aux[1], vb->cpu.inst.aux[2], 0); +} + +/* Clear interrupt disable flag */ +static void exbCLI(VB *vb) { + vb->cpu.pc += vb->cpu.inst.size; + vb->cpu.psw.id = 0; +} + +/* Exception */ +static void exbException(VB *vb) { + int x; /* Iterator */ + + /* Apply staged floating-point flags */ + if (vb->cpu.fp_flags != 0) { + cpuSetSystemRegister(vb, VB_PSW, vb->cpu.fp_flags | + cpuGetSystemRegister(vb, VB_PSW), 0); + vb->cpu.fp_flags = 0; + } /* Fatal exception */ - if (sim->cpu.psw.np) { - - /* Write the cause code for debugging */ - if (sim->cpu.busWait == 0) { - if (cpuWrite(sim, 0x00000000, VB_S32, 0xFFFF0000 | causeCode)) - return 1; - - /* Update state */ - sim->cpu.busWait = 1; - sim->cpu.clocks = sim->cpu.access.clocks; - - /* Wait for the bus access to complete */ - if (sim->cpu.clocks > 0) - return 0; + if (vb->cpu.psw.np) { + for (x = 0; x < 9; x += 3) { + busWrite(vb, vb->cpu.inst.aux[x], + vb->cpu.inst.aux[x + 1], vb->cpu.inst.aux[x + 2], 0); } - - /* Write PSW for debugging */ - if (sim->cpu.busWait == 1) { - if (cpuWrite(sim, 0x00000000, VB_S32, - vbGetSystemRegister(sim, VB_PSW))) - return 1; - - /* Update state */ - sim->cpu.busWait = 2; - sim->cpu.clocks = sim->cpu.access.clocks; - - /* Wait for the bus access to complete */ - if (sim->cpu.clocks > 0) - return 0; - } - - /* Write PC for debugging */ - if (sim->cpu.busWait == 2) { - if (cpuWrite(sim, 0x00000000, VB_S32, sim->cpu.pc)) - return 1; - - /* Update state */ - sim->cpu.busWait = 3; - sim->cpu.clocks = sim->cpu.access.clocks; - - /* Wait for the bus access to complete */ - if (sim->cpu.clocks > 0) - return 0; - } - - /* Update state */ - sim->cpu.busWait = 0; - sim->cpu.causeCode = 0; - sim->cpu.state = CPU_FATAL; - return 0; + vb->cpu.stage = CPU_FATAL; + return; } /* Duplexed exception */ - if (sim->cpu.psw.ep) { - sim->cpu.ecr.fecc = causeCode; - sim->cpu.fepsw = vbGetSystemRegister(sim, VB_PSW); - sim->cpu.fepc = sim->cpu.pc; - sim->cpu.psw.np = 1; - sim->cpu.pc = 0xFFFFFFD0; + if (vb->cpu.psw.ep) { + vb->cpu.ecr.fecc = vb->cpu.exception; + vb->cpu.fepc = vb->cpu.pc; + vb->cpu.fepsw = cpuGetSystemRegister(vb, VB_PSW); + vb->cpu.pc = 0xFFFFFFD0; + vb->cpu.psw.np = 1; } - /* Exception or interrupt */ + /* Regular exception */ else { - sim->cpu.ecr.eicc = causeCode; - sim->cpu.eipsw = vbGetSystemRegister(sim, VB_PSW); - sim->cpu.eipc = sim->cpu.pc + (irq ? 2 : 0); - sim->cpu.psw.ep = 1; - sim->cpu.pc = (causeCode & 0x0040) != 0 ? - 0xFFFFFF60 : ((uint32_t) 0xFFFF0000 | (causeCode & 0xFFF0)); + vb->cpu.ecr.eicc = vb->cpu.exception; + vb->cpu.eipc = vb->cpu.pc; + vb->cpu.eipsw = cpuGetSystemRegister(vb, VB_PSW); + vb->cpu.pc = vb->cpu.inst.aux[0]; + vb->cpu.psw.ep = 1; + + /* Interrupt */ + if (vb->cpu.exception < 0xFF00) { + if ((vb->cpu.inst.code[0] & 0xFC00) == 0x6800) /* HALT */ + vb->cpu.eipc += vb->cpu.inst.size; + vb->cpu.psw.i = Min(15, (vb->cpu.exception >> 4 & 15) + 1); + } + + /* TRAP */ + if ((vb->cpu.exception & 0xFFE0) == 0xFFA0) + vb->cpu.eipc += vb->cpu.inst.size; } - /* Interrupt */ - if (irq) - sim->cpu.psw.i += sim->cpu.psw.i == 15 ? 0 : 1; - - /* Update state */ - sim->cpu.causeCode = 0; - sim->cpu.state = CPU_FETCH; - sim->cpu.psw.id = 1; - sim->cpu.psw.ae = 0; - /* sim->cpu.clocks = ? */ - - /* Call the breakpoint handler if available */ - return sim->onException != NULL && sim->onException(sim, causeCode); + /* Common processing */ + vb->cpu.psw.ae = 0; + vb->cpu.psw.id = 1; } -/* Perform instruction fetch operations */ -static int cpuFetch(VB *sim) { - VB_INSTRUCTION *inst; /* Reference to sim->cpu.inst */ - uint8_t opcode; /* 6-bit instruction opcode */ +/* Floating-point instruction */ +static void exbFloating(VB *vb) { + int32_t result = vb->cpu.inst.aux[0]; /* Operation result */ + int32_t subop = vb->cpu.inst.aux[1]; /* Sub-opcode */ - /* Need to read a data unit */ - if (sim->cpu.busWait == 0) { - - /* Read the data unit from the bus */ - if (cpuReadFetch(sim, sim->cpu.pc + (sim->cpu.fetch << 1))) - return 1; - - /* Update state */ - sim->cpu.busWait = 1; - sim->cpu.clocks = sim->cpu.access.clocks; - - /* Wait for the bus access to complete */ - if (sim->cpu.clocks > 0) - return 0; + /* Apply staged floating-point flags */ + if (vb->cpu.fp_flags != 0) { + cpuSetSystemRegister(vb, VB_PSW, vb->cpu.fp_flags | + cpuGetSystemRegister(vb, VB_PSW), 0); + vb->cpu.fp_flags = 0; } /* Update state */ - inst = &sim->cpu.inst; - inst->bits[sim->cpu.fetch] = sim->cpu.access.value; - sim->cpu.busWait = 0; + vb->cpu.pc += vb->cpu.inst.size; + vb->cpu.psw.ov = 0; + vb->cpu.psw.s = result < 0; + vb->cpu.psw.z = result == 0; + if (subop != 0x03 && subop != 0x0B) /* CVT.SW, TRNC.SW */ + vb->cpu.psw.cy = result < 0; + if (subop != 0x00) /* CMPF.S */ + vb->cpu.program[vb->cpu.inst.code[0] >> 5 & 31] = result; +} - /* Working variables */ - opcode = inst->bits[0] >> 10 & 0x3F; +/* Halt */ +static void exbHALT(VB *vb) { + vb->cpu.stage = CPU_HALT; +} + +/* Jump and link */ +static void exbJAL(VB *vb) { + vb->cpu.program[31] = vb->cpu.pc + vb->cpu.inst.size; + vb->cpu.pc = vb->cpu.inst.aux[0]; +} + +/* Jump */ +static void exbJMP(VB *vb) { + vb->cpu.pc = vb->cpu.inst.aux[0]; +} + +/* Return from trap or interrupt */ +static void exbRETI(VB *vb) { + if (vb->cpu.psw.np) { + vb->cpu.pc = vb->cpu.fepc; + cpuSetSystemRegister(vb, VB_PSW, vb->cpu.fepsw, 0); + } else { + vb->cpu.pc = vb->cpu.eipc; + cpuSetSystemRegister(vb, VB_PSW, vb->cpu.eipsw, 0); + } +} + +/* Set interrupt disable flag */ +static void exbSEI(VB *vb) { + vb->cpu.pc += vb->cpu.inst.size; + vb->cpu.psw.id = 1; +} + +/* Standard two-operand instruction */ +static void exbStdTwo(VB *vb) { + ((OpDef *) vb->cpu.inst.def)->operation(vb, + &vb->cpu.program[vb->cpu.inst.code[0] >> 5 & 31], + vb->cpu.inst.aux[0] + ); + vb->cpu.pc += vb->cpu.inst.size; +} + +/* Standard three-operand instruction */ +static void exbStdThree(VB *vb) { + int32_t *reg2 = &vb->cpu.program[vb->cpu.inst.code[0] >> 5 & 31]; + *reg2 = vb->cpu.inst.aux[1]; + ((OpDef *) vb->cpu.inst.def)->operation(vb, reg2, vb->cpu.inst.aux[0]); + vb->cpu.pc += vb->cpu.inst.size; +} + + + +/**************************** Operation Handlers *****************************/ + +/* Add */ +static void opADD(VB *vb, int32_t *dest, int32_t src) { + int32_t result = *dest + src; + vb->cpu.psw.cy = (uint32_t) result < (uint32_t) *dest; + vb->cpu.psw.ov = (int32_t) (~(*dest ^ src) & (*dest ^ result)) < 0; + vb->cpu.psw.s = result < 0; + vb->cpu.psw.z = result == 0; + *dest = result; +} + +/* Add Floating Short */ +static void opADDF_S(VB *vb, int32_t *dest, int32_t src) { + FloatAux *aux = (FloatAux *) vb->cpu.inst.aux; + double left = *(float *)dest; + double right = *(float *)&src; + double result = left + right; + aux->f32 = result; + aux->f64 = result; +} + +/* And */ +static void opAND(VB *vb, int32_t *dest, int32_t src) { + int32_t result = *dest & src; + vb->cpu.psw.ov = 0; + vb->cpu.psw.s = result < 0; + vb->cpu.psw.z = result == 0; + *dest = result; +} + +/* And Bit String Upward */ +static void opANDBSU(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + *dest &= src; +} + +/* And Not Bit String Upward */ +static void opANDNBSU(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + *dest = ~*dest & src; +} + +/* Compare */ +static void opCMP(VB *vb, int32_t *dest, int32_t src) { + int32_t result = *dest - src; + vb->cpu.psw.cy = (uint32_t) *dest < (uint32_t) src; + vb->cpu.psw.ov = (int32_t) ((*dest ^ src) & (*dest ^ result)) < 0; + vb->cpu.psw.s = result < 0; + vb->cpu.psw.z = result == 0; +} + +/* Convert Word Integer to Short Floating */ +static void opCVT_WS(VB *vb, int32_t *dest, int32_t src) { + float value = (float) src; + *dest = *(int32_t *)&value; + if ((double) value != (double) src) + vb->cpu.psw.fpr = 1; +} + +/* Divide signed */ +static void opDIV(VB *vb, int32_t *dest, int32_t src) { + int32_t result; + if (*dest == INT32_MIN && src == -1) { + vb->cpu.psw.ov = 1; + vb->cpu.psw.s = 1; + vb->cpu.psw.z = 0; + vb->cpu.program[30] = 0; + } else { + result = *dest / src; + vb->cpu.psw.ov = 0; + vb->cpu.psw.s = result < 0; + vb->cpu.psw.z = result == 0; + vb->cpu.program[30] = *dest % src; + *dest = result; + } +} + +/* Divide Floating Short */ +static void opDIVF_S(VB *vb, int32_t *dest, int32_t src) { + FloatAux *aux = (FloatAux *) vb->cpu.inst.aux; + double left; /* Left operand */ + double right; /* Right operand */ + double result; /* Operation result */ + + /* Divisor is zero */ + if (*dest == 0) { + + /* Invalid operation */ + if (src == 0) { + vb->cpu.fp_flags = 0x00000100; /* FIV */ + vb->cpu.exception = 0xFF70; + } + + /* Zero division */ + else { + vb->cpu.fp_flags = 0x00000080; /* FZD */ + vb->cpu.exception = 0xFF68; + } + + return; + } + + /* Perform the operation */ + left = *(float *)dest; + right = *(float *)&src; + result = left / right; + aux->f32 = result; + aux->f64 = result; +} + +/* Divide unsigned */ +static void opDIVU(VB *vb, int32_t *dest, int32_t src) { + uint32_t result = (uint32_t) *dest / (uint32_t) src; + vb->cpu.psw.ov = 0; + vb->cpu.psw.s = (int32_t) result < 0; + vb->cpu.psw.z = result == 0; + vb->cpu.program[30] = (int32_t) ((uint32_t) *dest % (uint32_t) src); + *dest = (int32_t) result; +} + +/* Load to system register */ +static void opLDSR(VB *vb, int32_t *dest, int32_t src) { + cpuSetSystemRegister(vb, src, *dest, 0); +} + +/* Move */ +static void opMOV(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + *dest = src; +} + +/* Move Bit String Upward */ +static void opMOVBSU(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + (void) dest; + (void) src; +} + +/* Add Immediate */ +static void opMOVEA(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + *dest += src; +} + +/* Multiply Halfword */ +static void opMPYHW(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + *dest *= SignExtend(src, 17); +} + +/* Multiply signed */ +static void opMUL(VB *vb, int32_t *dest, int32_t src) { + int64_t result = (int64_t) *dest * (int64_t) src; + int32_t resultLow = (int32_t) result; + vb->cpu.psw.ov = result != resultLow; + vb->cpu.psw.s = resultLow < 0; + vb->cpu.psw.z = resultLow == 0; + vb->cpu.program[30] = (int32_t) (result >> 32); + *dest = resultLow; +} + +/* Multiply Floating Short */ +static void opMULF_S(VB *vb, int32_t *dest, int32_t src) { + FloatAux *aux = (FloatAux *) vb->cpu.inst.aux; + double left = *(float *)dest; + double right = *(float *)&src; + double result = left * right; + aux->f32 = result; + aux->f64 = result; +} + +/* Multiply unsigned */ +static void opMULU(VB *vb, int32_t *dest, int32_t src) { + uint64_t result = (uint64_t)(uint32_t)*dest * (uint64_t)(uint32_t)src; + uint32_t resultLow = (uint32_t) result; + vb->cpu.psw.ov = result != resultLow; + vb->cpu.psw.s = (int32_t) resultLow < 0; + vb->cpu.psw.z = resultLow == 0; + vb->cpu.program[30] = (int32_t) (result >> 32); + *dest = (int32_t) resultLow; +} + +/* Not */ +static void opNOT(VB *vb, int32_t *dest, int32_t src) { + int32_t result = ~src; + vb->cpu.psw.ov = 0; + vb->cpu.psw.s = result < 0; + vb->cpu.psw.z = result == 0; + *dest = result; +} + +/* Not Bit String Upward */ +static void opNOTBSU(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + (void) src; + *dest = ~*dest; +} + +/* Or */ +static void opOR(VB *vb, int32_t *dest, int32_t src) { + int32_t result = *dest | src; + vb->cpu.psw.ov = 0; + vb->cpu.psw.s = result < 0; + vb->cpu.psw.z = result == 0; + *dest = result; +} + +/* Or Bit String Upward */ +static void opORBSU(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + *dest |= src; +} + +/* Or Not Bit String Upward */ +static void opORNBSU(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + *dest = ~*dest | src; +} + +/* Reverse Bits in Word */ +static void opREV(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + src = (src << 16 & 0xFFFF0000) | (src >> 16 & 0x0000FFFF); + src = (src << 8 & 0xFF00FF00) | (src >> 8 & 0x00FF00FF); + src = (src << 4 & 0xF0F0F0F0) | (src >> 4 & 0x0F0F0F0F); + src = (src << 2 & 0xCCCCCCCC) | (src >> 2 & 0x33333333); + *dest = (src << 1 & 0xAAAAAAAA) | (src >> 1 & 0x55555555); +} + +/* Set flag condition */ +static void opSETF(VB *vb, int32_t *dest, int32_t src) { + *dest = cpuCondition(vb, src & 15); +} + +/* Shift right arithmetic */ +static void opSAR(VB *vb, int32_t *dest, int32_t src) { + int32_t result = *dest >> (src &= 31); + #ifndef VB_SIGNED_PROPAGATE + if (src != 0) + result = SignExtend(result, 32 - src); + #endif + vb->cpu.psw.cy = src != 0 && *dest & 1 << (src - 1); + vb->cpu.psw.ov = 0; + vb->cpu.psw.s = result < 0; + vb->cpu.psw.z = result == 0; + *dest = result; +} + +/* Shift left */ +static void opSHL(VB *vb, int32_t *dest, int32_t src) { + int32_t result = *dest << (src &= 31); + vb->cpu.psw.cy = src != 0 && *dest & 1 << (32 - src); + vb->cpu.psw.ov = 0; + vb->cpu.psw.s = result < 0; + vb->cpu.psw.z = result == 0; + *dest = result; +} + +/* Shift right logical */ +static void opSHR(VB *vb, int32_t *dest, int32_t src) { + int32_t result = (uint32_t) *dest >> (src &= 31); + #ifndef VB_SIGNED_PROPAGATE + if (src != 0) + result &= ((uint32_t) 1 << (32 - src)) - 1; + #endif + vb->cpu.psw.cy = src != 0 && *dest & 1 << (src - 1); + vb->cpu.psw.ov = 0; + vb->cpu.psw.s = result < 0; + vb->cpu.psw.z = result == 0; + *dest = result; +} + +/* Store */ +static void opST(VB *vb, int32_t *dest, int32_t src) { + (void) dest, (void) src; + busWrite(vb, vb->cpu.inst.aux[0], + vb->cpu.inst.aux[1], vb->cpu.inst.aux[2], 0); +} + +/* Store to system register */ +static void opSTSR(VB *vb, int32_t *dest, int32_t src) { + *dest = cpuGetSystemRegister(vb, src); +} + +/* Subtract */ +static void opSUB(VB *vb, int32_t *dest, int32_t src) { + int32_t result = *dest - src; + vb->cpu.psw.cy = (uint32_t) *dest < (uint32_t) src; + vb->cpu.psw.ov = (int32_t) ((*dest ^ src) & (*dest ^ result)) < 0; + vb->cpu.psw.s = result < 0; + vb->cpu.psw.z = result == 0; + *dest = result; +} + +/* Subtract Floating Short */ +static void opSUBF_S(VB *vb, int32_t *dest, int32_t src) { + FloatAux *aux = (FloatAux *) vb->cpu.inst.aux; + double left = *(float *)dest; + double right = *(float *)&src; + double result = left - right; + aux->f32 = result; + aux->f64 = result; +} + +/* Exchange Byte */ +static void opXB(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + *dest = (src & 0xFFFF0000) | (src << 8 & 0xFF00) | (src >> 8 & 0x00FF); +} + +/* Exchange Halfword */ +static void opXH(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + *dest = (src << 16 & 0xFFFF0000) | (src >> 16 & 0x0000FFFF); +} + +/* Exclusive Or */ +static void opXOR(VB *vb, int32_t *dest, int32_t src) { + int32_t result = *dest ^ src; + vb->cpu.psw.ov = 0; + vb->cpu.psw.s = result < 0; + vb->cpu.psw.z = result == 0; + *dest = result; +} + +/* Exclusive Or Bit String Upward */ +static void opXORBSU(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + *dest ^= src; +} + +/* Exclusive Or Not Bit String Upward */ +static void opXORNBSU(VB *vb, int32_t *dest, int32_t src) { + (void) vb; + *dest = ~*dest ^ src; +} + + + +/***************************** Operand Handlers ******************************/ + +/* imm5 (sign-extended) */ +static int32_t opImm5S(VB *vb) { + return SignExtend(vb->cpu.inst.code[0] & 31, 5); +} + +/* imm5 */ +static int32_t opImm5U(VB *vb) { + return vb->cpu.inst.code[0] & 31; +} + +/* imm16 (shifted left by 16) */ +static int32_t opImm16H(VB *vb) { + return (uint32_t) vb->cpu.inst.code[1] << 16; +} + +/* imm16 (sign-extended) */ +static int32_t opImm16S(VB *vb) { + return SignExtend(vb->cpu.inst.code[1], 16); +} + +/* imm16 */ +static int32_t opImm16U(VB *vb) { + return vb->cpu.inst.code[1]; +} + +/* reg1 */ +static int32_t opReg1(VB *vb) { + return vb->cpu.program[vb->cpu.inst.code[0] & 31]; +} + +/* reg2 */ +static int32_t opReg2(VB *vb) { + return vb->cpu.program[vb->cpu.inst.code[0] >> 5 & 31]; +} + + + +/**************************** Opcode Definitions *****************************/ + +/* Forward references */ +static int exaBitString(VB *); +static int exaFloatendo(VB *); + +/* Exception processing */ +static const OpDef OPDEF_EXCEPTION = + { &exaException, &exbException, NULL, NULL, 0, 0 }; + +/* Top-level opcode definitions */ +static const OpDef OPDEFS[] = { + { &exaStdTwo , &exbStdTwo , &opMOV , &opReg1 , 1, 1 }, /* 0x00 */ + { &exaStdTwo , &exbStdTwo , &opADD , &opReg1 , 1, 1 }, + { &exaStdTwo , &exbStdTwo , &opSUB , &opReg1 , 1, 1 }, + { &exaStdTwo , &exbStdTwo , &opCMP , &opReg1 , 1, 1 }, + { &exaStdTwo , &exbStdTwo , &opSHL , &opReg1 , 1, 1 }, + { &exaStdTwo , &exbStdTwo , &opSHR , &opReg1 , 1, 1 }, + { &exaStdTwo , &exbJMP , NULL , &opReg1 , 1, 3 }, + { &exaStdTwo , &exbStdTwo , &opSAR , &opReg1 , 1, 1 }, + { &exaStdTwo , &exbStdTwo , &opMUL , &opReg1 , 1, 13 }, + { &exaDivision , &exbStdTwo , &opDIV , &opReg1 , 1, 38 }, + { &exaStdTwo , &exbStdTwo , &opMULU , &opReg1 , 1, 13 }, + { &exaDivision , &exbStdTwo , &opDIVU , &opReg1 , 1, 36 }, + { &exaStdTwo , &exbStdTwo , &opOR , &opReg1 , 1, 1 }, + { &exaStdTwo , &exbStdTwo , &opAND , &opReg1 , 1, 1 }, + { &exaStdTwo , &exbStdTwo , &opXOR , &opReg1 , 1, 1 }, + { &exaStdTwo , &exbStdTwo , &opNOT , &opReg1 , 1, 1 }, + { &exaStdTwo , &exbStdTwo , &opMOV , &opImm5S , 1, 1 }, /* 0x10 */ + { &exaStdTwo , &exbStdTwo , &opADD , &opImm5S , 1, 1 }, + { &exaStdTwo , &exbStdTwo , &opSETF , &opImm5U , 1, 1 }, + { &exaStdTwo , &exbStdTwo , &opCMP , &opImm5S , 1, 1 }, + { &exaStdTwo , &exbStdTwo , &opSHL , &opImm5U , 1, 1 }, + { &exaStdTwo , &exbStdTwo , &opSHR , &opImm5U , 1, 1 }, + { &exaDefault , &exbCLI , NULL , NULL , 1, 12 }, + { &exaStdTwo , &exbStdTwo , &opSAR , &opImm5U , 1, 1 }, + { &exaTRAP , NULL , NULL , NULL , 1, 15 }, + { &exaDefault , &exbRETI , NULL , NULL , 1, 10 }, + { &exaDefault , &exbHALT , NULL , NULL , 1, 0 }, + { &exaIllegal , NULL , NULL , NULL , 1, 0 }, + { &exaStdTwo , &exbStdTwo , &opLDSR , &opImm5U , 1, 8 }, + { &exaStdTwo , &exbStdTwo , &opSTSR , &opImm5U , 1, 8 }, + { &exaDefault , &exbSEI , NULL , NULL , 1, 12 }, + { &exaBitString, NULL , NULL , NULL , 1, 0 }, + { &exaBCOND , &exbJMP , NULL , NULL , 1, 0 }, /* 0x20 */ + { &exaBCOND , &exbJMP , NULL , NULL , 1, 0 }, + { &exaBCOND , &exbJMP , NULL , NULL , 1, 0 }, + { &exaBCOND , &exbJMP , NULL , NULL , 1, 0 }, + { &exaBCOND , &exbJMP , NULL , NULL , 1, 0 }, + { &exaBCOND , &exbJMP , NULL , NULL , 1, 0 }, + { &exaBCOND , &exbJMP , NULL , NULL , 1, 0 }, + { &exaBCOND , &exbJMP , NULL , NULL , 1, 0 }, + { &exaStdThree , &exbStdThree, &opMOVEA, &opImm16S, 2, 1 }, + { &exaStdThree , &exbStdThree, &opADD , &opImm16S, 2, 1 }, + { &exaJR , &exbJMP , NULL , NULL , 2, 0 }, + { &exaJR , &exbJAL , NULL , NULL , 2, 0 }, + { &exaStdThree , &exbStdThree, &opOR , &opImm16U, 2, 1 }, + { &exaStdThree , &exbStdThree, &opAND , &opImm16U, 2, 1 }, + { &exaStdThree , &exbStdThree, &opXOR , &opImm16U, 2, 1 }, + { &exaStdThree , &exbStdThree, &opMOVEA, &opImm16H, 2, 1 }, + { &exaRead , &exbStdTwo , &opMOV , &opImm16S, 2, VB_S8 }, /* 0x30 */ + { &exaRead , &exbStdTwo , &opMOV , &opImm16S, 2, VB_S16 }, + { &exaIllegal , NULL , NULL , NULL , 1, 0 }, + { &exaRead , &exbStdTwo , &opMOV , &opImm16S, 2, VB_S32 }, + { &exaWrite , &exbStdTwo , &opST , &opImm16S, 2, VB_S8 }, + { &exaWrite , &exbStdTwo , &opST , &opImm16S, 2, VB_S16 }, + { &exaIllegal , NULL , NULL , NULL , 1, 0 }, + { &exaWrite , &exbStdTwo , &opST , &opImm16S, 2, VB_S32 }, + { &exaRead , &exbStdTwo , &opMOV , &opImm16S, 2, VB_U8 }, + { &exaRead , &exbStdTwo , &opMOV , &opImm16S, 2, VB_U16 }, + { &exaCAXI , &exbCAXI , NULL , &opImm16S, 2, 26 }, + { &exaRead , &exbStdTwo , &opMOV , &opImm16S, 2, VB_S32 }, + { &exaWrite , &exbStdTwo , &opST , &opImm16S, 2, VB_U8 }, + { &exaWrite , &exbStdTwo , &opST , &opImm16S, 2, VB_U16 }, + { &exaFloatendo, NULL , NULL , NULL , 2, 0 }, + { &exaWrite , &exbStdTwo , &opST , &opImm16S, 2, VB_S32 } +}; + +/* Bit string opcode definitions */ +static const OpDef OPDEFS_BITSTRING[] = { + { &exaBitSearch , &exbBitSearch , NULL , NULL, 1, 0 }, /* 0x00 */ + { &exaBitSearch , &exbBitSearch , NULL , NULL, 1, 0 }, + { &exaBitSearch , &exbBitSearch , NULL , NULL, 1, 0 }, + { &exaBitSearch , &exbBitSearch , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaBitBitwise, &exbBitBitwise, &opORBSU , NULL, 1, 0 }, + { &exaBitBitwise, &exbBitBitwise, &opANDBSU , NULL, 1, 0 }, + { &exaBitBitwise, &exbBitBitwise, &opXORBSU , NULL, 1, 0 }, + { &exaBitBitwise, &exbBitBitwise, &opMOVBSU , NULL, 1, 0 }, + { &exaBitBitwise, &exbBitBitwise, &opORNBSU , NULL, 1, 0 }, + { &exaBitBitwise, &exbBitBitwise, &opANDNBSU, NULL, 1, 0 }, + { &exaBitBitwise, &exbBitBitwise, &opXORNBSU, NULL, 1, 0 }, + { &exaBitBitwise, &exbBitBitwise, &opNOTBSU , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, /* 0x10 */ + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 }, + { &exaIllegal , NULL , NULL , NULL, 1, 0 } +}; + +/* Floating-point/Nintendo opcode definitions */ +static const OpDef OPDEFS_FLOATENDO[] = { + { &exaFloating2, &exbFloating, &opSUBF_S, NULL , 2, 10 }, /* 0x00 */ + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaStdTwo , &exbStdTwo , &opCVT_WS, &opReg1, 2, 16 }, + { &exaFloating1, &exbFloating, NULL , NULL , 2, 14 }, + { &exaFloating2, &exbFloating, &opADDF_S, NULL , 2, 28 }, + { &exaFloating2, &exbFloating, &opSUBF_S, NULL , 2, 30 }, + { &exaFloating2, &exbFloating, &opMULF_S, NULL , 2, 28 }, + { &exaFloating2, &exbFloating, &opDIVF_S, NULL , 2, 44 }, + { &exaStdTwo , &exbStdTwo , &opXB , &opReg2, 2, 6 }, + { &exaStdTwo , &exbStdTwo , &opXH , &opReg2, 2, 1 }, + { &exaStdTwo , &exbStdTwo , &opREV , &opReg1, 2, 22 }, + { &exaFloating1, &exbFloating, NULL , NULL , 2, 14 }, + { &exaStdTwo , &exbStdTwo , &opMPYHW , &opReg1, 2, 22 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, /* 0x10 */ + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, /* 0x20 */ + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, /* 0x30 */ + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, + { &exaIllegal , NULL , NULL , NULL , 2, 0 }, +}; + +/* Bit string instructions */ +static int exaBitString(VB *vb) { + OpDef *def; /* Opcode definition */ + vb->cpu.inst.def = def = + (OpDef *) &OPDEFS_BITSTRING[vb->cpu.inst.code[0] & 31]; + return def->executeA(vb); +} + +/* Floating-point and Nintendo instruction parser */ +static int exaFloatendo(VB *vb) { + OpDef *def; /* Opcode definition */ + vb->cpu.inst.def = def = + (OpDef *) &OPDEFS_FLOATENDO[vb->cpu.inst.code[1] >> 10 & 63]; + return def->executeA(vb); +} + + + +/****************************** Pipeline Stages ******************************/ + +/* Raise an exception */ +static void cpuException(VB *vb) { + vb->cpu.inst.def = (OpDef *) &OPDEF_EXCEPTION; + vb->cpu.stage = CPU_EXECUTE_A; + vb->cpu.inst.aux[0] = 0xFFFF0000 | (vb->cpu.exception & 0xFFF0); + if (vb->cpu.inst.aux[0] == (int32_t) 0xFFFFFF70) + vb->cpu.inst.aux[0] = 0xFFFFFF60; +} + +/* Execute: Pre-processing, does not update state */ +static int cpuExecuteA(VB *vb) { + OpDef *def; /* Opcode descriptor */ + VBInstruction inst; /* Instruction descriptor */ + + /* First invocation */ + if (vb->cpu.step == 0 && vb->cpu.exception == 0) { + + /* Call the breakpoint handler */ + if (vb->onExecute != NULL) { + + /* Query the application */ + inst.address = vb->cpu.pc; + inst.code[0] = vb->cpu.inst.code[0]; + inst.code[1] = vb->cpu.inst.code[1]; + inst.size = vb->cpu.inst.size; + if (vb->onExecute(vb, &inst)) + return 1; + + /* Apply changes */ + vb->cpu.inst.code[0] = inst.code[0]; + vb->cpu.inst.code[1] = inst.code[1]; + vb->cpu.inst.size = inst.size; + vb->cpu.inst.def = + (OpDef *) &OPDEFS[vb->cpu.inst.code[0] >> 10 & 63]; + } + + /* Detect non-bit string instruction */ + if ((vb->cpu.inst.code[0] & 0xFC00) != 0x7C00) + vb->cpu.bitstring = 0; + } + + /* Processing before updating simulation state */ + def = vb->cpu.inst.def; + for (;;) { + if (def->executeA(vb)) + return 1; + vb->cpu.step = 0; + + /* Advance to exception processing */ + if (vb->cpu.exception == 0 || def == &OPDEF_EXCEPTION) + break; + def = (OpDef *) &OPDEF_EXCEPTION; + cpuException(vb); + } + + /* Advance to execute B */ + vb->cpu.stage = CPU_EXECUTE_B; + return 0; +} + +/* Execute: Post-processing, updates state */ +static void cpuExecuteB(VB *vb) { + + /* Perform the operation and update state */ + ((OpDef *) vb->cpu.inst.def)->executeB(vb); + vb->cpu.program[0] = 0; + + /* Advance to next pipeline stage */ + if (vb->cpu.stage == CPU_EXECUTE_B) { + if (cpuCheckIRQs(vb)) + cpuException(vb); + else if (vb->cpu.bitstring != 0) + vb->cpu.stage = CPU_EXECUTE_A; + else vb->cpu.stage = CPU_FETCH; + } + +} + +/* Retrieve instruction data from the bus */ +static int cpuFetch(VB *vb) { + OpDef *def; /* Opcode definition */ /* First fetch */ - if (sim->cpu.fetch == 0) { - - /* Update state */ - inst->size = CPU_SIZES[opcode]; - - /* A second fetch is needed */ - if (inst->size == 4) { - sim->cpu.fetch = 1; - return 0; - } + if (vb->cpu.step == 0) { + if (cpuReadFetch(vb)) + return 1; + vb->cpu.inst.def = def = + (OpDef *) &OPDEFS[vb->cpu.inst.code[0] >> 10 & 0x003F]; + vb->cpu.inst.size = def->size << 1; + vb->cpu.step = 1; + } else def = (OpDef *) vb->cpu.inst.def; + /* Second fetch */ + for (; vb->cpu.step < def->size; vb->cpu.step++) { + if (cpuReadFetch(vb)) + return 1; } - /* Determine the internal ID of the instruction */ - inst->id = CPU_OPCODES[opcode]; - switch (inst->id) { - case CPU_BITSTRING: inst->id=CPU_BITSTRINGS[inst->bits[0]&0x1F]; break; - case CPU_FLOATENDO: inst->id=CPU_FLOATENDOS[inst->bits[1]>>10&0x3F]; - } - - /* Update state */ - sim->cpu.fetch = 0; - sim->cpu.state = CPU_EXECUTE; + /* Advance to execute A */ + vb->cpu.stage = CPU_EXECUTE_A; + vb->cpu.step = 0; return 0; } -/* Process the simulation for some number of clocks */ -static int cpuEmulate(VB *sim, uint32_t clocks) { - /* Fatal halt: cannot break */ - if (sim->cpu.state == CPU_FATAL) - return 0; + +/***************************** Module Functions ******************************/ + +/* Process a simulation for a given number of clocks */ +static int cpuEmulate(VB *vb, uint32_t clocks) { /* Process all clocks */ - do { + for (;;) { - /* The next operation is after the remaining clocks */ - if (clocks < sim->cpu.clocks) { - sim->cpu.clocks -= clocks; - return 0; + /* Processing by pipeline stage */ + switch (vb->cpu.stage) { + + /* Fetch: Retrive instruction code from memory */ + case CPU_FETCH: + if (cpuFetch(vb)) + return 1; + break; + + /* Execute A: Check for exceptions, configure CPU clocks */ + case CPU_EXECUTE_A: + if (cpuExecuteA(vb)) + return 1; + break; + + /* Execute B: Wait clocks and update state */ + case CPU_EXECUTE_B: + + /* Clocks remaining exceeds emulation clocks */ + if (clocks < vb->cpu.clocks) { + vb->cpu.clocks -= clocks; + return 0; + } + + /* Update simulation state */ + clocks -= vb->cpu.clocks; + vb->cpu.clocks = 0; + cpuExecuteB(vb); + break; + + /* Halt: Wait for an interrupt */ + case CPU_HALT: + if (!cpuCheckIRQs(vb)) + return 0; + cpuException(vb); + break; + + /* Fatal exception: Cannot recover */ + case CPU_FATAL: + return 0; } - /* Update remaining clocks */ - clocks -= sim->cpu.clocks; - sim->cpu.clocks = 0; + }; - /* Processing by operations state */ - switch (sim->cpu.state) { - case CPU_EXCEPTION: if ( cpuException(sim)) return 1; break; - case CPU_EXECUTE : if ( cpuExecute (sim)) return 1; break; - case CPU_FATAL : return 0; - case CPU_FETCH : if ( cpuFetch (sim)) return 1; break; - case CPU_HALTED : if (!cpuCheckIRQs(sim)) return 0; break; - } - - } while (clocks > 0); - - /* No break occurred */ + /* Unreachable */ return 0; } -/* Simulate a hardware reset */ -static void cpuReset(VB *sim) \ No newline at end of file +/* Compute clocks without breakpoint or state change */ +static int cpuUntil(VB *vb, uint32_t clocks) { + return vb->cpu.stage == CPU_HALT || vb->cpu.stage == CPU_FATAL ? + clocks : Min(vb->cpu.clocks, clocks); +} + + + +#endif /* VBAPI */ diff --git a/core/vb.c b/core/vb.c index cc9dfa7..22ab713 100644 --- a/core/vb.c +++ b/core/vb.c @@ -1,34 +1,35 @@ -#ifdef VB_EXPORT - #define VBAPI VB_EXPORT -#else - #define VBAPI +#ifndef VBAPI +#define VBAPI #endif - -/* Header includes */ -#include #include -/********************************* Constants *********************************/ +/***************************** Utility Functions *****************************/ -/* Type sizes */ -static const uint8_t TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; +/* Select the lesser of two unsigned numbers */ +static uint32_t Min(uint32_t a, uint32_t b) { + return a < b ? a : b; +} + +/* Sign-extend an integer, masking upper bits if positive */ +#ifndef VB_SIGNED_PROPAGATE + /* Generic implementation */ + static int32_t SignExtend(int32_t value, int bits) { + return value & 1 << (bits - 1) ? + value | ~0 << bits : + value & ((1 << bits) - 1) + ; + } +#else + /* Sign-propagating implementation */ + #define SignExtend(v, b) ((int32_t) (v) << (32 - (b)) >> (32 - (b))) +#endif -/********************************** Macros ***********************************/ +/**************************** Sub-Module Imports *****************************/ -/* Sign-extend a value of some number of bits to 32 bits */ -#define SignExtend(v,b) \ - ((v) | (((v) & (1 << ((b) - 1))) ? (uint32_t) 0xFFFFFFFF << (b) : 0)) - - - - -/*************************** Subsystem Components ****************************/ - -/* Component includes */ #include "bus.c" #include "cpu.c" @@ -36,252 +37,246 @@ static const uint8_t TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; /***************************** Module Functions ******************************/ -/* Process a simulation for some number of clocks */ -static int sysEmulate(VB *sim, uint32_t clocks) { - int broke; - broke = cpuEmulate(sim, clocks); - return broke; +/* Process a simulation for a given number of clocks */ +static int sysEmulate(VB *vb, uint32_t clocks) { + return + cpuEmulate(vb, clocks) + ; } -/* Determine the number of clocks before a break condititon could occur */ -static uint32_t sysUntil(VB *sim, uint32_t clocks) { - clocks = cpuUntil(sim, clocks); +/* Determine how many clocks can be simulated without a breakpoint */ +static uint32_t sysUntil(VB *vb, uint32_t clocks) { + clocks = cpuUntil(vb, clocks); return clocks; } -/******************************* API Functions *******************************/ +/************************************ API ************************************/ -/* Associate two simulations as peers, or remove an association */ -void vbConnect(VB *sim1, VB *sim2) { +/* Process a simulation */ +int vbEmulate(VB *vb, uint32_t *clocks) { + int brk; /* A break was requested */ + uint32_t until; /* Number of clocks during which no break will occur */ - /* Disconnect */ - if (sim2 == NULL) { - if (sim1->peer != NULL) - sim1->peer->peer = NULL; - sim1->peer = NULL; - return; + /* Process all clocks */ + for (brk = 0; *clocks != 0 && !brk; *clocks -= until) { + until = sysUntil (vb, *clocks); + brk = sysEmulate(vb, until ); } - /* Disconnect any existing link associations */ - if (sim1->peer != NULL && sim1->peer != sim2) - sim1->peer->peer = NULL; - if (sim2->peer != NULL && sim2->peer != sim1) - sim2->peer->peer = NULL; - - /* Link the two simulations */ - sim1->peer = sim2; - sim2->peer = sim1; -} - -/* Process one simulation */ -int vbEmulate(VB *sim, uint32_t *clocks) { - int broke; /* The simulation requested an application break */ - uint32_t until; /* Maximum clocks before a break could happen */ - - /* Process the simulation until a break condition occurs */ - do { - until = *clocks; - until = sysUntil (sim, until); - broke = sysEmulate(sim, until); - *clocks -= until; - } while (!broke && *clocks > 0); - - return broke; + return brk; } /* Process multiple simulations */ -int vbEmulateMulti(VB **sims, int count, uint32_t *clocks) { - int broke; /* The simulation requested an application break */ - uint32_t until; /* Maximum clocks before a break could happen */ +int vbEmulateEx(VB **vbs, int count, uint32_t *clocks) { + int brk; /* A break was requested */ + uint32_t until; /* Number of clocks during which no break will occur */ int x; /* Iterator */ - /* Process simulations until a break condition occurs */ - do { - broke = 0; + /* Process all clocks */ + for (brk = 0; *clocks != 0 && !brk; *clocks -= until) { until = *clocks; for (x = 0; x < count; x++) - until = sysUntil (sims[x], until); + until = sysUntil (vbs[x], until); for (x = 0; x < count; x++) - broke |= sysEmulate(sims[x], until); - *clocks -= until; - } while (!broke && *clocks > 0); - - return broke; -} - -/* Retrieve a current breakpoint callback */ -void* vbGetCallback(VB *sim, int type) { - void **field; /* Pointer to field within simulation */ - - /* Select the field to update */ - switch (type) { - case VB_ONEXCEPTION: field = (void *) &sim->onException; break; - case VB_ONEXECUTE : field = (void *) &sim->onExecute ; break; - case VB_ONFETCH : field = (void *) &sim->onFetch ; break; - case VB_ONREAD : field = (void *) &sim->onRead ; break; - case VB_ONWRITE : field = (void *) &sim->onWrite ; break; - default: return NULL; + brk |= sysEmulate(vbs[x], until); } - /* Retrieve the simulation field */ - return *field; + return brk; } -/* Retrieve the value of PC */ -uint32_t vbGetProgramCounter(VB *sim) { - return sim->cpu.pc; -} - -/* Retrieve the value of a program register */ -int32_t vbGetProgramRegister(VB *sim, int id) { - return id < 1 || id > 31 ? 0 : sim->cpu.program[id]; -} - -/* Retrieve the ROM buffer */ -void* vbGetROM(VB *sim, uint32_t *size) { - if (size != NULL) - *size = sim->cart.romSize; - return sim->cart.rom; -} - -/* Retrieve the SRAM buffer */ -void* vbGetSRAM(VB *sim, uint32_t *size) { - if (size != NULL) - *size = sim->cart.sramSize; - return sim->cart.sram; -} - -/* Retrieve the value of a system register */ -uint32_t vbGetSystemRegister(VB *sim, int id) { +/* Retrieve a current breakpoint handler */ +void* vbGetCallback(VB *vb, int id) { switch (id) { - case VB_ADTRE: return sim->cpu.adtre; - case VB_CHCW : return sim->cpu.chcw.ice << 1; - case VB_EIPC : return sim->cpu.eipc; - case VB_EIPSW: return sim->cpu.eipsw; - case VB_FEPC : return sim->cpu.fepc; - case VB_FEPSW: return sim->cpu.fepsw; - case VB_PIR : return 0x00005346; - case VB_TKCW : return 0x000000E0; - case 29 : return sim->cpu.sr29; - case 30 : return 0x00000004; - case 31 : return sim->cpu.sr31; - case VB_ECR : return - (uint32_t) sim->cpu.ecr.fecc << 16 | sim->cpu.ecr.eicc; - case VB_PSW : return - (uint32_t) sim->cpu.psw.i << 16 | - (uint32_t) sim->cpu.psw.np << 15 | - (uint32_t) sim->cpu.psw.ep << 14 | - (uint32_t) sim->cpu.psw.ae << 13 | - (uint32_t) sim->cpu.psw.id << 12 | - (uint32_t) sim->cpu.psw.fro << 9 | - (uint32_t) sim->cpu.psw.fiv << 8 | - (uint32_t) sim->cpu.psw.fzd << 7 | - (uint32_t) sim->cpu.psw.fov << 6 | - (uint32_t) sim->cpu.psw.fud << 5 | - (uint32_t) sim->cpu.psw.fpr << 4 | - (uint32_t) sim->cpu.psw.cy << 3 | - (uint32_t) sim->cpu.psw.ov << 2 | - (uint32_t) sim->cpu.psw.s << 1 | - (uint32_t) sim->cpu.psw.z - ; + case VB_ONEXCEPTION: return *(void **)&vb->onException; + case VB_ONEXECUTE : return *(void **)&vb->onExecute; + case VB_ONFETCH : return *(void **)&vb->onFetch; + case VB_ONREAD : return *(void **)&vb->onRead; + case VB_ONWRITE : return *(void **)&vb->onWrite; } - return 0; + return NULL; } -/* Prepare a simulation state instance for use */ -void vbInit(VB *sim) { - - /* Breakpoint callbacks */ - sim->onException = NULL; - sim->onExecute = NULL; - sim->onFetch = NULL; - sim->onRead = NULL; - sim->onWrite = NULL; - - /* System */ - sim->peer = NULL; - - /* Cartridge */ - sim->cart.rom = NULL; - sim->cart.romSize = 0; - sim->cart.sram = NULL; - sim->cart.sramSize = 0; - - /* Everything else */ - vbReset(sim); +/* Retrieve the value of a register */ +int32_t vbGetRegister(VB *vb, int type, int id) { + switch (type) { + case VB_PROGRAM: + return id < 0 || id > 31 ? 0 : vb->cpu.program[id]; + case VB_SYSTEM: + return cpuGetSystemRegister(vb, id); + case VB_OTHER: + switch (id) { + case VB_PC: return vb->cpu.pc; + } + } + return 0; /* Invalid type */ } -/* Read a data unit from the bus */ -int32_t vbRead(VB *sim, uint32_t address, int type, int debug) { - return type < 0 || type >= (int) sizeof TYPE_SIZES ? 0 : - busRead(sim, address, type, debug); +/* Retrieve a handle to the current cartridge ROM data */ +uint8_t* vbGetROM(VB *vb, uint32_t *size) { + if (size != NULL) + *size = vb->cart.romSize; + return vb->cart.rom; +} + +/* Retrieve a handle to the current cartridge RAM data */ +uint8_t* vbGetSRAM(VB *vb, uint32_t *size) { + if (size != NULL) + *size = vb->cart.ramSize; + return vb->cart.ram; +} + +/* Prepare a simulation instance for use */ +void vbInit(VB *vb) { + + /* Breakpoint handlers */ + vb->onException = NULL; + vb->onExecute = NULL; + vb->onFetch = NULL; + vb->onRead = NULL; + vb->onWrite = NULL; + + /* Game pak */ + vb->cart.ram = NULL; + vb->cart.ramSize = 0; + vb->cart.rom = NULL; + vb->cart.romSize = 0; + + /* Hardware reset */ + vbReset(vb); +} + +/* Read a value from memory */ +int32_t vbRead(VB *vb, uint32_t address, int type) { + return busRead(vb, address, type); +} + +/* Read multiple bytes from memory */ +void vbReadEx(VB *vb, uint32_t address, uint8_t *buffer, uint32_t length) { + while (length--) *buffer++ = busRead(vb, address++, VB_U8); } /* Simulate a hardware reset */ -void vbReset(VB *sim) { - uint32_t x; /* Iterator */ +void vbReset(VB *vb) { + int x; /* Iterator */ - /* Subsystem components */ - cpuReset(sim); - - /* WRAM (the hardware does not do this) */ + /* Reset WRAM (the hardware does not do this) */ for (x = 0; x < 0x10000; x++) - sim->wram[x] = 0x00; + vb->wram[x] = 0x00; + + /* CPU (normal) */ + vb->cpu.pc = 0xFFFFFFF0; + cpuSetSystemRegister(vb, VB_ECR, 0x0000FFF0, 1); + cpuSetSystemRegister(vb, VB_PSW, 0x00008000, 1); + for (x = 0; x < 5; x++) + vb->cpu.irq[x] = 0; + + /* CPU (extra, hardware doesn't do this) */ + vb->cpu.adtre = 0x00000000; + vb->cpu.eipc = 0x00000000; + vb->cpu.eipsw = 0x00000000; + vb->cpu.fepc = 0x00000000; + vb->cpu.fepsw = 0x00000000; + vb->cpu.sr29 = 0x00000000; + vb->cpu.sr31 = 0x00000000; + cpuSetSystemRegister(vb, VB_CHCW, 0x00000000, 1); + for (x = 0; x < 32; x++) + vb->cpu.program[x] = 0x00000000; + + /* CPU (internal) */ + vb->cpu.bitstring = 0; + vb->cpu.clocks = 0; + vb->cpu.exception = 0; + vb->cpu.stage = CPU_FETCH; + vb->cpu.step = 0; } -/* Specify a breakpoint callback */ -void* vbSetCallback(VB *sim, int type, void *callback) { - void **field; /* Pointer to field within simulation */ - void *prev; /* Previous value within field */ - - /* Select the field to update */ - switch (type) { - case VB_ONEXCEPTION: field = (void *) &sim->onException; break; - case VB_ONEXECUTE : field = (void *) &sim->onExecute ; break; - case VB_ONFETCH : field = (void *) &sim->onFetch ; break; - case VB_ONREAD : field = (void *) &sim->onRead ; break; - case VB_ONWRITE : field = (void *) &sim->onWrite ; break; - return NULL; +/* Specify a breakpoint handler */ +void* vbSetCallback(VB *vb, int id, void *proc) { + void *prev = vbGetCallback(vb, id); + switch (id) { + case VB_ONEXCEPTION: *(void **)&vb->onException = proc; break; + case VB_ONEXECUTE : *(void **)&vb->onExecute = proc; break; + case VB_ONFETCH : *(void **)&vb->onFetch = proc; break; + case VB_ONREAD : *(void **)&vb->onRead = proc; break; + case VB_ONWRITE : *(void **)&vb->onWrite = proc; break; } - - /* Update the simulation field */ - prev = *field; - *field = callback; return prev; } -/* Specify a new value for PC */ -uint32_t vbSetProgramCounter(VB *sim, uint32_t value) { - value &= 0xFFFFFFFE; - sim->cpu.busWait = 0; - sim->cpu.causeCode = 0; - sim->cpu.clocks = 0; - sim->cpu.fetch = 0; - sim->cpu.pc = value; - sim->cpu.state = CPU_FETCH; - sim->cpu.substring = 0; - return value; +/* Specify a value for a register */ +int32_t vbSetRegister(VB *vb, int type, int id, int32_t value) { + switch (type) { + case VB_PROGRAM: + return id < 1 || id > 31 ? 0 : (vb->cpu.program[id] = value); + case VB_SYSTEM: + return cpuSetSystemRegister(vb, id, value, 1); + case VB_OTHER: + switch (id) { + case VB_PC: + vb->cpu.bitstring = 0; + vb->cpu.clocks = 0; + vb->cpu.exception = 0; + vb->cpu.stage = CPU_FETCH; + return vb->cpu.pc = value & 0xFFFFFFFE; + } + } + return 0; /* Invalid type or ID */ } -/* Specify a new value for a program register */ -int32_t vbSetProgramRegister(VB *sim, int id, int32_t value) { - return id < 1 || id > 31 ? 0 : (sim->cpu.program[id] = value); -} +/* Specify a cartridge ROM buffer */ +int vbSetROM(VB *vb, uint8_t *data, uint32_t size) { -/* Supply a ROM buffer */ -int vbSetROM(VB *sim, void *rom, uint32_t size) { - - /* Check the buffer size */ - if (size < 1024 || size > 0x1000000 || ((size - 1) & size) != 0) + /* Specifying no ROM */ + if (data == NULL) { + vb->cart.rom = NULL; + vb->cart.romSize = 0; return 0; + } - /* Configure the ROM buffer */ - sim->cart.rom = (uint8_t *) rom; - sim->cart.romSize = size; - return 1; + /* Error checking */ + if ( + size < 4 || + size > 0x1000000 || + (size & (size - 1)) /* Power of 2 */ + ) return 1; + + /* Register the ROM data */ + vb->cart.rom = data; + vb->cart.romSize = size; + return 0; } -/* Supply an SRAM buffer */ -int vbSetSRAM(VB *sim, void *sram, uint32_t size) \ No newline at end of file +/* Specify a cartridge RAM buffer */ +int vbSetSRAM(VB *vb, uint8_t *data, uint32_t size) { + + /* Specifying no SRAM */ + if (data == NULL) { + vb->cart.ram = NULL; + vb->cart.ramSize = 0; + return 0; + } + + /* Error checking */ + if ( + size < 4 || + size > 0x1000000 || + (size & (size - 1)) /* Power of 2 */ + ) return 1; + + /* Register the SRAM data */ + vb->cart.ram = data; + vb->cart.ramSize = size; + return 0; +} + +/* Write a value to memory */ +void vbWrite(VB *vb, uint32_t address, int type, int32_t value) { + busWrite(vb, address, type, value, 1); +} + +/* Write multiple values to memory */ +void vbWriteEx(VB *vb, uint32_t address, uint8_t *buffer, uint32_t length) { + while (length--) busWrite(vb, address++, VB_U8, *buffer++, 1); +} diff --git a/core/vb.h b/core/vb.h index 421c2a9..49afac9 100644 Binary files a/core/vb.h and b/core/vb.h differ diff --git a/license.txt b/license.txt index 3fd8c86..1b40ee3 100644 --- a/license.txt +++ b/license.txt @@ -1,4 +1,4 @@ -Copyright (C) 2022 Guy Perfect +Copyright (C) 2023 Guy Perfect This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/makefile b/makefile index 96a4143..53771b8 100644 Binary files a/makefile and b/makefile differ diff --git a/web/core/Core.js b/web/core/Core.js index b441a47..ae8bfe8 100644 --- a/web/core/Core.js +++ b/web/core/Core.js @@ -146,6 +146,15 @@ class Core { }, [], options); } + // Retrieve the value of a program register + getSystemRegister(sim, id, options) { + return this.message({ + command: "getProgramRegister", + id : id, + sim : sim.pointer + }, [], options); + } + // Retrieve the value of a system register getSystemRegister(sim, id, options) { return this.message({ @@ -200,10 +209,10 @@ class Core { } // Specify a value for a program register - setProgramRegister(sim, index, value, options) { + setProgramRegister(sim, id, value, options) { return this.message({ command: "setProgramRegister", - index : index, + id : id, sim : sim.pointer, value : value }, [], options); diff --git a/web/core/CoreThread.js b/web/core/CoreThread.js index 484b095..14a2df6 100644 --- a/web/core/CoreThread.js +++ b/web/core/CoreThread.js @@ -119,11 +119,11 @@ class CoreThread { let program = new Int32Array (32); let system = new Uint32Array(32); for (let x = 0; x < 32; x++) { - program[x] = this.vbGetProgramRegister(msg.sim, x); - system [x] = this.vbGetSystemRegister (msg.sim, x); + program[x] = this.vbGetRegister(msg.sim, 0, x); + system [x] = this.vbGetRegister(msg.sim, 1, x); } return { - pc : this.vbGetProgramCounter(msg.sim) >>> 0, + pc : this.vbGetRegister(msg.sim, 2, 0) >>> 0, program : program, system : system, transfers: [ program.buffer, system.buffer ] @@ -132,12 +132,17 @@ class CoreThread { // Retrieve the value of PC getProgramCounter(msg) { - return { value: this.vbGetProgramCounter(msg.sim) >>> 0 }; + return { value: this.vbGetRegister(msg.sim, 2, 0) >>> 0 }; + } + + // Retrieve the value of a program register + getProgramRegister(msg) { + return { value: this.vbGetRegister(msg.sim, 0, msg.id) }; } // Retrieve the value of a system register getSystemRegister(msg) { - return { value: this.vbGetSystemRegister(msg.sim, msg.id) >>> 0 }; + return { value: this.vbGetRegister(msg.sim, 1, msg.id) >>> 0 }; } // Read multiple bytes from memory @@ -214,19 +219,19 @@ class CoreThread { let pcs = new Array(msg.sims.length); for (let x = 0; x < msg.sims.length; x++) - pcs[x] = this.vbGetProgramCounter(msg.sims[x]) >>> 0; + pcs[x] = this.vbGetRegister(msg.sims[x], 2, 0) >>> 0; return { pcs: pcs }; } // Specify a value for the program counter setProgramCounter(msg) { - return { value: this.vbSetProgramCounter(msg.sim, msg.value) >>> 0 }; + return { value: this.vbSetRegister(msg.sim, 2, 0, msg.value) >>> 0 }; } // Specify a value for a program register setProgramRegister(msg) { - return {value:this.vbSetProgramRegister(msg.sim,msg.index,msg.value)}; + return { value: this.vbSetRegister(msg.sim, 0, msg.id, msg.value) }; } // Specify a cartridge ROM buffer @@ -258,7 +263,7 @@ class CoreThread { // Specify a value for a system register setSystemRegister(msg) { - return {value:this.vbSetSystemRegister(msg.sim,msg.id,msg.value)>>>0}; + return {value:this.vbSetRegister(msg.sim, 1, msg.id, msg.value)>>>0}; } // Execute the current instruction @@ -271,7 +276,7 @@ class CoreThread { let pcs = new Array(msg.sims.length); for (let x = 0; x < msg.sims.length; x++) - pcs[x] = this.vbGetProgramCounter(msg.sims[x]) >>> 0; + pcs[x] = this.vbGetRegister(msg.sims[x], 2, 0) >>> 0; return { pcs: pcs }; } diff --git a/web/core/wasm.c b/web/core/wasm.c index 31fc35c..362306e 100644 --- a/web/core/wasm.c +++ b/web/core/wasm.c @@ -41,22 +41,22 @@ EMSCRIPTEN_KEEPALIVE int PointerSize() { ////////////////////////////// Debugger Commands ////////////////////////////// // Execute until the following instruction -uint32_t RunNextAddress; +static uint32_t RunNextAddress; static int RunNextFetch(VB *vb, int fetch, VBAccess *access) { return access->address == RunNextAddress; } static int RunNextExecute(VB *vb, VBInstruction *inst) { RunNextAddress = inst->address + inst->size; - vbSetOnExecute(vb, NULL); - vbSetOnFetch(vb, &RunNextFetch); + vbSetCallback(vb, VB_ONEXECUTE, NULL); + vbSetCallback(vb, VB_ONFETCH, &RunNextFetch); return 0; } EMSCRIPTEN_KEEPALIVE void RunNext(VB **vbs, int count) { uint32_t clocks = 20000000; // 1s - vbSetOnExecute(vbs[0], &RunNextExecute); - vbEmulateEx (vbs, count, &clocks); - vbSetOnExecute(vbs[0], NULL); - vbSetOnFetch (vbs[0], NULL); + vbSetCallback(vbs[0], VB_ONEXECUTE, &RunNextExecute); + vbEmulateEx (vbs, count, &clocks); + vbSetCallback(vbs[0], VB_ONEXECUTE, NULL); + vbSetCallback(vbs[0], VB_ONFETCH , NULL); } // Execute the current instruction @@ -72,7 +72,8 @@ static int SingleStepFetch(VB *vb, int fetch, VBAccess *access) { EMSCRIPTEN_KEEPALIVE void SingleStep(VB **vbs, int count) { uint32_t clocks = 20000000; // 1s SingleStepBreak = vbs[0]->cpu.stage == 0 ? 0 : 1; - vbSetOnFetch(vbs[0], &SingleStepFetch); - vbEmulateEx (vbs, count, &clocks); - vbSetOnFetch(vbs[0], NULL); + vbSetCallback(vbs[0], VB_ONFETCH, &SingleStepFetch); + vbEmulateEx (vbs, count, &clocks); + vbSetCallback(vbs[0], VB_ONEXECUTE, NULL); + vbSetCallback(vbs[0], VB_ONFETCH , NULL); }