Implement floating-point instructions

This commit is contained in:
Guy Perfect 2024-10-11 19:15:27 -05:00
parent 2e0af6b109
commit 5f563e6cac
2 changed files with 321 additions and 151 deletions

View File

@ -426,6 +426,23 @@ static void cpuAdvance(VB *sim, uint32_t clocks) {
sim->cpu.step = 0; sim->cpu.step = 0;
} }
/* Interpret floating short bits as word integer bits */
static int32_t cpuFloatToWord(float x) {
return *(int32_t *) &x;
}
/* Raise an exception */
static int cpuThrow(VB *sim, uint16_t cause) {
sim->cpu.exception = cause;
sim->cpu.operation = CPU_EXCEPTION;
return 0;
}
/* Interpret word integer bits as floating short bits */
static float cpuWordToFloat(int32_t x) {
return *(float *) &x;
}
/* Retrieve the value of a system register */ /* Retrieve the value of a system register */
static uint32_t cpuGetSystemRegister(VB *sim, int index) { static uint32_t cpuGetSystemRegister(VB *sim, int index) {
switch (index) { switch (index) {
@ -545,6 +562,56 @@ static int cpuCondition(VB *sim, int id) {
return !cpuCondition(sim, id & 7); return !cpuCondition(sim, id & 7);
} }
/* Floating-point common processing */
static int cpuFloatCommon(VB *sim, double value, int32_t *bits) {
float floatVal;
/* Overflow */
if (value < -FLT_MAX || value > FLT_MAX) {
/* TODO: CPU does give reg2 some value */
sim->cpu.psw.fov = 1;
cpuThrow(sim, 0xFF64);
return 1;
}
/* Underflow */
if (value < 0 ? value > -FLT_MIN : value < FLT_MIN) {
sim->cpu.psw.fud = 1;
floatVal = 0;
/* TODO: Can this produce negative zero? */
}
/* Regular conversion */
else floatVal = value;
/* Precision degradation */
if (floatVal != value)
sim->cpu.psw.fpr = 1;
/* Update state */
*bits = cpuFloatToWord(floatVal);
sim->cpu.psw.cy = floatVal < 0;
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = floatVal < 0;
sim->cpu.psw.z = floatVal == 0;
return 0;
}
/* Test whether a floating-point register value is a reserved operand */
static int cpuFloatReservedOne(int32_t bits) {
int32_t e = bits >> 23 & 0xFF;
return e ? (bits & 0x7FFFFFFF) != 0 : e == 0xFF;
}
/* Test whether floating-point register values are reserved operands */
static int cpuFloatReserved(VB *sim, int32_t a, int32_t b) {
if (!(cpuFloatReservedOne(a) || cpuFloatReservedOne(b)))
return 0;
sim->cpu.psw.fro = 1;
cpuThrow(sim, 0xFF60);
return 1;
}
/* Jump and branch common processing */ /* Jump and branch common processing */
static void cpuJump(VB *sim, uint32_t address) { static void cpuJump(VB *sim, uint32_t address) {
sim->cpu.clocks += cpuClocks(3); sim->cpu.clocks += cpuClocks(3);
@ -667,46 +734,55 @@ static int cpuST_OUT(VB *sim, int type) {
/************************** Instruction Operations ***************************/ /************************** Instruction Operations ***************************/
/* ADD immediate */ /* ADD immediate */
static int cpuADDImm(VB *sim) { static void cpuADDImm(VB *sim) {
cpuSetReg2(sim, cpuAdd(sim, cpuGetImm5S(sim))); cpuSetReg2(sim, cpuAdd(sim, cpuGetImm5S(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* ADD register */ /* ADD register */
static int cpuADDReg(VB *sim) { static void cpuADDReg(VB *sim) {
cpuSetReg2(sim, cpuAdd(sim, cpuGetReg1(sim))); cpuSetReg2(sim, cpuAdd(sim, cpuGetReg1(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0; }
/* ADDF.S */
static void cpuADDF_S(VB *sim) {
int32_t a = cpuGetReg2(sim);
int32_t b = cpuGetReg1(sim);
double c; /* Result */
int32_t d; /* Float bits for result */
if (cpuFloatReserved(sim, a, b))
return;
c = (double) cpuWordToFloat(a) + cpuWordToFloat(b);
if (cpuFloatCommon(sim, c, &d))
return;
cpuSetReg2(sim, d);
cpuAdvance(sim, cpuClocks(28)); /* TODO: Research */
} }
/* ADDI */ /* ADDI */
static int cpuADDI(VB *sim) { static void cpuADDI(VB *sim) {
cpuSetReg2(sim, cpuAdd(sim, cpuGetImm16S(sim))); cpuSetReg2(sim, cpuAdd(sim, cpuGetImm16S(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* AND */ /* AND */
static int cpuAND(VB *sim) { static void cpuAND(VB *sim) {
cpuSetReg2(sim, cpuBitwise(sim, cpuGetReg2(sim) & cpuGetReg1(sim))); cpuSetReg2(sim, cpuBitwise(sim, cpuGetReg2(sim) & cpuGetReg1(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* ANDI */ /* ANDI */
static int cpuANDI(VB *sim) { static void cpuANDI(VB *sim) {
cpuSetReg2(sim, cpuBitwise(sim, cpuGetReg2(sim) & cpuGetImm16U(sim))); cpuSetReg2(sim, cpuBitwise(sim, cpuGetReg2(sim) & cpuGetImm16U(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* BCOND */ /* BCOND */
static int cpuBCOND(VB *sim) { static void cpuBCOND(VB *sim) {
if (cpuCondition(sim, cpuGetCond(sim))) if (cpuCondition(sim, cpuGetCond(sim)))
cpuJump(sim, sim->cpu.pc + cpuGetDisp9(sim)); cpuJump(sim, sim->cpu.pc + cpuGetDisp9(sim));
else cpuAdvance(sim, cpuClocks(1)); else cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* CAXI */ /* CAXI */
@ -749,28 +825,78 @@ static int cpuCAXI(VB *sim) {
} }
/* CLI */ /* CLI */
static int cpuCLI(VB *sim) { static void cpuCLI(VB *sim) {
sim->cpu.psw.id = 0; sim->cpu.psw.id = 0;
cpuAdvance(sim, cpuClocks(12)); cpuAdvance(sim, cpuClocks(12));
return 0;
} }
/* CMP immediate */ /* CMP immediate */
static int cpuCMPImm(VB *sim) { static void cpuCMPImm(VB *sim) {
cpuSubtract(sim, cpuGetImm5S(sim)); cpuSubtract(sim, cpuGetImm5S(sim));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* CMP register */ /* CMP register */
static int cpuCMPReg(VB *sim) { static void cpuCMPReg(VB *sim) {
cpuSubtract(sim, cpuGetReg1(sim)); cpuSubtract(sim, cpuGetReg1(sim));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0; }
/* CMPF.S */
static void cpuCMPF_S(VB *sim) {
int32_t a = cpuGetReg2(sim);
int32_t b = cpuGetReg1(sim);
double c; /* Result */
int32_t d; /* Float bits for result */
if (cpuFloatReserved(sim, a, b))
return;
c = (double) cpuWordToFloat(a) - cpuWordToFloat(b);
if (cpuFloatCommon(sim, c, &d))
return;
cpuAdvance(sim, cpuClocks(10)); /* TODO: Research */
}
/* CVT.SW */
static void cpuCVT_SW(VB *sim) {
double f;
int32_t w = cpuGetReg1(sim);
if (cpuFloatReservedOne(w)) {
cpuThrow(sim, 0xFF60);
return;
}
f = cpuWordToFloat(w);
if (f <= -2147483648.5 || f >= 2147483647.5) {
sim->cpu.psw.fiv = 1;
cpuThrow(sim, 0xFF70);
return;
}
w = f < 0 ? f - 0.5 : f + 0.5;
cpuSetReg2(sim, w);
if (w != f)
sim->cpu.psw.fpr = 1;
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = w < 0;
sim->cpu.psw.z = w == 0;
cpuAdvance(sim, cpuClocks(14)); /* TODO: Research */
}
/* CVT.WS */
static void cpuCVT_WS(VB *sim) {
int32_t w = cpuGetReg1(sim);
float f = w;
if (f != w)
sim->cpu.psw.fpr = 1;
w = cpuFloatToWord(f);
cpuSetReg2(sim, w);
sim->cpu.psw.cy = w < 0;
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = w < 0;
sim->cpu.psw.z = w == 0;
cpuAdvance(sim, cpuClocks(16)); /* TODO: Research */
} }
/* DIV */ /* DIV */
static int cpuDIV(VB *sim) { static void cpuDIV(VB *sim) {
int32_t a; /* Dividend */ int32_t a; /* Dividend */
int32_t b; /* Divisor */ int32_t b; /* Divisor */
int32_t c; /* Remainder */ int32_t c; /* Remainder */
@ -783,10 +909,8 @@ static int cpuDIV(VB *sim) {
/* Zero division */ /* Zero division */
b = cpuGetReg1(sim); b = cpuGetReg1(sim);
if (b == 0) { if (b == 0) {
sim->cpu.exception = 0xFF80; cpuThrow(sim, 0xFF80);
sim->cpu.operation = CPU_EXCEPTION; return;
/* TODO: Research clocks */
return 0;
} }
/* Compute results */ /* Compute results */
@ -831,11 +955,29 @@ static int cpuDIV(VB *sim) {
sim->cpu.psw.s = d < 0; sim->cpu.psw.s = d < 0;
sim->cpu.psw.z = d == 0; sim->cpu.psw.z = d == 0;
cpuAdvance(sim, cpuClocks(38)); cpuAdvance(sim, cpuClocks(38));
return 0; }
/* DIVF.S */
static void cpuDIVF_S(VB *sim) {
int32_t a = cpuGetReg2(sim);
int32_t b = cpuGetReg1(sim);
double c; /* Result */
int32_t d; /* Float bits for result */
if (cpuFloatReserved(sim, a, b))
return;
if ((b & 0x7FFFFFFF) == 0) {
cpuThrow(sim, (a & 0x7FFFFFFF) == 0 ? 0xFF70 : 0xFF68);
return;
}
c = (double) cpuWordToFloat(a) / cpuWordToFloat(b);
if (cpuFloatCommon(sim, c, &d))
return;
cpuSetReg2(sim, d);
cpuAdvance(sim, cpuClocks(44));
} }
/* DIVU */ /* DIVU */
static int cpuDIVU(VB *sim) { static void cpuDIVU(VB *sim) {
uint32_t a; /* Dividend */ uint32_t a; /* Dividend */
uint32_t b; /* Divisor */ uint32_t b; /* Divisor */
int32_t c; /* Remainder */ int32_t c; /* Remainder */
@ -844,10 +986,8 @@ static int cpuDIVU(VB *sim) {
/* Zero division */ /* Zero division */
b = cpuGetReg1(sim); b = cpuGetReg1(sim);
if (b == 0) { if (b == 0) {
sim->cpu.exception = 0xFF80; cpuThrow(sim, 0xFF80);
sim->cpu.operation = CPU_EXCEPTION; return;
/* TODO: Research clocks */
return 0;
} }
/* Compute results */ /* Compute results */
@ -862,14 +1002,12 @@ static int cpuDIVU(VB *sim) {
sim->cpu.psw.s = d < 0; sim->cpu.psw.s = d < 0;
sim->cpu.psw.z = d == 0; sim->cpu.psw.z = d == 0;
cpuAdvance(sim, cpuClocks(36)); cpuAdvance(sim, cpuClocks(36));
return 0;
} }
/* HALT */ /* HALT */
static int cpuHALT(VB *sim) { static void cpuHALT(VB *sim) {
sim->cpu.operation = CPU_HALTING; sim->cpu.operation = CPU_HALTING;
/* TODO: Research clocks */ /* TODO: Research clocks */
return 0;
} }
/* IN.B */ /* IN.B */
@ -888,22 +1026,19 @@ static int cpuIN_W(VB *sim) {
} }
/* JAL */ /* JAL */
static int cpuJAL(VB *sim) { static void cpuJAL(VB *sim) {
sim->cpu.program[31] = sim->cpu.pc + 4; sim->cpu.program[31] = sim->cpu.pc + 4;
cpuJump(sim, sim->cpu.pc + cpuGetDisp26(sim)); cpuJump(sim, sim->cpu.pc + cpuGetDisp26(sim));
return 0;
} }
/* JMP */ /* JMP */
static int cpuJMP(VB *sim) { static void cpuJMP(VB *sim) {
cpuJump(sim, cpuGetReg1(sim)); cpuJump(sim, cpuGetReg1(sim));
return 0;
} }
/* JR */ /* JR */
static int cpuJR(VB *sim) { static void cpuJR(VB *sim) {
cpuJump(sim, sim->cpu.pc + cpuGetDisp26(sim)); cpuJump(sim, sim->cpu.pc + cpuGetDisp26(sim));
return 0;
} }
/* LD.B */ /* LD.B */
@ -922,48 +1057,42 @@ static int cpuLD_W(VB *sim) {
} }
/* LDSR */ /* LDSR */
static int cpuLDSR(VB *sim) { static void cpuLDSR(VB *sim) {
cpuSetSystemRegister(sim, cpuGetImm5U(sim), cpuGetReg2(sim), 0); cpuSetSystemRegister(sim, cpuGetImm5U(sim), cpuGetReg2(sim), 0);
cpuAdvance(sim, cpuClocks(8)); cpuAdvance(sim, cpuClocks(8));
return 0;
} }
/* MOV immediate */ /* MOV immediate */
static int cpuMOVImm(VB *sim) { static void cpuMOVImm(VB *sim) {
cpuSetReg2(sim, cpuGetImm5S(sim)); cpuSetReg2(sim, cpuGetImm5S(sim));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* MOV register */ /* MOV register */
static int cpuMOVReg(VB *sim) { static void cpuMOVReg(VB *sim) {
cpuSetReg2(sim, cpuGetReg1(sim)); cpuSetReg2(sim, cpuGetReg1(sim));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* MOVEA */ /* MOVEA */
static int cpuMOVEA(VB *sim) { static void cpuMOVEA(VB *sim) {
cpuSetReg2(sim, cpuGetReg1(sim) + cpuGetImm16S(sim)); cpuSetReg2(sim, cpuGetReg1(sim) + cpuGetImm16S(sim));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* MOVHI */ /* MOVHI */
static int cpuMOVHI(VB *sim) { static void cpuMOVHI(VB *sim) {
cpuSetReg2(sim, cpuGetReg1(sim) + (cpuGetImm16U(sim) << 16)); cpuSetReg2(sim, cpuGetReg1(sim) + (cpuGetImm16U(sim) << 16));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* MPYHW */ /* MPYHW */
static int cpuMPYHW(VB *sim) { static void cpuMPYHW(VB *sim) {
cpuSetReg2(sim, cpuGetReg2(sim) * SignExtend(cpuGetReg1(sim), 17)); cpuSetReg2(sim, cpuGetReg2(sim) * SignExtend(cpuGetReg1(sim), 17));
return 0;
} }
/* MUL */ /* MUL */
static int cpuMUL(VB *sim) { static void cpuMUL(VB *sim) {
int64_t a = cpuGetReg2(sim); int64_t a = cpuGetReg2(sim);
int64_t b = cpuGetReg1(sim); int64_t b = cpuGetReg1(sim);
int64_t c = a * b; int64_t c = a * b;
@ -974,11 +1103,25 @@ static int cpuMUL(VB *sim) {
sim->cpu.psw.s = d < 0; sim->cpu.psw.s = d < 0;
sim->cpu.psw.z = d == 0; sim->cpu.psw.z = d == 0;
cpuAdvance(sim, 13); cpuAdvance(sim, 13);
return 0; }
/* MULF.S */
static void cpuMULF_S(VB *sim) {
int32_t a = cpuGetReg2(sim);
int32_t b = cpuGetReg1(sim);
double c; /* Result */
int32_t d; /* Float bits for result */
if (cpuFloatReserved(sim, a, b))
return;
c = (double) cpuWordToFloat(a) * cpuWordToFloat(b);
if (cpuFloatCommon(sim, c, &d))
return;
cpuSetReg2(sim, d);
cpuAdvance(sim, cpuClocks(30)); /* TODO: Research */
} }
/* MULU */ /* MULU */
static int cpuMULU(VB *sim) { static void cpuMULU(VB *sim) {
uint64_t a = cpuGetReg2(sim); uint64_t a = cpuGetReg2(sim);
uint64_t b = cpuGetReg1(sim); uint64_t b = cpuGetReg1(sim);
int64_t c = a * b; int64_t c = a * b;
@ -989,28 +1132,24 @@ static int cpuMULU(VB *sim) {
sim->cpu.psw.s = d < 0; sim->cpu.psw.s = d < 0;
sim->cpu.psw.z = d == 0; sim->cpu.psw.z = d == 0;
cpuAdvance(sim, 13); cpuAdvance(sim, 13);
return 0;
} }
/* NOT */ /* NOT */
static int cpuNOT(VB *sim) { static void cpuNOT(VB *sim) {
cpuSetReg2(sim, cpuBitwise(sim, ~cpuGetReg1(sim))); cpuSetReg2(sim, cpuBitwise(sim, ~cpuGetReg1(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* OR */ /* OR */
static int cpuOR(VB *sim) { static void cpuOR(VB *sim) {
cpuSetReg2(sim, cpuBitwise(sim, cpuGetReg2(sim) | cpuGetReg1(sim))); cpuSetReg2(sim, cpuBitwise(sim, cpuGetReg2(sim) | cpuGetReg1(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* ORI */ /* ORI */
static int cpuORI(VB *sim) { static void cpuORI(VB *sim) {
cpuSetReg2(sim, cpuBitwise(sim, cpuGetReg2(sim) | cpuGetImm16U(sim))); cpuSetReg2(sim, cpuBitwise(sim, cpuGetReg2(sim) | cpuGetImm16U(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* OUT.B */ /* OUT.B */
@ -1029,7 +1168,7 @@ static int cpuOUT_W(VB *sim) {
} }
/* RETI */ /* RETI */
static int cpuRETI(VB *sim) { static void cpuRETI(VB *sim) {
if (sim->cpu.psw.np) { if (sim->cpu.psw.np) {
sim->cpu.nextPC = sim->cpu.fepc; sim->cpu.nextPC = sim->cpu.fepc;
cpuSetSystemRegister(sim, VB_PSW, sim->cpu.fepsw, 0); cpuSetSystemRegister(sim, VB_PSW, sim->cpu.fepsw, 0);
@ -1039,11 +1178,10 @@ static int cpuRETI(VB *sim) {
} }
sim->cpu.clocks += cpuClocks(10); sim->cpu.clocks += cpuClocks(10);
sim->cpu.operation = CPU_FETCH; sim->cpu.operation = CPU_FETCH;
return 0;
} }
/* REV */ /* REV */
static int cpuREV(VB *sim) { static void cpuREV(VB *sim) {
uint32_t x = cpuGetReg1(sim); uint32_t x = cpuGetReg1(sim);
x = (x << 16 & 0xFFFF0000) | (x >> 16 & 0x0000FFFF); x = (x << 16 & 0xFFFF0000) | (x >> 16 & 0x0000FFFF);
x = (x << 8 & 0xFF00FF00) | (x >> 8 & 0x00FF00FF); x = (x << 8 & 0xFF00FF00) | (x >> 8 & 0x00FF00FF);
@ -1051,63 +1189,54 @@ static int cpuREV(VB *sim) {
x = (x << 2 & 0xCCCCCCCC) | (x >> 2 & 0x33333333); x = (x << 2 & 0xCCCCCCCC) | (x >> 2 & 0x33333333);
x = (x << 1 & 0xAAAAAAAA) | (x >> 1 & 0x55555555); x = (x << 1 & 0xAAAAAAAA) | (x >> 1 & 0x55555555);
cpuSetReg2(sim, x); cpuSetReg2(sim, x);
return 0;
} }
/* SAR immediate */ /* SAR immediate */
static int cpuSARImm(VB *sim) { static void cpuSARImm(VB *sim) {
cpuSetReg2(sim, cpuShiftArithmetic(sim, cpuGetImm5U(sim))); cpuSetReg2(sim, cpuShiftArithmetic(sim, cpuGetImm5U(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* SEI */ /* SEI */
static int cpuSEI(VB *sim) { static void cpuSEI(VB *sim) {
sim->cpu.psw.id = 1; sim->cpu.psw.id = 1;
cpuAdvance(sim, cpuClocks(12)); cpuAdvance(sim, cpuClocks(12));
return 0;
} }
/* SETF */ /* SETF */
static int cpuSETF(VB *sim) { static void cpuSETF(VB *sim) {
cpuSetReg2(sim, cpuCondition(sim, cpuGetImm5U(sim) & 15)); cpuSetReg2(sim, cpuCondition(sim, cpuGetImm5U(sim) & 15));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* SHR register */ /* SHR register */
static int cpuSARReg(VB *sim) { static void cpuSARReg(VB *sim) {
cpuSetReg2(sim, cpuShiftArithmetic(sim, cpuGetReg1(sim) & 31)); cpuSetReg2(sim, cpuShiftArithmetic(sim, cpuGetReg1(sim) & 31));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* SHL immediate */ /* SHL immediate */
static int cpuSHLImm(VB *sim) { static void cpuSHLImm(VB *sim) {
cpuSetReg2(sim, cpuShiftLeft(sim, cpuGetImm5U(sim))); cpuSetReg2(sim, cpuShiftLeft(sim, cpuGetImm5U(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* SHR register */ /* SHR register */
static int cpuSHLReg(VB *sim) { static void cpuSHLReg(VB *sim) {
cpuSetReg2(sim, cpuShiftLeft(sim, cpuGetReg1(sim) & 31)); cpuSetReg2(sim, cpuShiftLeft(sim, cpuGetReg1(sim) & 31));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* SHR immediate */ /* SHR immediate */
static int cpuSHRImm(VB *sim) { static void cpuSHRImm(VB *sim) {
cpuSetReg2(sim, cpuShiftRight(sim, cpuGetImm5U(sim))); cpuSetReg2(sim, cpuShiftRight(sim, cpuGetImm5U(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* SHR register */ /* SHR register */
static int cpuSHRReg(VB *sim) { static void cpuSHRReg(VB *sim) {
cpuSetReg2(sim, cpuShiftRight(sim, cpuGetReg1(sim) & 31)); cpuSetReg2(sim, cpuShiftRight(sim, cpuGetReg1(sim) & 31));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* ST.B */ /* ST.B */
@ -1126,55 +1255,87 @@ static int cpuST_W(VB *sim) {
} }
/* STSR */ /* STSR */
static int cpuSTSR(VB *sim) { static void cpuSTSR(VB *sim) {
cpuSetReg2(sim, cpuGetSystemRegister(sim, cpuGetImm5U(sim))); cpuSetReg2(sim, cpuGetSystemRegister(sim, cpuGetImm5U(sim)));
cpuAdvance(sim, cpuClocks(8)); cpuAdvance(sim, cpuClocks(8));
return 0;
} }
/* SUB */ /* SUB */
static int cpuSUB(VB *sim) { static void cpuSUB(VB *sim) {
cpuSetReg2(sim, cpuSubtract(sim, cpuGetReg1(sim))); cpuSetReg2(sim, cpuSubtract(sim, cpuGetReg1(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0; }
/* SUBF.S */
static void cpuSUBF_S(VB *sim) {
int32_t a = cpuGetReg2(sim);
int32_t b = cpuGetReg1(sim);
double c; /* Result */
int32_t d; /* Float bits for result */
if (cpuFloatReserved(sim, a, b))
return;
c = (double) cpuWordToFloat(a) - cpuWordToFloat(b);
if (cpuFloatCommon(sim, c, &d))
return;
cpuSetReg2(sim, d);
cpuAdvance(sim, cpuClocks(28)); /* TODO: Research */
} }
/* TRAP */ /* TRAP */
static int cpuTRAP(VB *sim) { static void cpuTRAP(VB *sim) {
sim->cpu.clocks += cpuClocks(15); sim->cpu.clocks += cpuClocks(15);
sim->cpu.exception = 0xFFA0 + cpuGetImm5U(sim); sim->cpu.exception = 0xFFA0 + cpuGetImm5U(sim);
sim->cpu.operation = CPU_EXCEPTION; sim->cpu.operation = CPU_EXCEPTION;
return 0; }
/* TRNC.SW */
static void cpuTRNC_SW(VB *sim) {
double f;
int32_t w = cpuGetReg1(sim);
if (cpuFloatReservedOne(w)) {
cpuThrow(sim, 0xFF60);
return;
}
f = cpuWordToFloat(w);
if (f <= -2147483649.0 || f >= 2147483648.0) {
sim->cpu.psw.fiv = 1;
cpuThrow(sim, 0xFF70);
return;
}
w = f;
cpuSetReg2(sim, w);
if (w != f)
sim->cpu.psw.fpr = 1;
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = w < 0;
sim->cpu.psw.z = w == 0;
cpuAdvance(sim, cpuClocks(14)); /* TODO: Research */
} }
/* XB */ /* XB */
static int cpuXB(VB *sim) { static void cpuXB(VB *sim) {
uint32_t x = cpuGetReg2(sim); uint32_t x = cpuGetReg2(sim);
x = (x & 0xFFFF0000) | (x << 8 & 0x0000FF00) | (x >> 8 & 0x000000FF); x = (x & 0xFFFF0000) | (x << 8 & 0x0000FF00) | (x >> 8 & 0x000000FF);
cpuSetReg2(sim, x); cpuSetReg2(sim, x);
return 0;
} }
/* XH */ /* XH */
static int cpuXH(VB *sim) { static void cpuXH(VB *sim) {
uint32_t x = cpuGetReg2(sim); uint32_t x = cpuGetReg2(sim);
x = (x << 16 & 0xFFFF0000) | (x >> 16 & 0x0000FFFF); x = (x << 16 & 0xFFFF0000) | (x >> 16 & 0x0000FFFF);
cpuSetReg2(sim, x); cpuSetReg2(sim, x);
return 0;
} }
/* XOR */ /* XOR */
static int cpuXOR(VB *sim) { static void cpuXOR(VB *sim) {
cpuSetReg2(sim, cpuBitwise(sim, cpuGetReg2(sim) ^ cpuGetReg1(sim))); cpuSetReg2(sim, cpuBitwise(sim, cpuGetReg2(sim) ^ cpuGetReg1(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
/* XORI */ /* XORI */
static int cpuXORI(VB *sim) { static void cpuXORI(VB *sim) {
cpuSetReg2(sim, cpuBitwise(sim, cpuGetReg2(sim) ^ cpuGetImm16U(sim))); cpuSetReg2(sim, cpuBitwise(sim, cpuGetReg2(sim) ^ cpuGetImm16U(sim)));
cpuAdvance(sim, cpuClocks(1)); cpuAdvance(sim, cpuClocks(1));
return 0;
} }
@ -1183,7 +1344,7 @@ static int cpuXORI(VB *sim) {
/* Process component */ /* Process component */
static int cpuEmulate(VB *sim, uint32_t clocks) { static int cpuEmulate(VB *sim, uint32_t clocks) {
int brk; int brk = 0;
/* Process until there are clocks to wait */ /* Process until there are clocks to wait */
for (;;) { for (;;) {
@ -1204,62 +1365,70 @@ static int cpuEmulate(VB *sim, uint32_t clocks) {
switch (sim->cpu.operation) { switch (sim->cpu.operation) {
case CPU_FETCH: brk = cpuFetch(sim); break; case CPU_FETCH: brk = cpuFetch(sim); break;
case CPU_ADD_IMM: brk = cpuADDImm(sim); break; case CPU_ADD_IMM: cpuADDImm (sim); break;
case CPU_ADD_REG: brk = cpuADDReg(sim); break; case CPU_ADD_REG: cpuADDReg (sim); break;
case CPU_ADDI : brk = cpuADDI (sim); break; case CPU_ADDF_S : cpuADDF_S (sim); break;
case CPU_AND : brk = cpuAND (sim); break; case CPU_ADDI : cpuADDI (sim); break;
case CPU_ANDI : brk = cpuANDI (sim); break; case CPU_AND : cpuAND (sim); break;
case CPU_BCOND : brk = cpuBCOND (sim); break; case CPU_ANDI : cpuANDI (sim); break;
case CPU_BCOND : cpuBCOND (sim); break;
case CPU_CAXI : brk = cpuCAXI (sim); break; case CPU_CAXI : brk = cpuCAXI (sim); break;
case CPU_CLI : brk = cpuCLI (sim); break; case CPU_CLI : cpuCLI (sim); break;
case CPU_CMP_IMM: brk = cpuCMPImm(sim); break; case CPU_CMP_IMM: cpuCMPImm (sim); break;
case CPU_CMP_REG: brk = cpuCMPReg(sim); break; case CPU_CMP_REG: cpuCMPReg (sim); break;
case CPU_DIV : brk = cpuDIV (sim); break; case CPU_CMPF_S : cpuCMPF_S (sim); break;
case CPU_DIVU : brk = cpuDIVU (sim); break; case CPU_CVT_SW : cpuCVT_SW (sim); break;
case CPU_HALT : brk = cpuHALT (sim); break; case CPU_CVT_WS : cpuCVT_WS (sim); break;
case CPU_DIV : cpuDIV (sim); break;
case CPU_DIVF_S : cpuDIVF_S (sim); break;
case CPU_DIVU : cpuDIVU (sim); break;
case CPU_HALT : cpuHALT (sim); break;
case CPU_IN_B : brk = cpuIN_B (sim); break; case CPU_IN_B : brk = cpuIN_B (sim); break;
case CPU_IN_H : brk = cpuIN_H (sim); break; case CPU_IN_H : brk = cpuIN_H (sim); break;
case CPU_IN_W : brk = cpuIN_W (sim); break; case CPU_IN_W : brk = cpuIN_W (sim); break;
case CPU_JAL : brk = cpuJAL (sim); break; case CPU_JAL : cpuJAL (sim); break;
case CPU_JMP : brk = cpuJMP (sim); break; case CPU_JMP : cpuJMP (sim); break;
case CPU_JR : brk = cpuJR (sim); break; case CPU_JR : cpuJR (sim); break;
case CPU_LD_B : brk = cpuLD_B (sim); break; case CPU_LD_B : brk = cpuLD_B (sim); break;
case CPU_LD_H : brk = cpuLD_H (sim); break; case CPU_LD_H : brk = cpuLD_H (sim); break;
case CPU_LD_W : brk = cpuLD_W (sim); break; case CPU_LD_W : brk = cpuLD_W (sim); break;
case CPU_LDSR : brk = cpuLDSR (sim); break; case CPU_LDSR : cpuLDSR (sim); break;
case CPU_MOV_IMM: brk = cpuMOVImm(sim); break; case CPU_MOV_IMM: cpuMOVImm (sim); break;
case CPU_MOV_REG: brk = cpuMOVReg(sim); break; case CPU_MOV_REG: cpuMOVReg (sim); break;
case CPU_MOVEA : brk = cpuMOVEA (sim); break; case CPU_MOVEA : cpuMOVEA (sim); break;
case CPU_MOVHI : brk = cpuMOVHI (sim); break; case CPU_MOVHI : cpuMOVHI (sim); break;
case CPU_MPYHW : brk = cpuMPYHW (sim); break; case CPU_MPYHW : cpuMPYHW (sim); break;
case CPU_MUL : brk = cpuMUL (sim); break; case CPU_MUL : cpuMUL (sim); break;
case CPU_MULU : brk = cpuMULU (sim); break; case CPU_MULF_S : cpuMULF_S (sim); break;
case CPU_NOT : brk = cpuNOT (sim); break; case CPU_MULU : cpuMULU (sim); break;
case CPU_OR : brk = cpuOR (sim); break; case CPU_NOT : cpuNOT (sim); break;
case CPU_ORI : brk = cpuORI (sim); break; case CPU_OR : cpuOR (sim); break;
case CPU_ORI : cpuORI (sim); break;
case CPU_OUT_B : brk = cpuOUT_B (sim); break; case CPU_OUT_B : brk = cpuOUT_B (sim); break;
case CPU_OUT_H : brk = cpuOUT_H (sim); break; case CPU_OUT_H : brk = cpuOUT_H (sim); break;
case CPU_OUT_W : brk = cpuOUT_W (sim); break; case CPU_OUT_W : brk = cpuOUT_W (sim); break;
case CPU_RETI : brk = cpuRETI (sim); break; case CPU_RETI : cpuRETI (sim); break;
case CPU_REV : brk = cpuREV (sim); break; case CPU_REV : cpuREV (sim); break;
case CPU_SAR_IMM: brk = cpuSARImm(sim); break; case CPU_SAR_IMM: cpuSARImm (sim); break;
case CPU_SAR_REG: brk = cpuSARReg(sim); break; case CPU_SAR_REG: cpuSARReg (sim); break;
case CPU_SEI : brk = cpuSEI (sim); break; case CPU_SEI : cpuSEI (sim); break;
case CPU_SETF : brk = cpuSETF (sim); break; case CPU_SETF : cpuSETF (sim); break;
case CPU_SHL_IMM: brk = cpuSHLImm(sim); break; case CPU_SHL_IMM: cpuSHLImm (sim); break;
case CPU_SHL_REG: brk = cpuSHLReg(sim); break; case CPU_SHL_REG: cpuSHLReg (sim); break;
case CPU_SHR_IMM: brk = cpuSHRImm(sim); break; case CPU_SHR_IMM: cpuSHRImm (sim); break;
case CPU_SHR_REG: brk = cpuSHRReg(sim); break; case CPU_SHR_REG: cpuSHRReg (sim); break;
case CPU_ST_B : brk = cpuST_B (sim); break; case CPU_ST_B : brk = cpuST_B (sim); break;
case CPU_ST_H : brk = cpuST_H (sim); break; case CPU_ST_H : brk = cpuST_H (sim); break;
case CPU_ST_W : brk = cpuST_W (sim); break; case CPU_ST_W : brk = cpuST_W (sim); break;
case CPU_STSR : brk = cpuSTSR (sim); break; case CPU_STSR : cpuSTSR (sim); break;
case CPU_SUB : brk = cpuSUB (sim); break; case CPU_SUB : cpuSUB (sim); break;
case CPU_TRAP : brk = cpuTRAP (sim); break; case CPU_SUBF_S : cpuSUBF_S (sim); break;
case CPU_XB : brk = cpuXB (sim); break; case CPU_TRAP : cpuTRAP (sim); break;
case CPU_XH : brk = cpuXH (sim); break; case CPU_TRNC_SW: cpuTRNC_SW(sim); break;
case CPU_XOR : brk = cpuXOR (sim); break; case CPU_XB : cpuXB (sim); break;
case CPU_XORI : brk = cpuXORI (sim); break; case CPU_XH : cpuXH (sim); break;
case CPU_XOR : cpuXOR (sim); break;
case CPU_XORI : cpuXORI (sim); break;
default: return -1; /* TODO: Temporary for debugging */ default: return -1; /* TODO: Temporary for debugging */
} }

View File

@ -1,6 +1,7 @@
#ifndef VBAPI #ifndef VBAPI
#define VBAPI #define VBAPI
#endif #endif
#include <float.h>
#include <vb.h> #include <vb.h>