pvbemu/core/cpu.c

1650 lines
54 KiB
C
Raw Normal View History

2021-09-06 00:09:15 +00:00
/* This file is included into vb.c and cannot be compiled on its own. */
#ifdef VBAPI
/********************************* Constants *********************************/
2023-03-11 00:44:57 +00:00
/* Pipeline stages */
2021-09-19 01:31:40 +00:00
#define CPU_FETCH 0
2023-03-11 00:44:57 +00:00
#define CPU_EXECUTE_A 1
#define CPU_EXECUTE_B 2
#define CPU_HALT 3
2021-09-19 01:31:40 +00:00
#define CPU_FATAL 4
2021-09-06 00:09:15 +00:00
2023-03-11 00:44:57 +00:00
/*********************************** Types ***********************************/
2021-09-06 00:09:15 +00:00
2023-03-11 00:44:57 +00:00
/* Handler types */
typedef int (*ExecuteAProc )(VB *);
typedef void (*ExecuteBProc )(VB *);
typedef void (*OperationProc)(VB *, int32_t *, int32_t);
typedef int32_t (*OperandProc )(VB *);
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* 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;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Floating-point auxiliary memory */
typedef struct {
float f32; /* 32-bit result */
double f64; /* 64-bit result */
} FloatAux;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/***************************** Utility Functions *****************************/
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Check for an interrupt exception condition */
2023-03-11 01:00:45 +00:00
static int cpuCheckIRQs(VB *sim) {
2023-03-11 00:44:57 +00:00
int x; /* Iterator */
/* Interrupts are masked */
2023-03-11 01:00:45 +00:00
if (sim->cpu.psw.id || sim->cpu.psw.ep || sim->cpu.psw.np)
2021-09-19 01:31:40 +00:00
return 0;
2023-03-11 00:44:57 +00:00
/* Check for interrupt requests */
2023-03-11 01:00:45 +00:00
for (x = 4; x >= sim->cpu.psw.i; x--) {
if (!sim->cpu.irq[x])
2023-03-11 00:44:57 +00:00
continue;
2023-03-11 01:00:45 +00:00
sim->cpu.exception = 0xFE00 | x << 4;
2023-03-11 00:44:57 +00:00
return 1;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* No interrupt */
return 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Test a condition */
2023-03-11 01:00:45 +00:00
static int cpuCondition(VB *sim, int index) {
2023-03-11 00:44:57 +00:00
switch (index) {
2023-03-11 01:00:45 +00:00
case 0: return sim->cpu.psw.ov; /*V */
case 1: return sim->cpu.psw.cy; /*C,L*/
case 2: return sim->cpu.psw.z; /*E,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 */
case 7: return (sim->cpu.psw.ov^sim->cpu.psw.s)|sim->cpu.psw.z;/*LE */
2021-09-19 01:31:40 +00:00
}
2023-03-11 01:00:45 +00:00
return !cpuCondition(sim, index - 8);
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Retrieve the value of a system register */
2023-03-11 01:00:45 +00:00
static uint32_t cpuGetSystemRegister(VB *sim, int id) {
2023-03-11 00:44:57 +00:00
switch (id) {
2023-03-11 01:00:45 +00:00
case VB_ADTRE: return sim->cpu.adtre;
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;
2023-03-11 00:44:57 +00:00
case VB_PIR : return 0x00005346;
case VB_TKCW : return 0x000000E0;
2023-03-11 01:00:45 +00:00
case 29 : return sim->cpu.sr29;
2023-03-11 00:44:57 +00:00
case 30 : return 0x00000004;
2023-03-11 01:00:45 +00:00
case 31 : return sim->cpu.sr31;
2023-03-11 00:44:57 +00:00
case VB_CHCW : return
2023-03-11 01:00:45 +00:00
(uint32_t) sim->cpu.chcw.ice << 1
2023-03-11 00:44:57 +00:00
;
case VB_ECR : return
2023-03-11 01:00:45 +00:00
(uint32_t) sim->cpu.ecr.fecc << 16 |
(uint32_t) sim->cpu.ecr.eicc
2023-03-11 00:44:57 +00:00
;
case VB_PSW : return
2023-03-11 01:00:45 +00:00
(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
2023-03-11 00:44:57 +00:00
;
}
return 0; /* Invalid ID */
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Read a memory value from the bus */
2023-03-11 01:00:45 +00:00
static int cpuRead(VB *sim, uint32_t address, int type, int32_t *value) {
2023-03-11 00:44:57 +00:00
VBAccess access; /* Bus access descriptor */
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Retrieve the value from the simulation state */
access.clocks = 0; /* TODO: Needs research */
2023-03-11 01:00:45 +00:00
access.value = busRead(sim, address, type);
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Call the breakpoint handler */
2023-03-11 01:00:45 +00:00
if (sim->onRead != NULL) {
2023-03-11 00:44:57 +00:00
access.address = address;
access.type = type;
2023-03-11 01:00:45 +00:00
if (sim->onRead(sim, &access))
2021-09-19 01:31:40 +00:00
return 1;
}
2023-03-11 00:44:57 +00:00
/* Post-processing */
2023-03-11 01:00:45 +00:00
sim->cpu.clocks += access.clocks;
2023-03-11 00:44:57 +00:00
*value = access.value;
2021-09-19 01:31:40 +00:00
return 0;
}
2023-03-11 00:44:57 +00:00
/* Fetch an instruction code unit from the bus */
2023-03-11 01:00:45 +00:00
static int cpuReadFetch(VB *sim) {
2023-03-11 00:44:57 +00:00
VBAccess access; /* Bus access descriptor */
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Retrieve the value from the simulation state */
2023-03-11 01:00:45 +00:00
access.address = sim->cpu.pc + (sim->cpu.step << 1);
2023-03-11 00:44:57 +00:00
access.clocks = 0; /* TODO: Prefetch makes this tricky */
2023-03-11 01:00:45 +00:00
access.value = busRead(sim, access.address, VB_U16);
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Call the breakpoint handler */
2023-03-11 01:00:45 +00:00
if (sim->onFetch != NULL) {
2023-03-11 00:44:57 +00:00
access.type = VB_U16;
2023-03-11 01:00:45 +00:00
if (sim->onFetch(sim, sim->cpu.step, &access))
2023-03-11 00:44:57 +00:00
return 1;
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Post-processing */
2023-03-11 01:00:45 +00:00
sim->cpu.clocks += access.clocks;
sim->cpu.inst.code[sim->cpu.step++] = access.value;
2023-03-11 00:44:57 +00:00
return 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* 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 */ \
)
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Specify a value for a system register */
2023-03-11 01:00:45 +00:00
static uint32_t cpuSetSystemRegister(VB *sim,int id,uint32_t value,int debug) {
2023-03-11 00:44:57 +00:00
switch (id) {
2023-03-11 01:00:45 +00:00
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;
2023-03-11 00:44:57 +00:00
case VB_PIR : return 0x00005346;
case VB_TKCW : return 0x000000E0;
2023-03-11 01:00:45 +00:00
case 29 : return sim->cpu.sr29 = value;
2023-03-11 00:44:57 +00:00
case 30 : return 0x00000004;
case 31 : return
2023-03-11 01:00:45 +00:00
sim->cpu.sr31 = debug || value < (uint32_t) 0x80000000 ?
2023-03-11 00:44:57 +00:00
value : (uint32_t) -(int32_t)value;
case VB_CHCW:
/* TODO: Manage cache functions */
2023-03-11 01:00:45 +00:00
sim->cpu.chcw.ice = value >> 1 & 1;
2023-03-11 00:44:57 +00:00
return value & 0x00000002;
case VB_ECR:
if (debug) {
2023-03-11 01:00:45 +00:00
sim->cpu.ecr.fecc = value >> 16 & 0xFFFF;
sim->cpu.ecr.eicc = value & 0xFFFF;
2023-03-11 00:44:57 +00:00
}
2023-03-11 01:00:45 +00:00
return (uint32_t) sim->cpu.ecr.fecc << 16 | sim->cpu.ecr.eicc;
2023-03-11 00:44:57 +00:00
case VB_PSW:
2023-03-11 01:00:45 +00:00
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;
2023-03-11 00:44:57 +00:00
return value & 0x000FF3FF;
}
return 0; /* Invalid ID */
}
2021-09-20 21:29:00 +00:00
2023-03-11 00:44:57 +00:00
/* Prepare to write a memory value to the bus */
2023-03-11 01:00:45 +00:00
static int cpuWritePre(VB *sim,uint32_t *address,int32_t *type,int32_t *value){
2023-03-11 00:44:57 +00:00
VBAccess access; /* Bus access descriptor */
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Determine how many clocks the access will take */
access.clocks = 0; /* TODO: Needs research */
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Call the breakpoint handler */
2023-03-11 01:00:45 +00:00
if (sim->onWrite != NULL) {
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Query the application */
access.address = *address;
access.value = *value;
access.type = *type;
2023-03-11 01:00:45 +00:00
if (sim->onWrite(sim, &access))
2023-03-11 00:44:57 +00:00
return 1;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Apply changes */
*address = access.address;
*value = access.value;
if (access.type <= VB_S32)
*type = access.type;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Post-processing */
2023-03-11 01:00:45 +00:00
sim->cpu.clocks += access.clocks;
2021-09-19 01:31:40 +00:00
return 0;
}
2023-03-11 00:44:57 +00:00
/**************************** Execute A Handlers *****************************/
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Standard two-operand instruction */
2023-03-11 01:00:45 +00:00
static int exaStdTwo(VB *sim) {
OpDef *def = (OpDef *) sim->cpu.inst.def;
sim->cpu.inst.aux[0] = def->operand(sim);
sim->cpu.clocks += def->aux;
2023-03-11 00:44:57 +00:00
return 0;
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Standard three-operand instruction */
2023-03-11 01:00:45 +00:00
static int exaStdThree(VB *sim) {
OpDef *def = (OpDef *) sim->cpu.inst.def;
sim->cpu.inst.aux[0] = def->operand(sim);
sim->cpu.inst.aux[1] = sim->cpu.program[sim->cpu.inst.code[0] & 31];
sim->cpu.clocks += def->aux;
2023-03-11 00:44:57 +00:00
return 0;
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Bit string bitwise */
2023-03-11 01:00:45 +00:00
static int exaBitBitwise(VB *sim) {
2023-03-11 00:44:57 +00:00
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 */
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Initial invocation */
2023-03-11 01:00:45 +00:00
if (sim->cpu.step == 0)
sim->cpu.step = sim->cpu.bitstring + 1;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Read the low-order 32 source bits */
2023-03-11 01:00:45 +00:00
if (sim->cpu.step == 1) {
if (cpuRead(sim, sim->cpu.program[30], VB_S32, &sim->cpu.inst.aux[0]))
2021-09-19 01:31:40 +00:00
return 1;
2023-03-11 01:00:45 +00:00
sim->cpu.clocks += 4; /* TODO: Needs research */
sim->cpu.step = 2;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Read the high-order 32 source bits */
2023-03-11 01:00:45 +00:00
if (sim->cpu.step == 2) {
if (cpuRead(sim,sim->cpu.program[30]+4,VB_S32,&sim->cpu.inst.aux[1]))
2021-09-19 01:31:40 +00:00
return 1;
2023-03-11 01:00:45 +00:00
sim->cpu.clocks += 4; /* TODO: Needs research */
sim->cpu.step = 3;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Read the destination bits */
2023-03-11 01:00:45 +00:00
if (sim->cpu.step == 3) {
if (cpuRead(sim, sim->cpu.program[29], VB_S32, &sim->cpu.inst.aux[2]))
2023-03-11 00:44:57 +00:00
return 1;
2023-03-11 01:00:45 +00:00
sim->cpu.clocks += 4; /* TODO: Needs research */
sim->cpu.step = 4;
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Compute the result */
2023-03-11 01:00:45 +00:00
if (sim->cpu.step == 4) {
length = sim->cpu.program[28];
offDest = sim->cpu.program[26] & 31;
offSrc = sim->cpu.program[27] & 31;
result = sim->cpu.inst.aux[0];
valDest = sim->cpu.inst.aux[2];
2023-03-11 00:44:57 +00:00
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
2023-03-11 01:00:45 +00:00
result |= sim->cpu.inst.aux[1] << (32 + bits);
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Compose the destination value */
2023-03-11 01:00:45 +00:00
((OpDef *) sim->cpu.inst.def)
->operation(sim, (int32_t *) &result, valDest);
2023-03-11 00:44:57 +00:00
bits = (1 << offDest) - 1;
if (length < 32 && offDest + length < 32)
bits |= (uint32_t) 0xFFFFFFFF << (offDest + length);
2023-03-11 01:00:45 +00:00
sim->cpu.inst.aux[2] = (result & ~bits) | (valDest & bits);
2023-03-11 00:44:57 +00:00
/* Prepare to write the result */
2023-03-11 01:00:45 +00:00
sim->cpu.inst.aux[3] = sim->cpu.program[29] & 0xFFFFFFFC;
sim->cpu.inst.aux[4] = VB_S32;
if (cpuWritePre(sim, (uint32_t *) &sim->cpu.inst.aux[3],
&sim->cpu.inst.aux[4], &sim->cpu.inst.aux[2]))
2021-09-19 01:31:40 +00:00
return 1;
2023-03-11 01:00:45 +00:00
sim->cpu.clocks += 4; /* TODO: Needs research */
2021-09-19 01:31:40 +00:00
}
return 0;
}
2023-03-11 00:44:57 +00:00
/* Bit string search */
2023-03-11 01:00:45 +00:00
static int exaBitSearch(VB *sim) {
if (cpuRead(sim, sim->cpu.program[30], VB_S32, &sim->cpu.inst.aux[0]))
2023-03-11 00:44:57 +00:00
return 1;
2023-03-11 01:00:45 +00:00
sim->cpu.clocks += 4; /* TODO: Needs research */
2023-03-11 00:44:57 +00:00
return 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Branch on condition */
2023-03-11 01:00:45 +00:00
static int exaBCOND(VB *sim) {
if (cpuCondition(sim, sim->cpu.inst.code[0] >> 9 & 15)) {
sim->cpu.inst.aux[0] =
(sim->cpu.pc + SignExtend(sim->cpu.inst.code[0], 9)) & 0xFFFFFFFE;
sim->cpu.clocks += 3;
2023-03-11 00:44:57 +00:00
} else {
2023-03-11 01:00:45 +00:00
sim->cpu.inst.aux[0] = sim->cpu.pc + sim->cpu.inst.size;
sim->cpu.clocks += 1;
2023-03-11 00:44:57 +00:00
}
return 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Compare and exchange interlocked */
2023-03-11 01:00:45 +00:00
static int exaCAXI(VB *sim) {
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* First invocation */
2023-03-11 01:00:45 +00:00
if (sim->cpu.step == 0) {
exaStdThree(sim);
sim->cpu.inst.aux[0] += sim->cpu.inst.aux[1]; /* Address */
sim->cpu.inst.aux[1] = VB_S32; /* Write type */
sim->cpu.inst.aux[3] = sim->cpu.program[sim->cpu.inst.code[0]>>5&31];
sim->cpu.step = 1;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Read the lock word and determine the exchange value */
2023-03-11 01:00:45 +00:00
if (sim->cpu.step == 1) {
if (cpuRead(sim, sim->cpu.inst.aux[0], VB_S32, &sim->cpu.inst.aux[4]))
2023-03-11 00:44:57 +00:00
return 1;
2023-03-11 01:00:45 +00:00
sim->cpu.inst.aux[2] = sim->cpu.inst.aux[3] == sim->cpu.inst.aux[4] ?
sim->cpu.program[30] : sim->cpu.inst.aux[4];
sim->cpu.step = 2;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Prepare to write the exchange value */
2023-03-11 01:00:45 +00:00
if (sim->cpu.step == 2) {
if (cpuWritePre(sim, (uint32_t *) &sim->cpu.inst.aux[0],
&sim->cpu.inst.aux[1], &sim->cpu.inst.aux[2]))
2023-03-11 00:44:57 +00:00
return 1;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
return 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* No special action */
2023-03-11 01:00:45 +00:00
static int exaDefault(VB *sim) {
sim->cpu.clocks += ((OpDef *) sim->cpu.inst.def)->aux;
2023-03-11 00:44:57 +00:00
return 0;
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Division */
2023-03-11 01:00:45 +00:00
static int exaDivision(VB *sim) {
exaStdTwo(sim);
if (sim->cpu.inst.aux[0] == 0) {
sim->cpu.clocks = 0; /* exaStdTwo adds clocks */
sim->cpu.exception = 0xFF80; /* Zero division */
2023-03-11 00:44:57 +00:00
}
return 0;
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Exception */
2023-03-11 01:00:45 +00:00
static int exaException(VB *sim) {
2023-03-11 00:44:57 +00:00
VBException exception; /* Exception descriptor */
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Initial invocation */
2023-03-11 01:00:45 +00:00
if (sim->cpu.step == 0) {
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Call the breakpoint handler */
2023-03-11 01:00:45 +00:00
if (sim->onException != NULL) {
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Query the application */
2023-03-11 01:00:45 +00:00
exception.address = sim->cpu.inst.aux[0];
exception.code = sim->cpu.exception;
2023-03-11 00:44:57 +00:00
exception.cancel = 0;
2023-03-11 01:00:45 +00:00
if (sim->onException(sim, &exception))
2023-03-11 00:44:57 +00:00
return 1;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* The application canceled the exception */
if (exception.cancel) {
2023-03-11 01:00:45 +00:00
sim->cpu.exception = 0;
sim->cpu.stage = CPU_FETCH;
2023-03-11 00:44:57 +00:00
return 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Apply changes */
2023-03-11 01:00:45 +00:00
sim->cpu.inst.aux[0] = exception.address;
sim->cpu.exception = exception.code;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Fatal exception: stage values for writing */
2023-03-11 01:00:45 +00:00
if (sim->cpu.psw.np) {
sim->cpu.inst.aux[0] = 0x00000000;
sim->cpu.inst.aux[1] = VB_S32;
sim->cpu.inst.aux[2] = 0xFFFF0000 | sim->cpu.exception;
sim->cpu.inst.aux[3] = 0x00000004;
sim->cpu.inst.aux[4] = VB_S32;
sim->cpu.inst.aux[5] = cpuGetSystemRegister(sim, VB_PSW);
sim->cpu.inst.aux[6] = 0x00000008;
sim->cpu.inst.aux[7] = VB_S32;
sim->cpu.inst.aux[8] = sim->cpu.pc;
sim->cpu.step = 1;
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Other exception */
2023-03-11 01:00:45 +00:00
else sim->cpu.step = 10;
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Prepare to dump fatal exception diagnostic values to memory */
2023-03-11 01:00:45 +00:00
for (; sim->cpu.step < 10; sim->cpu.step += 3) {
if (cpuWritePre(sim, (uint32_t *)
&sim->cpu.inst.aux[sim->cpu.step - 1],
&sim->cpu.inst.aux[sim->cpu.step ],
&sim->cpu.inst.aux[sim->cpu.step + 1]
2021-09-19 01:31:40 +00:00
)) return 1;
}
2023-03-11 00:44:57 +00:00
/* Common processing */
2023-03-11 01:00:45 +00:00
sim->cpu.bitstring = 0;
sim->cpu.clocks += 1; /* TODO: Needs research */
2021-09-19 01:31:40 +00:00
return 0;
}
2023-03-11 00:44:57 +00:00
/* One-operand floating-point instruction */
2023-03-11 01:00:45 +00:00
static int exaFloating1(VB *sim) {
2023-03-11 00:44:57 +00:00
int bits; /* Number of bits to shift */
int32_t reg1; /* Left operand */
int32_t result; /* Operation result */
int32_t subop; /* Sub-opcode */
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Reserved operand */
2023-03-11 01:00:45 +00:00
reg1 = sim->cpu.program[sim->cpu.inst.code[0] & 31];
2023-03-11 00:44:57 +00:00
if (cpuFRO(reg1)) {
2023-03-19 23:15:55 +00:00
sim->cpu.fpFlags = 0x00000200; /* FRO */
2023-03-11 01:00:45 +00:00
sim->cpu.exception = 0xFF60;
2023-03-11 00:44:57 +00:00
return 0;
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Working variables */
bits = (reg1 >> 23 & 0xFF) - 150;
result = (reg1 & 0x007FFFFF) | 0x00800000;
2023-03-11 01:00:45 +00:00
subop = sim->cpu.inst.code[1] >> 10 & 63;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Zero */
if ((reg1 & 0x7FFFFFFF) == 0x00000000)
result = 0;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Minimum negative value */
else if (bits == 8 && result == 0x00800000 && reg1 < 0)
result = INT32_MIN;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Shifting left */
else if (bits > 0) {
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Invalid operation */
if (bits > 7) {
2023-03-19 23:15:55 +00:00
sim->cpu.fpFlags = 0x00000100; /* FIV */
2023-03-11 01:00:45 +00:00
sim->cpu.exception = 0xFF70;
2021-09-19 01:31:40 +00:00
return 0;
2023-03-11 00:44:57 +00:00
}
/* Compute result */
result <<= bits;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* 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 */
2023-03-19 23:15:55 +00:00
sim->cpu.fpFlags = result==*(float *)&reg1 ? 0 : 0x00000010; /* FPR */
2023-03-11 01:00:45 +00:00
sim->cpu.inst.aux[0] = result;
sim->cpu.inst.aux[1] = subop;
sim->cpu.clocks += ((OpDef *) sim->cpu.inst.def)->aux;
2021-09-19 01:31:40 +00:00
return 0;
}
2023-03-11 00:44:57 +00:00
/* Two-operand floating-point instruction */
2023-03-11 01:00:45 +00:00
static int exaFloating2(VB *sim) {
2023-03-11 00:44:57 +00:00
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 */
2023-03-11 01:00:45 +00:00
OpDef *def = (OpDef *) sim->cpu.inst.def;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Reserved operand */
2023-03-11 01:00:45 +00:00
reg1 = sim->cpu.program[sim->cpu.inst.code[0] & 31];
reg2 = sim->cpu.program[sim->cpu.inst.code[0] >> 5 & 31];
2023-03-11 00:44:57 +00:00
if (cpuFRO(reg1) || cpuFRO(reg2)) {
2023-03-19 23:15:55 +00:00
sim->cpu.fpFlags = 0x00000200; /* FRO */
2023-03-11 01:00:45 +00:00
sim->cpu.exception = 0xFF60;
2023-03-11 00:44:57 +00:00
return 0;
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Perform the operation */
2023-03-11 01:00:45 +00:00
def->operation(sim, &reg2, reg1);
if (sim->cpu.exception != 0)
2023-03-11 00:44:57 +00:00
return 0; /* Handled in opDIVF_S() */
2023-03-11 01:00:45 +00:00
aux = (FloatAux *) &sim->cpu.inst.aux;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Overflow */
bits = 0x7F7FFFFF; /* Maximum value */
test = *(float *)&bits;
if (aux->f64 > test || aux->f64 < -test) {
2023-03-19 23:15:55 +00:00
sim->cpu.fpFlags = 0x00000040; /* FOV */
2023-03-11 01:00:45 +00:00
sim->cpu.exception = 0xFF64;
2023-03-11 00:44:57 +00:00
return 0;
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Process result */
2023-03-19 23:15:55 +00:00
bits = *(int32_t *)&aux->f32;
sim->cpu.fpFlags = 0;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Zero */
if ((bits & 0x7FFFFFFF) == 0x00000000)
aux->f32 = bits = 0;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Underflow */
else if ((bits & 0x7F800000) == 0x00000000) {
2023-03-19 23:15:55 +00:00
sim->cpu.fpFlags = 0x00000020; /* FUD */
aux->f32 = bits = 0;
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Precision degradation */
if (aux->f32 != aux->f64)
2023-03-19 23:15:55 +00:00
sim->cpu.fpFlags |= 0x00000010; /* FPR */
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Other state */
2023-03-11 01:00:45 +00:00
sim->cpu.inst.aux[0] = bits;
sim->cpu.inst.aux[1] = sim->cpu.inst.code[1] >> 10 & 63;
sim->cpu.clocks += def->aux;
2023-03-11 00:44:57 +00:00
return 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Illegal opcode */
2023-03-11 01:00:45 +00:00
static int exaIllegal(VB *sim) {
sim->cpu.exception = 0xFF90; /* Illegal opcode */
2023-03-11 00:44:57 +00:00
return 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Jump relative, jump and link */
2023-03-11 01:00:45 +00:00
static int exaJR(VB *sim) {
sim->cpu.inst.aux[0] = 0xFFFFFFFE & (sim->cpu.pc + SignExtend(
(int32_t) sim->cpu.inst.code[0] << 16 | sim->cpu.inst.code[1], 26));
sim->cpu.clocks += 3;
2023-03-11 00:44:57 +00:00
return 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Memory read */
2023-03-11 01:00:45 +00:00
static int exaRead(VB *sim) {
2023-03-11 00:44:57 +00:00
/* First invocation */
2023-03-11 01:00:45 +00:00
if (sim->cpu.step == 0) {
exaStdThree(sim);
sim->cpu.inst.aux[1] += sim->cpu.inst.aux[0]; /* Address */
sim->cpu.clocks += 5; /* TODO: Needs research */
sim->cpu.step = 1;
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Read the value */
2023-03-11 01:00:45 +00:00
return cpuRead(sim, sim->cpu.inst.aux[1],
((OpDef *) sim->cpu.inst.def)->aux, &sim->cpu.inst.aux[0]);
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Trap */
2023-03-11 01:00:45 +00:00
static int exaTRAP(VB *sim) {
2023-03-11 00:44:57 +00:00
/* TODO: Clocks is less 1 here because exaException adds 1 */
2023-03-11 01:00:45 +00:00
sim->cpu.clocks += ((OpDef *) sim->cpu.inst.def)->aux - 1;
sim->cpu.exception = 0xFFA0 | (sim->cpu.inst.code[0] & 31);
2023-03-11 00:44:57 +00:00
return 0;
}
2021-09-19 19:36:30 +00:00
2023-03-11 00:44:57 +00:00
/* Memory write */
2023-03-11 01:00:45 +00:00
static int exaWrite(VB *sim) {
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* First invocation */
2023-03-11 01:00:45 +00:00
if (sim->cpu.step == 0) {
exaStdThree(sim);
sim->cpu.inst.aux[0] += sim->cpu.inst.aux[1];
sim->cpu.inst.aux[1] = ((OpDef *) sim->cpu.inst.def)->aux; /* Type */
sim->cpu.inst.aux[2] = sim->cpu.program[sim->cpu.inst.code[0]>>5&31];
sim->cpu.clocks += 4; /* TODO: Needs research */
sim->cpu.step = 1;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Write the value */
2023-03-11 01:00:45 +00:00
return cpuWritePre(sim, (uint32_t *) &sim->cpu.inst.aux[0],
&sim->cpu.inst.aux[1], &sim->cpu.inst.aux[2]);
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/**************************** Execute B Handlers *****************************/
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Bit string bitwise */
2023-03-11 01:00:45 +00:00
static void exbBitBitwise(VB *sim) {
2023-03-11 00:44:57 +00:00
int32_t bits;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Write the output value */
2023-03-11 01:00:45 +00:00
if (sim->cpu.program[28] != 0) {
busWrite(sim, sim->cpu.inst.aux[3],
sim->cpu.inst.aux[4], sim->cpu.inst.aux[2], 0);
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Prepare registers */
2023-03-11 01:00:45 +00:00
sim->cpu.program[26] &= 0x0000001F;
sim->cpu.program[27] &= 0x0000001F;
sim->cpu.program[29] &= 0xFFFFFFFC;
sim->cpu.program[30] &= 0xFFFFFFFC;
2023-03-11 00:44:57 +00:00
/* Determine how many bits of output have been processed */
2023-03-11 01:00:45 +00:00
bits = 32 - sim->cpu.program[26];
if ((uint32_t) sim->cpu.program[28] <= (uint32_t) bits)
bits = sim->cpu.program[28];
2023-03-11 00:44:57 +00:00
/* Update source */
2023-03-11 01:00:45 +00:00
sim->cpu.program[27] += bits;
if (sim->cpu.program[27] >= 32) {
sim->cpu.program[27] &= 31;
sim->cpu.program[30] += 4;
sim->cpu.inst.aux[0] = sim->cpu.inst.aux[1];
sim->cpu.bitstring = 1; /* Read next source word */
} else sim->cpu.bitstring = 2; /* Skip source reads */
2023-03-11 00:44:57 +00:00
/* Update destination */
2023-03-11 01:00:45 +00:00
sim->cpu.program[26] += bits;
if (sim->cpu.program[26] >= 32) {
sim->cpu.program[26] &= 31;
sim->cpu.program[29] += 4;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Update length */
2023-03-11 01:00:45 +00:00
sim->cpu.program[28] -= bits;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Advance to the next instruction */
2023-03-11 01:00:45 +00:00
if (sim->cpu.program[28] == 0) {
sim->cpu.bitstring = 0;
sim->cpu.pc += sim->cpu.inst.size;
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Bit string search */
2023-03-11 01:00:45 +00:00
static void exbBitSearch(VB *sim) {
int32_t dir = ((~sim->cpu.inst.code[0] & 1) << 1) - 1;
int32_t test = sim->cpu.inst.code[0] >> 1 & 1;
2023-03-11 00:44:57 +00:00
/* Prepare registers */
2023-03-11 01:00:45 +00:00
sim->cpu.program[27] &= 0x0000001F;
sim->cpu.program[30] &= 0xFFFFFFFC;
sim->cpu.psw.z = 1;
sim->cpu.bitstring = 1;
2023-03-11 00:44:57 +00:00
/* Process all remaining bits in the current word */
2023-03-11 01:00:45 +00:00
while (sim->cpu.psw.z && sim->cpu.program[28] != 0) {
2023-03-11 00:44:57 +00:00
/* The bit does not match */
if (
2023-03-11 01:00:45 +00:00
(sim->cpu.inst.aux[0] & 1 << sim->cpu.program[27]) !=
test << sim->cpu.program[27]
) sim->cpu.program[29]++;
2023-03-11 00:44:57 +00:00
/* A match was found */
2023-03-11 01:00:45 +00:00
else sim->cpu.psw.z = 0;
2023-03-11 00:44:57 +00:00
/* Advance to the next bit */
2023-03-11 01:00:45 +00:00
sim->cpu.program[28]--;
sim->cpu.program[27] += dir;
if (sim->cpu.program[27] & 0x00000020) {
sim->cpu.program[27] &= 0x0000001F;
sim->cpu.program[30] += dir << 2;
2023-03-11 00:44:57 +00:00
break;
}
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Advance to the next instruction */
2023-03-11 01:00:45 +00:00
if (!sim->cpu.psw.z || sim->cpu.program[28] == 0) {
sim->cpu.bitstring = 0;
sim->cpu.pc += sim->cpu.inst.size;
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Compare and exchange interlocked */
2023-03-11 01:00:45 +00:00
static void exbCAXI(VB *sim) {
int32_t left = sim->cpu.inst.aux[3];
int32_t right = sim->cpu.inst.aux[4];
2023-03-11 00:44:57 +00:00
int32_t result = left - right;
2023-03-11 01:00:45 +00:00
sim->cpu.psw.cy = (uint32_t) left < (uint32_t) right;
sim->cpu.psw.ov = (int32_t) ((left ^ right) & (left ^ result)) < 0;
sim->cpu.psw.s = result < 0;
sim->cpu.psw.z = result == 0;
sim->cpu.pc += sim->cpu.inst.size;
sim->cpu.program[sim->cpu.inst.code[0] >> 5 & 31] = right;
busWrite(sim, sim->cpu.inst.aux[0],
sim->cpu.inst.aux[1], sim->cpu.inst.aux[2], 0);
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Clear interrupt disable flag */
2023-03-11 01:00:45 +00:00
static void exbCLI(VB *sim) {
sim->cpu.pc += sim->cpu.inst.size;
sim->cpu.psw.id = 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Exception */
2023-03-11 01:00:45 +00:00
static void exbException(VB *sim) {
2023-03-11 00:44:57 +00:00
int x; /* Iterator */
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Apply staged floating-point flags */
2023-03-19 23:15:55 +00:00
if (sim->cpu.fpFlags != 0) {
cpuSetSystemRegister(sim, VB_PSW, sim->cpu.fpFlags |
2023-03-11 01:00:45 +00:00
cpuGetSystemRegister(sim, VB_PSW), 0);
2023-03-19 23:15:55 +00:00
sim->cpu.fpFlags = 0;
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Fatal exception */
2023-03-11 01:00:45 +00:00
if (sim->cpu.psw.np) {
2023-03-11 00:44:57 +00:00
for (x = 0; x < 9; x += 3) {
2023-03-11 01:00:45 +00:00
busWrite(sim, sim->cpu.inst.aux[x],
sim->cpu.inst.aux[x + 1], sim->cpu.inst.aux[x + 2], 0);
2023-03-11 00:44:57 +00:00
}
2023-03-11 01:00:45 +00:00
sim->cpu.stage = CPU_FATAL;
2021-09-19 01:31:40 +00:00
return;
}
2023-03-11 00:44:57 +00:00
/* Duplexed exception */
2023-03-11 01:00:45 +00:00
if (sim->cpu.psw.ep) {
sim->cpu.ecr.fecc = sim->cpu.exception;
sim->cpu.fepc = sim->cpu.pc;
sim->cpu.fepsw = cpuGetSystemRegister(sim, VB_PSW);
sim->cpu.pc = 0xFFFFFFD0;
sim->cpu.psw.np = 1;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Regular exception */
2021-09-19 01:31:40 +00:00
else {
2023-03-11 01:00:45 +00:00
sim->cpu.ecr.eicc = sim->cpu.exception;
sim->cpu.eipc = sim->cpu.pc;
sim->cpu.eipsw = cpuGetSystemRegister(sim, VB_PSW);
sim->cpu.pc = sim->cpu.inst.aux[0];
sim->cpu.psw.ep = 1;
2023-03-11 00:44:57 +00:00
/* Interrupt */
2023-03-11 01:00:45 +00:00
if (sim->cpu.exception < 0xFF00) {
if ((sim->cpu.inst.code[0] & 0xFC00) == 0x6800) /* HALT */
sim->cpu.eipc += sim->cpu.inst.size;
sim->cpu.psw.i = Min(15, (sim->cpu.exception >> 4 & 15) + 1);
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* TRAP */
2023-03-11 01:00:45 +00:00
if ((sim->cpu.exception & 0xFFE0) == 0xFFA0)
sim->cpu.eipc += sim->cpu.inst.size;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Common processing */
2023-03-11 01:00:45 +00:00
sim->cpu.psw.ae = 0;
sim->cpu.psw.id = 1;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Floating-point instruction */
2023-03-11 01:00:45 +00:00
static void exbFloating(VB *sim) {
int32_t result = sim->cpu.inst.aux[0]; /* Operation result */
int32_t subop = sim->cpu.inst.aux[1]; /* Sub-opcode */
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Apply staged floating-point flags */
2023-03-19 23:15:55 +00:00
if (sim->cpu.fpFlags != 0) {
cpuSetSystemRegister(sim, VB_PSW, sim->cpu.fpFlags |
2023-03-11 01:00:45 +00:00
cpuGetSystemRegister(sim, VB_PSW), 0);
2023-03-19 23:15:55 +00:00
sim->cpu.fpFlags = 0;
2021-09-19 01:31:40 +00:00
}
/* Update state */
2023-03-11 01:00:45 +00:00
sim->cpu.pc += sim->cpu.inst.size;
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = result < 0;
sim->cpu.psw.z = result == 0;
2023-03-11 00:44:57 +00:00
if (subop != 0x03 && subop != 0x0B) /* CVT.SW, TRNC.SW */
2023-03-11 01:00:45 +00:00
sim->cpu.psw.cy = result < 0;
2023-03-11 00:44:57 +00:00
if (subop != 0x00) /* CMPF.S */
2023-03-11 01:00:45 +00:00
sim->cpu.program[sim->cpu.inst.code[0] >> 5 & 31] = result;
2021-09-19 01:31:40 +00:00
}
/* Halt */
2023-03-11 01:00:45 +00:00
static void exbHALT(VB *sim) {
sim->cpu.stage = CPU_HALT;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Jump and link */
2023-03-11 01:00:45 +00:00
static void exbJAL(VB *sim) {
sim->cpu.program[31] = sim->cpu.pc + sim->cpu.inst.size;
sim->cpu.pc = sim->cpu.inst.aux[0];
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Jump */
2023-03-11 01:00:45 +00:00
static void exbJMP(VB *sim) {
sim->cpu.pc = sim->cpu.inst.aux[0];
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Return from trap or interrupt */
2023-03-11 01:00:45 +00:00
static void exbRETI(VB *sim) {
if (sim->cpu.psw.np) {
sim->cpu.pc = sim->cpu.fepc;
cpuSetSystemRegister(sim, VB_PSW, sim->cpu.fepsw, 0);
2023-03-11 00:44:57 +00:00
} else {
2023-03-11 01:00:45 +00:00
sim->cpu.pc = sim->cpu.eipc;
cpuSetSystemRegister(sim, VB_PSW, sim->cpu.eipsw, 0);
2023-03-11 00:44:57 +00:00
}
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Set interrupt disable flag */
2023-03-11 01:00:45 +00:00
static void exbSEI(VB *sim) {
sim->cpu.pc += sim->cpu.inst.size;
sim->cpu.psw.id = 1;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Standard two-operand instruction */
2023-03-11 01:00:45 +00:00
static void exbStdTwo(VB *sim) {
((OpDef *) sim->cpu.inst.def)->operation(sim,
&sim->cpu.program[sim->cpu.inst.code[0] >> 5 & 31],
sim->cpu.inst.aux[0]
2023-03-11 00:44:57 +00:00
);
2023-03-11 01:00:45 +00:00
sim->cpu.pc += sim->cpu.inst.size;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Standard three-operand instruction */
2023-03-11 01:00:45 +00:00
static void exbStdThree(VB *sim) {
int32_t *reg2 = &sim->cpu.program[sim->cpu.inst.code[0] >> 5 & 31];
*reg2 = sim->cpu.inst.aux[1];
((OpDef *) sim->cpu.inst.def)->operation(sim, reg2, sim->cpu.inst.aux[0]);
sim->cpu.pc += sim->cpu.inst.size;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/**************************** Operation Handlers *****************************/
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Add */
2023-03-11 01:00:45 +00:00
static void opADD(VB *sim, int32_t *dest, int32_t src) {
int32_t result = *dest + src;
sim->cpu.psw.cy = (uint32_t) result < (uint32_t) *dest;
sim->cpu.psw.ov = (int32_t) (~(*dest ^ src) & (*dest ^ result)) < 0;
sim->cpu.psw.s = result < 0;
sim->cpu.psw.z = result == 0;
*dest = result;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Add Floating Short */
2023-03-11 01:00:45 +00:00
static void opADDF_S(VB *sim, int32_t *dest, int32_t src) {
FloatAux *aux = (FloatAux *) sim->cpu.inst.aux;
2023-03-11 00:44:57 +00:00
double left = *(float *)dest;
double right = *(float *)&src;
double result = left + right;
aux->f32 = result;
aux->f64 = result;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* And */
2023-03-11 01:00:45 +00:00
static void opAND(VB *sim, int32_t *dest, int32_t src) {
int32_t result = *dest & src;
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = result < 0;
sim->cpu.psw.z = result == 0;
*dest = result;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* And Bit String Upward */
2023-03-11 01:00:45 +00:00
static void opANDBSU(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
*dest &= src;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* And Not Bit String Upward */
2023-03-11 01:00:45 +00:00
static void opANDNBSU(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
*dest = ~*dest & src;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Compare */
2023-03-11 01:00:45 +00:00
static void opCMP(VB *sim, int32_t *dest, int32_t src) {
2023-03-11 00:44:57 +00:00
int32_t result = *dest - src;
2023-03-11 01:00:45 +00:00
sim->cpu.psw.cy = (uint32_t) *dest < (uint32_t) src;
sim->cpu.psw.ov = (int32_t) ((*dest ^ src) & (*dest ^ result)) < 0;
sim->cpu.psw.s = result < 0;
sim->cpu.psw.z = result == 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Convert Word Integer to Short Floating */
2023-03-11 01:00:45 +00:00
static void opCVT_WS(VB *sim, int32_t *dest, int32_t src) {
2023-03-11 00:44:57 +00:00
float value = (float) src;
*dest = *(int32_t *)&value;
if ((double) value != (double) src)
2023-03-11 01:00:45 +00:00
sim->cpu.psw.fpr = 1;
2023-03-11 00:44:57 +00:00
}
/* Divide signed */
2023-03-11 01:00:45 +00:00
static void opDIV(VB *sim, int32_t *dest, int32_t src) {
2023-03-11 00:44:57 +00:00
int32_t result;
if (*dest == INT32_MIN && src == -1) {
2023-03-11 01:00:45 +00:00
sim->cpu.psw.ov = 1;
sim->cpu.psw.s = 1;
sim->cpu.psw.z = 0;
sim->cpu.program[30] = 0;
2023-03-11 00:44:57 +00:00
} else {
2023-03-11 01:00:45 +00:00
result = *dest / src;
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = result < 0;
sim->cpu.psw.z = result == 0;
sim->cpu.program[30] = *dest % src;
*dest = result;
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Divide Floating Short */
2023-03-11 01:00:45 +00:00
static void opDIVF_S(VB *sim, int32_t *dest, int32_t src) {
FloatAux *aux = (FloatAux *) sim->cpu.inst.aux;
2023-03-11 00:44:57 +00:00
double left; /* Left operand */
double right; /* Right operand */
double result; /* Operation result */
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Divisor is zero */
if (*dest == 0) {
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Invalid operation */
if (src == 0) {
2023-03-19 23:15:55 +00:00
sim->cpu.fpFlags = 0x00000100; /* FIV */
2023-03-11 01:00:45 +00:00
sim->cpu.exception = 0xFF70;
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Zero division */
else {
2023-03-19 23:15:55 +00:00
sim->cpu.fpFlags = 0x00000080; /* FZD */
2023-03-11 01:00:45 +00:00
sim->cpu.exception = 0xFF68;
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
return;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Perform the operation */
left = *(float *)dest;
right = *(float *)&src;
result = left / right;
aux->f32 = result;
aux->f64 = result;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Divide unsigned */
2023-03-11 01:00:45 +00:00
static void opDIVU(VB *sim, int32_t *dest, int32_t src) {
uint32_t result = (uint32_t) *dest / (uint32_t) src;
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = (int32_t) result < 0;
sim->cpu.psw.z = result == 0;
sim->cpu.program[30] = (int32_t) ((uint32_t) *dest % (uint32_t) src);
*dest = (int32_t) result;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Load to system register */
2023-03-11 01:00:45 +00:00
static void opLDSR(VB *sim, int32_t *dest, int32_t src) {
cpuSetSystemRegister(sim, src, *dest, 0);
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Move */
2023-03-11 01:00:45 +00:00
static void opMOV(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
*dest = src;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Move Bit String Upward */
2023-03-11 01:00:45 +00:00
static void opMOVBSU(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
(void) dest;
(void) src;
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Add Immediate */
2023-03-11 01:00:45 +00:00
static void opMOVEA(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
*dest += src;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Multiply Halfword */
2023-03-11 01:00:45 +00:00
static void opMPYHW(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
*dest *= SignExtend(src, 17);
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Multiply signed */
2023-03-11 01:00:45 +00:00
static void opMUL(VB *sim, int32_t *dest, int32_t src) {
int64_t result = (int64_t) *dest * (int64_t) src;
int32_t resultLow = (int32_t) result;
sim->cpu.psw.ov = result != resultLow;
sim->cpu.psw.s = resultLow < 0;
sim->cpu.psw.z = resultLow == 0;
sim->cpu.program[30] = (int32_t) (result >> 32);
*dest = resultLow;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Multiply Floating Short */
2023-03-11 01:00:45 +00:00
static void opMULF_S(VB *sim, int32_t *dest, int32_t src) {
FloatAux *aux = (FloatAux *) sim->cpu.inst.aux;
2023-03-11 00:44:57 +00:00
double left = *(float *)dest;
double right = *(float *)&src;
double result = left * right;
aux->f32 = result;
aux->f64 = result;
}
/* Multiply unsigned */
2023-03-11 01:00:45 +00:00
static void opMULU(VB *sim, 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;
sim->cpu.psw.ov = result != resultLow;
sim->cpu.psw.s = (int32_t) resultLow < 0;
sim->cpu.psw.z = resultLow == 0;
sim->cpu.program[30] = (int32_t) (result >> 32);
*dest = (int32_t) resultLow;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Not */
2023-03-11 01:00:45 +00:00
static void opNOT(VB *sim, int32_t *dest, int32_t src) {
2023-03-11 00:44:57 +00:00
int32_t result = ~src;
2023-03-11 01:00:45 +00:00
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = result < 0;
sim->cpu.psw.z = result == 0;
*dest = result;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Not Bit String Upward */
2023-03-11 01:00:45 +00:00
static void opNOTBSU(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
(void) src;
*dest = ~*dest;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Or */
2023-03-11 01:00:45 +00:00
static void opOR(VB *sim, int32_t *dest, int32_t src) {
int32_t result = *dest | src;
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = result < 0;
sim->cpu.psw.z = result == 0;
*dest = result;
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Or Bit String Upward */
2023-03-11 01:00:45 +00:00
static void opORBSU(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
*dest |= src;
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Or Not Bit String Upward */
2023-03-11 01:00:45 +00:00
static void opORNBSU(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
*dest = ~*dest | src;
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Reverse Bits in Word */
2023-03-11 01:00:45 +00:00
static void opREV(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
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 */
2023-03-11 01:00:45 +00:00
static void opSETF(VB *sim, int32_t *dest, int32_t src) {
*dest = cpuCondition(sim, src & 15);
2023-03-11 00:44:57 +00:00
}
/* Shift right arithmetic */
2023-03-11 01:00:45 +00:00
static void opSAR(VB *sim, int32_t *dest, int32_t src) {
2023-03-11 00:44:57 +00:00
int32_t result = *dest >> (src &= 31);
#ifndef VB_SIGNED_PROPAGATE
if (src != 0)
result = SignExtend(result, 32 - src);
#endif
2023-03-11 01:00:45 +00:00
sim->cpu.psw.cy = src != 0 && *dest & 1 << (src - 1);
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = result < 0;
sim->cpu.psw.z = result == 0;
*dest = result;
2023-03-11 00:44:57 +00:00
}
/* Shift left */
2023-03-11 01:00:45 +00:00
static void opSHL(VB *sim, int32_t *dest, int32_t src) {
int32_t result = *dest << (src &= 31);
sim->cpu.psw.cy = src != 0 && *dest & 1 << (32 - src);
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = result < 0;
sim->cpu.psw.z = result == 0;
*dest = result;
2023-03-11 00:44:57 +00:00
}
/* Shift right logical */
2023-03-11 01:00:45 +00:00
static void opSHR(VB *sim, int32_t *dest, int32_t src) {
2023-03-11 00:44:57 +00:00
int32_t result = (uint32_t) *dest >> (src &= 31);
#ifndef VB_SIGNED_PROPAGATE
if (src != 0)
result &= ((uint32_t) 1 << (32 - src)) - 1;
#endif
2023-03-11 01:00:45 +00:00
sim->cpu.psw.cy = src != 0 && *dest & 1 << (src - 1);
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = result < 0;
sim->cpu.psw.z = result == 0;
*dest = result;
2023-03-11 00:44:57 +00:00
}
/* Store */
2023-03-11 01:00:45 +00:00
static void opST(VB *sim, int32_t *dest, int32_t src) {
2023-03-11 00:44:57 +00:00
(void) dest, (void) src;
2023-03-11 01:00:45 +00:00
busWrite(sim, sim->cpu.inst.aux[0],
sim->cpu.inst.aux[1], sim->cpu.inst.aux[2], 0);
2023-03-11 00:44:57 +00:00
}
/* Store to system register */
2023-03-11 01:00:45 +00:00
static void opSTSR(VB *sim, int32_t *dest, int32_t src) {
*dest = cpuGetSystemRegister(sim, src);
2021-09-19 01:31:40 +00:00
}
/* Subtract */
2023-03-11 01:00:45 +00:00
static void opSUB(VB *sim, int32_t *dest, int32_t src) {
int32_t result = *dest - src;
sim->cpu.psw.cy = (uint32_t) *dest < (uint32_t) src;
sim->cpu.psw.ov = (int32_t) ((*dest ^ src) & (*dest ^ result)) < 0;
sim->cpu.psw.s = result < 0;
sim->cpu.psw.z = result == 0;
*dest = result;
2021-09-19 01:31:40 +00:00
}
/* Subtract Floating Short */
2023-03-11 01:00:45 +00:00
static void opSUBF_S(VB *sim, int32_t *dest, int32_t src) {
FloatAux *aux = (FloatAux *) sim->cpu.inst.aux;
2023-03-11 00:44:57 +00:00
double left = *(float *)dest;
double right = *(float *)&src;
double result = left - right;
aux->f32 = result;
aux->f64 = result;
2021-09-19 01:31:40 +00:00
}
/* Exchange Byte */
2023-03-11 01:00:45 +00:00
static void opXB(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
*dest = (src & 0xFFFF0000) | (src << 8 & 0xFF00) | (src >> 8 & 0x00FF);
2021-09-19 01:31:40 +00:00
}
/* Exchange Halfword */
2023-03-11 01:00:45 +00:00
static void opXH(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
*dest = (src << 16 & 0xFFFF0000) | (src >> 16 & 0x0000FFFF);
2021-09-19 01:31:40 +00:00
}
/* Exclusive Or */
2023-03-11 01:00:45 +00:00
static void opXOR(VB *sim, int32_t *dest, int32_t src) {
int32_t result = *dest ^ src;
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = result < 0;
sim->cpu.psw.z = result == 0;
*dest = result;
2021-09-19 01:31:40 +00:00
}
/* Exclusive Or Bit String Upward */
2023-03-11 01:00:45 +00:00
static void opXORBSU(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
*dest ^= src;
2021-09-19 01:31:40 +00:00
}
2021-09-19 19:36:30 +00:00
/* Exclusive Or Not Bit String Upward */
2023-03-11 01:00:45 +00:00
static void opXORNBSU(VB *sim, int32_t *dest, int32_t src) {
(void) sim;
2023-03-11 00:44:57 +00:00
*dest = ~*dest ^ src;
}
/***************************** Operand Handlers ******************************/
/* imm5 (sign-extended) */
2023-03-11 01:00:45 +00:00
static int32_t opImm5S(VB *sim) {
return SignExtend(sim->cpu.inst.code[0] & 31, 5);
2023-03-11 00:44:57 +00:00
}
/* imm5 */
2023-03-11 01:00:45 +00:00
static int32_t opImm5U(VB *sim) {
return sim->cpu.inst.code[0] & 31;
2023-03-11 00:44:57 +00:00
}
/* imm16 (shifted left by 16) */
2023-03-11 01:00:45 +00:00
static int32_t opImm16H(VB *sim) {
return (uint32_t) sim->cpu.inst.code[1] << 16;
2023-03-11 00:44:57 +00:00
}
/* imm16 (sign-extended) */
2023-03-11 01:00:45 +00:00
static int32_t opImm16S(VB *sim) {
return SignExtend(sim->cpu.inst.code[1], 16);
2023-03-11 00:44:57 +00:00
}
/* imm16 */
2023-03-11 01:00:45 +00:00
static int32_t opImm16U(VB *sim) {
return sim->cpu.inst.code[1];
2023-03-11 00:44:57 +00:00
}
/* reg1 */
2023-03-11 01:00:45 +00:00
static int32_t opReg1(VB *sim) {
return sim->cpu.program[sim->cpu.inst.code[0] & 31];
2023-03-11 00:44:57 +00:00
}
/* reg2 */
2023-03-11 01:00:45 +00:00
static int32_t opReg2(VB *sim) {
return sim->cpu.program[sim->cpu.inst.code[0] >> 5 & 31];
2023-03-11 00:44:57 +00:00
}
/**************************** 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 }
};
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* 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 }
};
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* 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 },
};
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Bit string instructions */
2023-03-11 01:00:45 +00:00
static int exaBitString(VB *sim) {
2023-03-11 00:44:57 +00:00
OpDef *def; /* Opcode definition */
2023-03-11 01:00:45 +00:00
sim->cpu.inst.def = def =
(OpDef *) &OPDEFS_BITSTRING[sim->cpu.inst.code[0] & 31];
return def->executeA(sim);
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Floating-point and Nintendo instruction parser */
2023-03-11 01:00:45 +00:00
static int exaFloatendo(VB *sim) {
2023-03-11 00:44:57 +00:00
OpDef *def; /* Opcode definition */
2023-03-11 01:00:45 +00:00
sim->cpu.inst.def = def =
(OpDef *) &OPDEFS_FLOATENDO[sim->cpu.inst.code[1] >> 10 & 63];
return def->executeA(sim);
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/****************************** Pipeline Stages ******************************/
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Raise an exception */
2023-03-11 01:00:45 +00:00
static void cpuException(VB *sim) {
sim->cpu.inst.def = (OpDef *) &OPDEF_EXCEPTION;
sim->cpu.stage = CPU_EXECUTE_A;
sim->cpu.inst.aux[0] = 0xFFFF0000 | (sim->cpu.exception & 0xFFF0);
if (sim->cpu.inst.aux[0] == (int32_t) 0xFFFFFF70)
sim->cpu.inst.aux[0] = 0xFFFFFF60;
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Execute: Pre-processing, does not update state */
2023-03-11 01:00:45 +00:00
static int cpuExecuteA(VB *sim) {
2023-03-11 00:44:57 +00:00
OpDef *def; /* Opcode descriptor */
VBInstruction inst; /* Instruction descriptor */
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* First invocation */
2023-03-11 01:00:45 +00:00
if (sim->cpu.step == 0 && sim->cpu.exception == 0) {
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Call the breakpoint handler */
2023-03-11 01:00:45 +00:00
if (sim->onExecute != NULL) {
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Query the application */
2023-03-11 01:00:45 +00:00
inst.address = sim->cpu.pc;
inst.code[0] = sim->cpu.inst.code[0];
inst.code[1] = sim->cpu.inst.code[1];
inst.size = sim->cpu.inst.size;
if (sim->onExecute(sim, &inst))
2021-09-19 01:31:40 +00:00
return 1;
2023-03-11 00:44:57 +00:00
/* Apply changes */
2023-03-11 01:00:45 +00:00
sim->cpu.inst.code[0] = inst.code[0];
sim->cpu.inst.code[1] = inst.code[1];
sim->cpu.inst.size = inst.size;
sim->cpu.inst.def =
(OpDef *) &OPDEFS[sim->cpu.inst.code[0] >> 10 & 63];
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Detect non-bit string instruction */
2023-03-11 01:00:45 +00:00
if ((sim->cpu.inst.code[0] & 0xFC00) != 0x7C00)
sim->cpu.bitstring = 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Processing before updating simulation state */
2023-03-11 01:00:45 +00:00
def = sim->cpu.inst.def;
2023-03-11 00:44:57 +00:00
for (;;) {
2023-03-11 01:00:45 +00:00
if (def->executeA(sim))
2023-03-11 00:44:57 +00:00
return 1;
2023-03-11 01:00:45 +00:00
sim->cpu.step = 0;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Advance to exception processing */
2023-03-11 01:00:45 +00:00
if (sim->cpu.exception == 0 || def == &OPDEF_EXCEPTION)
2023-03-11 00:44:57 +00:00
break;
def = (OpDef *) &OPDEF_EXCEPTION;
2023-03-11 01:00:45 +00:00
cpuException(sim);
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Advance to execute B */
2023-03-11 01:00:45 +00:00
sim->cpu.stage = CPU_EXECUTE_B;
2023-03-11 00:44:57 +00:00
return 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Execute: Post-processing, updates state */
2023-03-11 01:00:45 +00:00
static void cpuExecuteB(VB *sim) {
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Perform the operation and update state */
2023-03-11 01:00:45 +00:00
((OpDef *) sim->cpu.inst.def)->executeB(sim);
sim->cpu.program[0] = 0;
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Advance to next pipeline stage */
2023-03-11 01:00:45 +00:00
if (sim->cpu.stage == CPU_EXECUTE_B) {
if (cpuCheckIRQs(sim))
cpuException(sim);
else if (sim->cpu.bitstring != 0)
sim->cpu.stage = CPU_EXECUTE_A;
else sim->cpu.stage = CPU_FETCH;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
}
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Retrieve instruction data from the bus */
2023-03-11 01:00:45 +00:00
static int cpuFetch(VB *sim) {
2023-03-11 00:44:57 +00:00
OpDef *def; /* Opcode definition */
2021-09-19 01:31:40 +00:00
/* First fetch */
2023-03-11 01:00:45 +00:00
if (sim->cpu.step == 0) {
if (cpuReadFetch(sim))
2023-03-11 00:44:57 +00:00
return 1;
2023-03-11 01:00:45 +00:00
sim->cpu.inst.def = def =
(OpDef *) &OPDEFS[sim->cpu.inst.code[0] >> 10 & 0x003F];
sim->cpu.inst.size = def->size << 1;
sim->cpu.step = 1;
} else def = (OpDef *) sim->cpu.inst.def;
2023-03-11 00:44:57 +00:00
/* Second fetch */
2023-03-11 01:00:45 +00:00
for (; sim->cpu.step < def->size; sim->cpu.step++) {
if (cpuReadFetch(sim))
2023-03-11 00:44:57 +00:00
return 1;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
/* Advance to execute A */
2023-03-11 01:00:45 +00:00
sim->cpu.stage = CPU_EXECUTE_A;
sim->cpu.step = 0;
2021-09-19 01:31:40 +00:00
return 0;
}
2023-03-11 00:44:57 +00:00
/***************************** Module Functions ******************************/
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Process a simulation for a given number of clocks */
2023-03-11 01:00:45 +00:00
static int cpuEmulate(VB *sim, uint32_t clocks) {
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Process all clocks */
for (;;) {
/* Processing by pipeline stage */
2023-03-11 01:00:45 +00:00
switch (sim->cpu.stage) {
2023-03-11 00:44:57 +00:00
/* Fetch: Retrive instruction code from memory */
case CPU_FETCH:
2023-03-11 01:00:45 +00:00
if (cpuFetch(sim))
2023-03-11 00:44:57 +00:00
return 1;
break;
/* Execute A: Check for exceptions, configure CPU clocks */
case CPU_EXECUTE_A:
2023-03-11 01:00:45 +00:00
if (cpuExecuteA(sim))
2023-03-11 00:44:57 +00:00
return 1;
break;
/* Execute B: Wait clocks and update state */
case CPU_EXECUTE_B:
/* Clocks remaining exceeds emulation clocks */
2023-03-11 01:00:45 +00:00
if (clocks < sim->cpu.clocks) {
sim->cpu.clocks -= clocks;
2023-03-11 00:44:57 +00:00
return 0;
}
/* Update simulation state */
2023-03-11 01:00:45 +00:00
clocks -= sim->cpu.clocks;
sim->cpu.clocks = 0;
cpuExecuteB(sim);
2023-03-11 00:44:57 +00:00
break;
/* Halt: Wait for an interrupt */
case CPU_HALT:
2023-03-11 01:00:45 +00:00
if (!cpuCheckIRQs(sim))
2023-03-11 00:44:57 +00:00
return 0;
2023-03-11 01:00:45 +00:00
cpuException(sim);
2023-03-11 00:44:57 +00:00
break;
/* Fatal exception: Cannot recover */
case CPU_FATAL:
return 0;
2021-09-19 01:31:40 +00:00
}
2023-03-11 00:44:57 +00:00
};
2021-09-19 01:31:40 +00:00
2023-03-11 00:44:57 +00:00
/* Unreachable */
2021-09-19 01:31:40 +00:00
return 0;
}
2023-03-11 00:44:57 +00:00
/* Compute clocks without breakpoint or state change */
2023-03-11 01:00:45 +00:00
static int cpuUntil(VB *sim, uint32_t clocks) {
return sim->cpu.stage == CPU_HALT || sim->cpu.stage == CPU_FATAL ?
clocks : Min(sim->cpu.clocks, clocks);
2023-03-11 00:44:57 +00:00
}
#endif /* VBAPI */