1 /***************************************************************************** 2 * 3 * m6502ops.h 4 * Addressing mode and opcode macros for 6502,65c02,65sc02,6510,n2a03 CPUs 5 * 6 * Copyright Juergen Buchmueller, all rights reserved. 7 * 65sc02 core Copyright Peter Trauner, all rights reserved. 8 * 9 * - This source code is released as freeware for non-commercial purposes. 10 * - You are free to use and redistribute this code in modified or 11 * unmodified form, provided you list me in the credits. 12 * - If you modify this source code, you must add a notice to each modified 13 * source file that it has been changed. If you're a nice person, you 14 * will clearly mark each change too. :) 15 * - If you wish to use this for commercial purposes, please contact me at 16 * pullmoll@t-online.de 17 * - The author of this copywritten work reserves the right to change the 18 * terms of its usage and license at any time, including retroactively 19 * - This entire notice must remain in the source code. 20 * 21 *****************************************************************************/ 22 23 24 /*************************************************************** 25 *************************************************************** 26 * Macros to emulate the 65C02 opcodes 27 *************************************************************** 28 ***************************************************************/ 29 30 /* 65C02 ******************************************************* 31 * EA = absolute address + X 32 * one additional read if page boundary is crossed 33 ***************************************************************/ 34 #define EA_ABX_C02_P \ 35 EA_ABS; \ 36 if ( EAL + X > 0xff ) { \ 37 RDMEM( PCW - 1 ); \ 38 } \ 39 EAW += X; 40 41 /* 65C02 ******************************************************* 42 * EA = absolute address + X 43 ***************************************************************/ 44 #define EA_ABX_C02_NP \ 45 EA_ABS; \ 46 RDMEM( PCW - 1 ); \ 47 EAW += X; 48 49 /*************************************************************** 50 * EA = absolute address + Y 51 * one additional read if page boundary is crossed 52 ***************************************************************/ 53 #define EA_ABY_C02_P \ 54 EA_ABS; \ 55 if ( EAL + Y > 0xff ) { \ 56 RDMEM( PCW - 1 ); \ 57 } \ 58 EAW += Y; 59 60 /* 65C02 ******************************************************* 61 * EA = absolute address + Y 62 ***************************************************************/ 63 #define EA_ABY_C02_NP \ 64 EA_ABS; \ 65 RDMEM( PCW - 1 ); \ 66 EAW += Y 67 68 /* 65C02 ******************************************************* 69 * EA = zero page indirect + Y (post indexed) 70 * subtract 1 cycle if page boundary is crossed 71 ***************************************************************/ 72 #define EA_IDY_C02_P \ 73 ZPL = RDOPARG(); \ 74 EAL = RDMEM(ZPD); \ 75 ZPL++; \ 76 EAH = RDMEM(ZPD); \ 77 if (EAL + Y > 0xff) { \ 78 RDMEM( PCW - 1 ); \ 79 } \ 80 EAW += Y; 81 82 /* 65C02 ******************************************************* 83 * EA = zero page indirect + Y 84 ***************************************************************/ 85 #define EA_IDY_C02_NP \ 86 ZPL = RDOPARG(); \ 87 EAL = RDMEM(ZPD); \ 88 ZPL++; \ 89 EAH = RDMEM(ZPD); \ 90 RDMEM( PCW - 1 ); \ 91 EAW += Y 92 93 /* 65C02 ******************************************************* 94 * EA = indirect (only used by JMP) 95 * correct overflow handling 96 ***************************************************************/ 97 #define EA_IND_C02 \ 98 EA_ABS; \ 99 tmp = RDMEM(EAD); \ 100 RDMEM(PCW-1); \ 101 EAD++; \ 102 EAH = RDMEM(EAD); \ 103 EAL = tmp 104 105 /* 65C02 ******************************************************* 106 * EA = indirect plus x (only used by 65c02 JMP) 107 ***************************************************************/ 108 #define EA_IAX \ 109 EA_ABS; \ 110 RDMEM( PCW - 1 ); \ 111 if (EAL + X > 0xff) { \ 112 RDMEM( PCW - 1 ); \ 113 } \ 114 EAW += X; \ 115 tmp = RDMEM(EAD); \ 116 EAD++; \ 117 EAH = RDMEM(EAD); \ 118 EAL = tmp 119 120 /* read a value into tmp */ 121 /* Base number of cycles taken for each mode (including reading of opcode): 122 RD_ABX_C02_P 4/5 123 RD_ABX_C02_NP/WR_ABX_C02_NP 5 124 RD_ABY_C02_P 4/5 125 RD_IDY_C02_P 5/6 126 WR_IDY_C02_NP 6 127 */ 128 #define RD_ABX_C02_P EA_ABX_C02_P; tmp = RDMEM(EAD) 129 #define RD_ABX_C02_NP EA_ABX_C02_NP; tmp = RDMEM(EAD) 130 #define RD_ABX_C02_NP_DISCARD EA_ABX_C02_NP; RDMEM(EAD) 131 #define RD_ABY_C02_P EA_ABY_C02_P; tmp = RDMEM(EAD) 132 #define RD_IDY_C02_P EA_IDY_C02_P; tmp = RDMEM_ID(EAD); m6502_ICount -= 1 133 134 #define WR_ABX_C02_NP EA_ABX_C02_NP; WRMEM(EAD, tmp) 135 #define WR_ABY_C02_NP EA_ABY_C02_NP; WRMEM(EAD, tmp) 136 #define WR_IDY_C02_NP EA_IDY_C02_NP; WRMEM_ID(EAD, tmp); m6502_ICount -= 1 137 138 139 /* 65C02******************************************************** 140 * BRA branch relative 141 * extra cycle if page boundary is crossed 142 ***************************************************************/ 143 #define BRA_C02(cond) \ 144 tmp = RDOPARG(); \ 145 if (cond) \ 146 { \ 147 RDMEM(PCW); \ 148 EAW = PCW + (signed char)tmp; \ 149 if ( EAH != PCH ) { \ 150 RDMEM( PCW - 1 ); \ 151 } \ 152 PCD = EAD; \ 153 CHANGE_PC; \ 154 } 155 156 /* 65C02 ******************************************************** 157 * ADC Add with carry 158 * different setting of flags in decimal mode 159 ***************************************************************/ 160 #define ADC_C02 \ 161 if (P & F_D) \ 162 { \ 163 int c = (P & F_C); \ 164 int lo = (A & 0x0f) + (tmp & 0x0f) + c; \ 165 int hi = (A & 0xf0) + (tmp & 0xf0); \ 166 P &= ~(F_V | F_C); \ 167 if( lo > 0x09 ) \ 168 { \ 169 hi += 0x10; \ 170 lo += 0x06; \ 171 } \ 172 if( ~(A^tmp) & (A^hi) & F_N ) \ 173 P |= F_V; \ 174 if( hi > 0x90 ) \ 175 hi += 0x60; \ 176 if( hi & 0xff00 ) \ 177 P |= F_C; \ 178 A = (lo & 0x0f) + (hi & 0xf0); \ 179 RDMEM( PCW - 1 ); \ 180 } \ 181 else \ 182 { \ 183 int c = (P & F_C); \ 184 int sum = A + tmp + c; \ 185 P &= ~(F_V | F_C); \ 186 if( ~(A^tmp) & (A^sum) & F_N ) \ 187 P |= F_V; \ 188 if( sum & 0xff00 ) \ 189 P |= F_C; \ 190 A = (UINT8) sum; \ 191 } \ 192 SET_NZ(A) 193 194 /* 65C02 ******************************************************** 195 * SBC Subtract with carry 196 * different setting of flags in decimal mode 197 ***************************************************************/ 198 #define SBC_C02 \ 199 if (P & F_D) \ 200 { \ 201 int c = (P & F_C) ^ F_C; \ 202 int sum = A - tmp - c; \ 203 int lo = (A & 0x0f) - (tmp & 0x0f) - c; \ 204 int hi = (A & 0xf0) - (tmp & 0xf0); \ 205 P &= ~(F_V | F_C); \ 206 if( (A^tmp) & (A^sum) & F_N ) \ 207 P |= F_V; \ 208 if( lo & 0xf0 ) \ 209 lo -= 6; \ 210 if( lo & 0x80 ) \ 211 hi -= 0x10; \ 212 if( hi & 0x0f00 ) \ 213 hi -= 0x60; \ 214 if( (sum & 0xff00) == 0 ) \ 215 P |= F_C; \ 216 A = (lo & 0x0f) + (hi & 0xf0); \ 217 RDMEM( PCW - 1 ); \ 218 } \ 219 else \ 220 { \ 221 int c = (P & F_C) ^ F_C; \ 222 int sum = A - tmp - c; \ 223 P &= ~(F_V | F_C); \ 224 if( (A^tmp) & (A^sum) & F_N ) \ 225 P |= F_V; \ 226 if( (sum & 0xff00) == 0 ) \ 227 P |= F_C; \ 228 A = (UINT8) sum; \ 229 } \ 230 SET_NZ(A) 231 232 /* 65C02 ******************************************************* 233 * BBR Branch if bit is reset 234 ***************************************************************/ 235 #define BBR(bit) \ 236 BRA(!(tmp & (1<<bit))) 237 238 /* 65C02 ******************************************************* 239 * BBS Branch if bit is set 240 ***************************************************************/ 241 #define BBS(bit) \ 242 BRA(tmp & (1<<bit)) 243 244 /* 65c02 ******************************************************** 245 * BRK Break 246 * increment PC, push PC hi, PC lo, flags (with B bit set), 247 * set I flag, reset D flag and jump via IRQ vector 248 ***************************************************************/ 249 #define BRK_C02 \ 250 RDOPARG(); \ 251 PUSH(PCH); \ 252 PUSH(PCL); \ 253 PUSH(P | F_B); \ 254 P = (P | F_I) & ~F_D; \ 255 PCL = RDMEM(M6502_IRQ_VEC); \ 256 PCH = RDMEM(M6502_IRQ_VEC+1); \ 257 CHANGE_PC 258 259 260 /* 65C02 ******************************************************* 261 * DEA Decrement accumulator 262 ***************************************************************/ 263 #define DEA \ 264 A = (UINT8)(A - 1); \ 265 SET_NZ(A) 266 267 /* 65C02 ******************************************************* 268 * INA Increment accumulator 269 ***************************************************************/ 270 #define INA \ 271 A = (UINT8)(A + 1); \ 272 SET_NZ(A) 273 274 /* 65C02 ******************************************************* 275 * PHX Push index X 276 ***************************************************************/ 277 #define PHX \ 278 PUSH(X) 279 280 /* 65C02 ******************************************************* 281 * PHY Push index Y 282 ***************************************************************/ 283 #define PHY \ 284 PUSH(Y) 285 286 /* 65C02 ******************************************************* 287 * PLX Pull index X 288 ***************************************************************/ 289 #define PLX \ 290 RDMEM(SPD); \ 291 PULL(X); \ 292 SET_NZ(X) 293 294 /* 65C02 ******************************************************* 295 * PLY Pull index Y 296 ***************************************************************/ 297 #define PLY \ 298 RDMEM(SPD); \ 299 PULL(Y); \ 300 SET_NZ(Y) 301 302 /* 65C02 ******************************************************* 303 * RMB Reset memory bit 304 ***************************************************************/ 305 #define RMB(bit) \ 306 tmp &= ~(1<<bit) 307 308 /* 65C02 ******************************************************* 309 * SMB Set memory bit 310 ***************************************************************/ 311 #define SMB(bit) \ 312 tmp |= (1<<bit) 313 314 /* 65C02 ******************************************************* 315 * STZ Store zero 316 ***************************************************************/ 317 #define STZ \ 318 tmp = 0 319 320 /* 65C02 ******************************************************* 321 * TRB Test and reset bits 322 ***************************************************************/ 323 #define TRB \ 324 SET_Z(tmp&A); \ 325 tmp &= ~A 326 327 /* 65C02 ******************************************************* 328 * TSB Test and set bits 329 ***************************************************************/ 330 #define TSB \ 331 SET_Z(tmp&A); \ 332 tmp |= A 333 334 /* 6502 ******************************************************** 335 * BIT Bit test Immediate, only Z affected 336 ***************************************************************/ 337 #undef BIT_IMM_C02 338 #define BIT_IMM_C02 \ 339 P &= ~(F_Z); \ 340 if ((tmp & A) == 0) \ 341 P |= F_Z 342 343 344 /*************************************************************** 345 *************************************************************** 346 * Macros to emulate the 65sc02 opcodes 347 *************************************************************** 348 ***************************************************************/ 349 350 351 /* 65sc02 ******************************************************** 352 * BSR Branch to subroutine 353 ***************************************************************/ 354 #define BSR \ 355 EAL = RDOPARG(); \ 356 RDMEM(SPD); \ 357 PUSH(PCH); \ 358 PUSH(PCL); \ 359 EAH = RDOPARG(); \ 360 EAW = PCW + (INT16)(EAW-1); \ 361 PCD = EAD; \ 362 CHANGE_PC 363