// JLH 06/15/2006 Scrubbed all BYTE, WORD & DWORD references from the code
// JLH 11/13/2006 Converted core to V65C02 macro style :-)
// JLH 11/13/2006 Converted flags to unpacked and separate flags
+// JLH 07/21/2009 Converted clock from 32-bit to 64-bit value, added possible
+// "don't branch" optimization
//
// NOTE: V6808_STATE_WAI is not handled in the main loop correctly. !!! FIX !!!
// [DONE--remain to be seen if there is any performance increase]
//#define __DEBUG__
+#define TEST_DONT_BRANCH_OPTIMIZATION
#include "v6808.h"
// Various macros
-#if 0
-#define CLR_Z (regs.cc &= ~FLAG_Z)
-#define CLR_ZN (regs.cc &= ~(FLAG_Z | FLAG_N))
-#define CLR_ZNC (regs.cc &= ~(FLAG_Z | FLAG_N | FLAG_C))
-#define CLR_NVC (regs.cc &= ~(FLAG_N | FLAG_V | FLAG_C))
-#define CLR_VC (regs.cc &= ~(FLAG_V | FLAG_C))
-#define CLR_V (regs.cc &= ~FLAG_V)
-#define CLR_N (regs.cc &= ~FLAG_N)
-#define SET_Z(r) (regs.cc = ((r) == 0 ? regs.cc | FLAG_Z : regs.cc & ~FLAG_Z))
-#define SET_N(r) (regs.cc = ((r) & 0x80 ? regs.cc | FLAG_N : regs.cc & ~FLAG_N))
-#define SET_V(a,b,r) (regs.cc = ((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V)
-
-//Not sure that this code is computing the carry correctly... Investigate! [Seems to be]
-#define SET_C_ADD(a,b) (regs.cc = ((uint8)(b) > (uint8)(~(a)) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
-#define SET_C_CMP(a,b) (regs.cc = ((uint8)(b) < (uint8)(a) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
-#define SET_ZN(r) SET_N(r); SET_Z(r)
-#define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
-#define SET_ZNVC_CMP(a,b,r) SET_N(r); SET_Z(r); SET_C_CMP(a,b); SET_V(a,b,r)
-
-#define SET_N16(r) (regs.cc = ((r) & 0x8000 ? regs.cc | FLAG_N : regs.cc & ~FLAG_N))
-#define SET_V16(a,b,r) (regs.cc = ((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x8000 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V)
-#define SET_C_CMP16(a,b) (regs.cc = ((uint16)(b) < (uint16)(a) ? regs.cc | FLAG_C : regs.cc & ~FLAG_C))
-#define SET_ZNVC_CMP16(a,b,r) SET_N16(r); SET_Z(r); SET_C_CMP16(a,b); SET_V16(a,b,r)
-#else
#define CLR_Z (flagZ = 0)
#define CLR_ZN (flagZ = flagN = 0)
#define CLR_ZNC (flagZ = flagN = flagC = 0)
#define SET_V16(a,b,r) (flagV = (((b) ^ (a) ^ (r) ^ ((r) >> 1)) & 0x8000) >> 15)
#define SET_C_CMP16(a,b) (flagC = ((uint16)(b) < (uint16)(a) ? 1 : 0))
#define SET_ZNVC_CMP16(a,b,r) SET_N16(r); SET_Z(r); SET_C_CMP16(a,b); SET_V16(a,b,r)
-#endif
//Small problem with the EA_ macros: ABS macros don't increment the PC!!! !!! FIX !!! [DONE, kinda]
+//Can't fix for reading...
#define EA_IMM regs.pc++
#define EA_ZP regs.RdMem(regs.pc++)
#define EA_ZP_X (regs.RdMem(regs.pc++) + regs.x)
// ADD opcodes
-//#define OP_ADD_HANDLER(m, acc) \
- uint16 sum = (uint16)(acc) + (m); \
- regs.cc = (regs.cc & ~FLAG_C) | (sum >> 8); \
- regs.cc = (regs.cc & ~FLAG_H) | ((sum << 1) & FLAG_H); \
- SET_V(m, acc, sum); \
- (acc) = sum & 0xFF; \
- SET_ZN(acc)
#define OP_ADD_HANDLER(m, acc) \
uint16 sum = (uint16)(acc) + (m); \
flagC = sum >> 8; \
// ADC opcodes
-//#define OP_ADC_HANDLER(m, acc) \
- uint16 sum = (uint16)acc + (m) + (uint16)(regs.cc & FLAG_C); \
- regs.cc = (regs.cc & ~FLAG_C) | (sum >> 8); \
- regs.cc = (regs.cc & ~FLAG_H) | ((sum << 1) & FLAG_H); \
- SET_V(m, acc, sum); \
- acc = sum & 0xFF; \
- SET_ZN(acc)
#define OP_ADC_HANDLER(m, acc) \
uint16 sum = (uint16)acc + (m) + (uint16)flagC; \
flagC = sum >> 8; \
// COM opcodes
-//#define OP_COM_HANDLER(m) \
- m = m ^ 0xFF; \
- SET_ZN(m); \
- CLR_V; \
- regs.cc |= FLAG_C
#define OP_COM_HANDLER(m) \
m = m ^ 0xFF; \
SET_ZN(m); \
// NEG opcodes
-//#define OP_NEG_HANDLER(m) \
- m = -m; \
- SET_ZN(m); \
- regs.cc = (m == 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V); \
- regs.cc = (m == 0x00 ? regs.cc | FLAG_C : regs.cc & ~FLAG_C)
#define OP_NEG_HANDLER(m) \
m = -m; \
SET_ZN(m); \
static void Op19(void) // DAA
{
-#if 0 // Just because we can optimize a little here, we will... ;-)
- uint16 adjust = 0;
-
- if ((regs.a & 0x0F) > 0x09 || (regs.cc & FLAG_H))
- adjust |= 0x06;
-
- if ((regs.a & 0xF0) > 0x90 || (regs.cc & FLAG_C) || ((regs.a & 0xF0) > 0x80 && (regs.a & 0x0F) > 0x09))
- adjust |= 0x60;
-
- uint16 result = regs.a + adjust;
- regs.a = (uint8)result;
- SET_ZN(result);
- CLR_V; // Not sure this is correct...
- regs.cc |= (result & 0x100) >> 8; // Overwrite carry if it was 0, otherwise, ignore
-#else
uint16 result = (uint16)regs.a;
-// if ((regs.a & 0x0F) > 0x09 || (regs.cc & FLAG_H))
if ((regs.a & 0x0F) > 0x09 || flagH)
result += 0x06;
-// if ((regs.a & 0xF0) > 0x90 || (regs.cc & FLAG_C) || ((regs.a & 0xF0) > 0x80 && (regs.a & 0x0F) > 0x09))
if ((regs.a & 0xF0) > 0x90 || flagC || ((regs.a & 0xF0) > 0x80 && (regs.a & 0x0F) > 0x09))
result += 0x60;
regs.a = (uint8)result;
SET_ZN(result);
CLR_V; // Not sure this is correct...
-// regs.cc |= (result & 0x100) >> 8; // Overwrite carry if it was 0, otherwise, ignore
flagC |= (result & 0x100) >> 8; // Overwrite carry if it was 0, otherwise, ignore
-#endif
}
/*
// DEC opcodes
-//#define OP_DEC_HANDLER(m) \
- m--; \
- SET_ZN(m); \
- regs.cc = (m == 0x7F ? regs.cc | FLAG_V : regs.cc & ~FLAG_V)
#define OP_DEC_HANDLER(m) \
m--; \
SET_ZN(m); \
// INC opcodes
-//#define OP_INC_HANDLER(m) \
- m++; \
- SET_ZN(m); \
- regs.cc = (m == 0x80 ? regs.cc | FLAG_V : regs.cc & ~FLAG_V)
#define OP_INC_HANDLER(m) \
m++; \
SET_ZN(m); \
static void Op36(void) // PSHA
{
-// regs.WrMem(--regs.s, regs.a);
PUSH(regs.a);
}
static void Op37(void) // PSHB
{
-// regs.WrMem(--regs.s, regs.b);
PUSH(regs.b);
}
static void Op32(void) // PULA
{
-// regs.a = regs.RdMem(regs.s++);
regs.a = PULL;
}
static void Op33(void) // PULB
{
-// regs.b = regs.RdMem(regs.s++);
regs.b = PULL;
}
// ROL opcodes
-//#define OP_ROL_HANDLER(m) \
- uint8 newCarry = (m & 0x80) >> 7; \
- m = (m << 1) | (regs.cc & FLAG_C); \
- SET_ZN(m); \
- regs.cc = (regs.cc & ~FLAG_C) | newCarry; \
- regs.cc = (regs.cc & ~FLAG_V) | ((regs.cc & FLAG_N) >> 2) ^ ((regs.cc & FLAG_C) << 1)
#define OP_ROL_HANDLER(m) \
uint8 newCarry = (m & 0x80) >> 7; \
m = (m << 1) | flagC; \
// ROR opcodes
-//#define OP_ROR_HANDLER(m) \
- uint8 newCarry = m & 0x01; \
- m = (m >> 1) | ((regs.cc & FLAG_C) << 7); \
- SET_ZN(m); \
- regs.cc = (regs.cc & ~FLAG_C) | newCarry; \
- regs.cc = (regs.cc & ~FLAG_V) | ((regs.cc & FLAG_N) >> 2) ^ ((regs.cc & FLAG_C) << 1)
#define OP_ROR_HANDLER(m) \
uint8 newCarry = m & 0x01; \
m = (m >> 1) | (flagC << 7); \
// ASL opcodes
-//#define OP_ASL_HANDLER(m) \
- uint8 newCarry = (m & 0x80) >> 7; \
- m <<= 1; \
- SET_ZN(m); \
- regs.cc = (regs.cc & ~FLAG_C) | newCarry; \
- regs.cc = (regs.cc & ~FLAG_V) | ((regs.cc & FLAG_N) >> 2) ^ ((regs.cc & FLAG_C) << 1)
#define OP_ASL_HANDLER(m) \
uint8 newCarry = (m & 0x80) >> 7; \
m <<= 1; \
// ASR opcodes
-//#define OP_ASR_HANDLER(m) \
- uint8 newCarry = m & 0x01; \
- m = (m >> 1) | (m & 0x80); \
- SET_ZN(m); \
- regs.cc = (regs.cc & ~FLAG_C) | newCarry; \
- regs.cc = (regs.cc & ~FLAG_V) | ((regs.cc & FLAG_N) >> 2) ^ ((regs.cc & FLAG_C) << 1)
#define OP_ASR_HANDLER(m) \
uint8 newCarry = m & 0x01; \
m = (m >> 1) | (m & 0x80); \
// LSR opcodes
-//#define OP_LSR_HANDLER(m) \
- uint8 newCarry = m & 0x01; \
- m >>= 1; \
- SET_ZN(m); \
- regs.cc = (regs.cc & ~FLAG_C) | newCarry; \
- regs.cc = (regs.cc & ~FLAG_V) | ((regs.cc & FLAG_N) >> 2) ^ ((regs.cc & FLAG_C) << 1)
#define OP_LSR_HANDLER(m) \
uint8 newCarry = m & 0x01; \
m >>= 1; \
// SUB opcodes
-//#define OP_SUB_HANDLER(m, acc) \
- uint16 sum = (uint16)acc - (m); \
- regs.cc = (regs.cc & ~FLAG_C) | (sum >> 15); \
- SET_V(m, acc, sum); \
- acc = (uint8)sum; \
- SET_ZN(acc)
#define OP_SUB_HANDLER(m, acc) \
uint16 sum = (uint16)acc - (m); \
flagC = sum >> 15; \
// SBC opcodes
-//#define OP_SBC_HANDLER(m, acc) \
- uint16 sum = (uint16)acc - (m) - (uint16)(regs.cc & FLAG_C); \
- regs.cc = (regs.cc & ~FLAG_C) | (sum >> 15); \
- SET_V(m, acc, sum); \
- acc = (uint8)sum; \
- SET_ZN(acc)
#define OP_SBC_HANDLER(m, acc) \
uint16 sum = (uint16)acc - (m) - (uint16)flagC; \
flagC = sum >> 15; \
static void Op24(void) // BCC
{
+// NOTE: We can optimize this by following the maxim: "Don't branch!" by converting the boolean
+// result into a multiplication. The only way to know if this is a win is to do some profiling
+// both with and without the optimization.
int16 m = (int16)(int8)READ_IMM;
-// if (!(regs.cc & FLAG_C))
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+//Note sure if the ! operator will do what we want, so we use ^ 1
+ regs.pc += m * (flagC ^ 0x01);
+#else
if (!flagC)
regs.pc += m;
+#endif
}
static void Op25(void) // BCS
{
int16 m = (int16)(int8)READ_IMM;
-// if (regs.cc & FLAG_C)
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+ regs.pc += m * (flagC);
+#else
if (flagC)
regs.pc += m;
+#endif
}
static void Op27(void) // BEQ
{
int16 m = (int16)(int8)READ_IMM;
-// if (regs.cc & FLAG_Z)
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+ regs.pc += m * (flagZ);
+#else
if (flagZ)
regs.pc += m;
+#endif
}
static void Op2C(void) // BGE
{
int16 m = (int16)(int8)READ_IMM;
-// if (!(((regs.cc & FLAG_N) >> 2) ^ (regs.cc & FLAG_V)))
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+ regs.pc += m * ((flagN ^ flagV) ^ 0x01);
+#else
if (!(flagN ^ flagV))
regs.pc += m;
+#endif
}
static void Op2E(void) // BGT
{
int16 m = (int16)(int8)READ_IMM;
-// if (!(((regs.cc & FLAG_Z) >> 1) | (((regs.cc & FLAG_N) >> 2) ^ (regs.cc & FLAG_V))))
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+ regs.pc += m * ((flagZ | (flagN ^ flagV)) ^ 0x01);
+#else
if (!(flagZ | (flagN ^ flagV)))
regs.pc += m;
+#endif
}
static void Op22(void) // BHI
{
int16 m = (int16)(int8)READ_IMM;
-// if (!(((regs.cc & FLAG_Z) >> 2) | (regs.cc & FLAG_C)))
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+ regs.pc += m * ((flagZ | flagC) ^ 0x01);
+#else
if (!(flagZ | flagC))
regs.pc += m;
+#endif
}
static void Op2F(void) // BLE
{
int16 m = (int16)(int8)READ_IMM;
-// if (((regs.cc & FLAG_Z) >> 1) | (((regs.cc & FLAG_N) >> 2) ^ (regs.cc & FLAG_V)))
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+ regs.pc += m * (flagZ | (flagN ^ flagV));
+#else
if (flagZ | (flagN ^ flagV))
regs.pc += m;
+#endif
}
static void Op23(void) // BLS
{
int16 m = (int16)(int8)READ_IMM;
-// if (((regs.cc & FLAG_Z) >> 2) | (regs.cc & FLAG_C))
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+ regs.pc += m * (flagZ | flagC);
+#else
if (flagZ | flagC)
regs.pc += m;
+#endif
}
static void Op2D(void) // BLT
{
int16 m = (int16)(int8)READ_IMM;
-// if (((regs.cc & FLAG_N) >> 2) ^ (regs.cc & FLAG_V))
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+ regs.pc += m * (flagN ^ flagV);
+#else
if (flagN ^ flagV)
regs.pc += m;
+#endif
}
static void Op2B(void) // BMI
{
int16 m = (int16)(int8)READ_IMM;
-// if (regs.cc & FLAG_N)
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+ regs.pc += m * (flagN);
+#else
if (flagN)
regs.pc += m;
+#endif
}
static void Op26(void) // BNE
{
int16 m = (int16)(int8)READ_IMM;
-// if (!(regs.cc & FLAG_Z))
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+ regs.pc += m * (flagZ ^ 0x01);
+#else
if (!flagZ)
regs.pc += m;
+#endif
}
static void Op28(void) // BVC
{
int16 m = (int16)(int8)READ_IMM;
-// if (!(regs.cc & FLAG_V))
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+ regs.pc += m * (flagV ^ 0x01);
+#else
if (!flagV)
regs.pc += m;
+#endif
}
static void Op29(void) // BVS
{
int16 m = (int16)(int8)READ_IMM;
-// if (regs.cc & FLAG_V)
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+ regs.pc += m * (flagV);
+#else
if (flagV)
regs.pc += m;
+#endif
}
static void Op2A(void) // BPL
{
int16 m = (int16)(int8)READ_IMM;
-// if (!(regs.cc & FLAG_N))
+#ifdef TEST_DONT_BRANCH_OPTIMIZATION
+ regs.pc += m * (flagN ^ 0x01);
+#else
if (!flagN)
regs.pc += m;
+#endif
}
/*
PUSH(regs.a);
PUSH(regs.cc);
regs.pc = RdMemW(0xFFFA); // And do it!
-// regs.cc |= FLAG_I; // Also, set IRQ inhibit
flagI = 1; // Also, set IRQ inhibit
}
static void Op0C(void) // CLC
{
-// regs.cc &= ~FLAG_C;
flagC = 0;
}
static void Op0E(void) // CLI
{
-// regs.cc &= ~FLAG_I;
flagI = 0;
}
static void Op0A(void) // CLV
{
-// regs.cc &= ~FLAG_V;
flagV = 0;
}
static void Op0D(void) // SEC
{
-// regs.cc |= FLAG_C;
flagC = 1;
}
static void Op0F(void) // SEI
{
-// regs.cc |= FLAG_I;
flagI = 1;
}
static void Op0B(void) // SEV
{
-// regs.cc |= FLAG_V;
flagV = 1;
}
static void Op07(void) // TPA
{
-// regs.a = regs.cc;
regs.a = PACK_FLAGS;
}
//
void Execute6808(V6808REGS * context, uint32 cycles)
{
-#warning V6808_STATE_WAI is not properly handled yet!
+#warning "V6808_STATE_WAI is not properly handled yet! !!! FIX !!!"
+#warning "Need to convert from destructive clock to non-destructive. !!! FIX !!!"
myMemcpy(®s, context, sizeof(V6808REGS));
UNPACK_FLAGS; // Explode flags register into individual uint8s
#ifdef __DEBUG__
WriteLog("*** RESET LINE ASSERTED ***\n");
#endif
-// regs.cc |= FLAG_I; // Set I
flagI = 1; // Set I
regs.pc = RdMemW(0xFFFE); // And load PC with the RESET vector
PUSH(regs.cc);
regs.pc = RdMemW(0xFFFC); // And do it!
+#warning "# of clock cycles for NMI unknown. !!! FIX !!!"
regs.clock += 0; // How many???
context->cpuFlags &= ~V6808_ASSERT_LINE_NMI;// Reset the asserted line (NMI)...
regs.cpuFlags &= ~V6808_ASSERT_LINE_NMI; // Reset the asserted line (NMI)...
PUSH(regs.cc);
regs.pc = RdMemW(0xFFF8); // And do it!
+#warning "# of clock cycles for IRQ unknown. !!! FIX !!!"
regs.clock += 0; // How many???
#warning "IRQ/NMI lines should not be cleared here... !!! FIX !!!"
context->cpuFlags &= ~V6808_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)...
//
// Get the clock of the currently executing CPU
//
-uint32 GetCurrentV6808Clock(void)
+uint64 GetCurrentV6808Clock(void)
{
return regs.clock;
}