From: Shamus Hammons Date: Tue, 21 Jul 2009 21:23:04 +0000 (+0000) Subject: Change V6808 clock to 64-bit, added possible "don't branch" optimization X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=stargem2;a=commitdiff_plain;h=2879315d07ce59a7996bc8a137c3b66ae018013a Change V6808 clock to 64-bit, added possible "don't branch" optimization --- diff --git a/src/v6808.cpp b/src/v6808.cpp index 96ff814..2022e90 100755 --- a/src/v6808.cpp +++ b/src/v6808.cpp @@ -12,6 +12,8 @@ // 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 !!! @@ -25,6 +27,7 @@ // [DONE--remain to be seen if there is any performance increase] //#define __DEBUG__ +#define TEST_DONT_BRANCH_OPTIMIZATION #include "v6808.h" @@ -35,30 +38,6 @@ // 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) @@ -79,9 +58,9 @@ #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) @@ -172,13 +151,6 @@ Add Accumulators |ABA | | | | |1B 2 1|A=A+B |T T // 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; \ @@ -249,13 +221,6 @@ Add with Carry |ADCA |89 2 2|99 3 2|A9 5 2|B9 4 3| |A=A+M+C |T T // 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; \ @@ -555,11 +520,6 @@ Complement 1's |COM | | |63 7 2|73 6 3| |M=-M | T // 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); \ @@ -602,11 +562,6 @@ Complement 2's |NEG | | |60 7 2|70 6 3| |M=00-M | T // 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); \ @@ -647,37 +602,18 @@ Decimal Adjust |DAA | | | | |19 2 1|* | T 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 } /* @@ -690,10 +626,6 @@ Decrement |DEC | | |6A 7 2|7A 6 3| |M=M-1 | T // 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); \ @@ -797,10 +729,6 @@ Increment |INC | | |6C 7 2|7C 6 3| |M=M+1 | T // 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); \ @@ -967,25 +895,21 @@ Pull Data |PULA | | | | |32 4 1|A=Msp, *+ | 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; } @@ -999,12 +923,6 @@ Rotate Left |ROL | | |69 7 2|79 6 3| |Memory *1| T // 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; \ @@ -1048,12 +966,6 @@ Rotate Right |ROR | | |66 7 2|76 6 3| |Memory *2| T // 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); \ @@ -1097,12 +1009,6 @@ Arithmetic Shift Left |ASL | | |68 7 2|78 6 3| |Memory *3| T // 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; \ @@ -1146,12 +1052,6 @@ Arithmetic Shift Right |ASR | | |67 7 2|77 6 3| |Memory *4| T // 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); \ @@ -1195,12 +1095,6 @@ Logic Shift Right |LSR | | |64 7 2|74 6 3| |Memory *5| T // 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; \ @@ -1283,12 +1177,6 @@ Subtract Accumulators |SBA | | | | |10 2 1|A=A-B | T // 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; \ @@ -1358,12 +1246,6 @@ Subtract with Carry |SBCA |82 2 2|92 3 2|A2 5 2|B2 4 3| |A=A-M-C | T // 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; \ @@ -1712,128 +1594,174 @@ static void Op20(void) // BRA 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 } /* @@ -1915,7 +1843,6 @@ static void Op3F(void) // SWI 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 } @@ -1948,37 +1875,31 @@ Accumlator A=CCR |TPA | | | | |07 2 1|A=CCR | 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; } @@ -1990,7 +1911,6 @@ static void Op06(void) // TAP static void Op07(void) // TPA { -// regs.a = regs.cc; regs.a = PACK_FLAGS; } @@ -2100,7 +2020,8 @@ static bool logGo = false; // 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 @@ -2132,7 +2053,6 @@ if (logGo) #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 @@ -2152,6 +2072,7 @@ WriteLog("*** NMI LINE ASSERTED ***\n"); 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)... @@ -2176,6 +2097,7 @@ logGo = true; 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)... @@ -2191,7 +2113,7 @@ logGo = true; // // Get the clock of the currently executing CPU // -uint32 GetCurrentV6808Clock(void) +uint64 GetCurrentV6808Clock(void) { return regs.clock; } diff --git a/src/v6808.h b/src/v6808.h index ec19a63..2b25aee 100755 --- a/src/v6808.h +++ b/src/v6808.h @@ -39,16 +39,17 @@ struct V6808REGS uint8 cc; // 6808 Condition Code register uint8 a; // 6808 A register uint8 b; // 6808 B register - uint32 clock; // 6808 clock + uint64 clock; // 6808 clock uint8 (* RdMem)(uint16); // Address of uint8 read routine void (* WrMem)(uint16, uint8); // Address of uint8 write routine uint32 cpuFlags; // v6808 IRQ/RESET flags + uint32 clockOverrun; // Amount of overflow between runs }; // Function prototypes void Execute6808(V6808REGS *, uint32); // Function to execute 6808 instructions -uint32 GetCurrentV6808Clock(void); // Get the clock of the currently executing CPU +uint64 GetCurrentV6808Clock(void); // Get the clock of the currently executing CPU //uint8 GetCCRegister(void); // Hmm. #endif // __V6808_H__ diff --git a/src/v6809.cpp b/src/v6809.cpp index cb67072..a8b24fa 100755 --- a/src/v6809.cpp +++ b/src/v6809.cpp @@ -47,6 +47,7 @@ //Small problem with the EA_ macros: ABS macros don't increment the PC!!! !!! FIX !!! //Hmm, why not do like we did for READ_ABS*??? +//Because the EA_* macros are usually used as an argument to a function call, that's why. #define EA_IMM regs.pc++ #define EA_ZP regs.RdMem(regs.pc++) #define EA_ZP_X (regs.RdMem(regs.pc++) + regs.x) & 0xFF