1 /* 2 * cpu_macros.h - Macro definitions for 6510 CPU emulation opcode routines 3 * 4 * Frodo (C) Copyright 1994-2004 Christian Bauer 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 22 /* 23 * Status register flag bits 24 */ 25 26 #define PFLAG_N 0x80 27 #define PFLAG_V 0x40 28 #define PFLAG_B 0x10 29 #define PFLAG_D 0x08 30 #define PFLAG_I 0x04 31 #define PFLAG_Z 0x02 32 #define PFLAG_C 0x01 33 34 35 /* 36 * Opcode flag bits 37 */ 38 39 #define OPFLAG_IRQ_DISABLED 0x100 40 #define OPFLAG_IRQ_ENABLED 0x200 41 #define OPFLAG_INT_DELAYED 0x400 42 43 44 /* 45 * Address calculation macros 46 */ 47 48 // Read zero page operand address 49 #define read_adr_zero \ 50 ADR = read_opcode; inc_pc; next_cycle 51 52 // Read zero page x-indexed operand address 53 #define read_adr_zero_x \ 54 ADR = read_opcode; inc_pc; next_cycle; \ 55 read_idle_zp(ADR); next_cycle; \ 56 ADR = (ADR + RX) & 0xff 57 58 // Read zero page y-indexed operand address 59 #define read_adr_zero_y \ 60 ADR = read_opcode; inc_pc; next_cycle; \ 61 read_idle_zp(ADR); next_cycle; \ 62 ADR = (ADR + RY) & 0xff 63 64 // Read absolute operand address 65 #define read_adr_abs \ 66 ADR = read_opcode; inc_pc; next_cycle; \ 67 ADR |= read_opcode << 8; inc_pc; next_cycle 68 69 // Read absolute x-indexed operand address (no extra cycle for page crossing) 70 #define read_adr_abs_x \ 71 { \ 72 ADR = read_opcode; inc_pc; next_cycle; \ 73 unsigned int tmp = ADR + RX; \ 74 ADR = tmp + (read_opcode << 8); inc_pc; next_cycle; \ 75 if (tmp >= 0x100) { \ 76 read_idle((ADR - 0x100) & 0xffff); \ 77 } else { \ 78 read_idle(ADR); \ 79 } \ 80 next_cycle; \ 81 } 82 83 // Read absolute y-indexed operand address (no extra cycle for page crossing) 84 #define read_adr_abs_y \ 85 { \ 86 ADR = read_opcode; inc_pc; next_cycle; \ 87 unsigned int tmp = ADR + RY; \ 88 ADR = tmp + (read_opcode << 8); inc_pc; next_cycle; \ 89 if (tmp >= 0x100) { \ 90 read_idle((ADR - 0x100) & 0xffff); \ 91 } else { \ 92 read_idle(ADR); \ 93 } \ 94 next_cycle; \ 95 } 96 97 // Read indexed indirect operand address (no extra cycle for page crossing) 98 #define read_adr_ind_x \ 99 { \ 100 unsigned int tmp = read_opcode; inc_pc; next_cycle; \ 101 read_idle_zp(tmp); next_cycle; \ 102 tmp += RX; \ 103 ADR = read_zp(tmp & 0xff); next_cycle; \ 104 ADR |= read_zp((tmp + 1) & 0xff) << 8; next_cycle; \ 105 } 106 107 // Read indirect indexed operand address (no extra cycle for page crossing) 108 #define read_adr_ind_y \ 109 { \ 110 unsigned int tmp = read_opcode; inc_pc; next_cycle; \ 111 unsigned int tmp2 = read_zp(tmp) + RY; next_cycle; \ 112 ADR = tmp2 + (read_zp((tmp + 1) & 0xff) << 8); next_cycle; \ 113 if (tmp2 >= 0x100) { \ 114 read_idle((ADR - 0x100) & 0xffff); \ 115 } else { \ 116 read_idle(ADR); \ 117 } \ 118 next_cycle; \ 119 } 120 121 122 /* 123 * Operand fetch macros 124 */ 125 126 // Read immediate operand 127 #define read_byte_imm(to) \ 128 to = read_opcode; inc_pc; next_cycle 129 130 // Read zero page operand 131 #define read_byte_zero(to) \ 132 read_adr_zero; \ 133 to = read_zp(ADR); next_cycle 134 135 // Read zero page x-indexed operand 136 #define read_byte_zero_x(to) \ 137 read_adr_zero_x; \ 138 to = read_zp(ADR); next_cycle 139 140 // Read zero page y-indexed operand 141 #define read_byte_zero_y(to) \ 142 read_adr_zero_y; \ 143 to = read_zp(ADR); next_cycle 144 145 // Read absolute operand 146 #define read_byte_abs(to) \ 147 read_adr_abs; \ 148 to = read_byte(ADR); next_cycle; 149 150 // Read absolute x-indexed operand (extra cycle for page crossing) 151 #define read_byte_abs_x(to) \ 152 { \ 153 ADR = read_opcode; inc_pc; next_cycle; \ 154 unsigned int tmp = ADR + RX; \ 155 ADR = tmp + (read_opcode << 8); inc_pc; next_cycle; \ 156 if (tmp >= 0x100) { \ 157 /* Page crossed */ \ 158 read_idle((ADR - 0x100) & 0xffff); next_cycle; \ 159 } \ 160 to = read_byte(ADR); next_cycle; \ 161 } 162 163 // Read absolute y-indexed operand (extra cycle for page crossing) 164 #define read_byte_abs_y(to) \ 165 { \ 166 ADR = read_opcode; inc_pc; next_cycle; \ 167 unsigned int tmp = ADR + RY; \ 168 ADR = tmp + (read_opcode << 8); inc_pc; next_cycle; \ 169 if (tmp >= 0x100) { \ 170 /* Page crossed */ \ 171 read_idle((ADR - 0x100) & 0xffff); next_cycle; \ 172 } \ 173 to = read_byte(ADR); next_cycle; \ 174 } 175 176 // Read indexed indirect operand (no extra cycle for page crossing) 177 #define read_byte_ind_x(to) \ 178 read_adr_ind_x; \ 179 to = read_byte(ADR); next_cycle; 180 181 // Read indirect indexed operand (extra cycle for page crossing) 182 #define read_byte_ind_y(to) \ 183 { \ 184 unsigned int tmp = read_opcode; inc_pc; next_cycle; \ 185 unsigned int tmp2 = read_zp(tmp) + RY; next_cycle; \ 186 ADR = tmp2 + (read_zp((tmp + 1) & 0xff) << 8); next_cycle; \ 187 if (tmp2 >= 0x100) { \ 188 /* Page crossed */ \ 189 read_idle((ADR - 0x100) & 0xffff); next_cycle; \ 190 } \ 191 to = read_byte(ADR); next_cycle; \ 192 } 193 194 195 /* 196 * Other macros 197 */ 198 199 // Set N and Z flags 200 #define set_nz(val) \ 201 N_FLAG = Z_FLAG = val 202 203 // Pop status flags 204 #define pop_flags \ 205 N_FLAG = PFLAGS = pop_byte & 0xcf; next_cycle; \ 206 Z_FLAG = !(PFLAGS & PFLAG_Z) 207 208 // Push status flags 209 #ifdef DRIVE_CPU 210 #define push_flags(b_flag) \ 211 { \ 212 gcr_drive->Update(current_cycle); \ 213 if (gcr_drive->ByteReady()) \ 214 PFLAGS |= PFLAG_V; \ 215 (N_FLAG & 0x80) ? (PFLAGS |= PFLAG_N) : (PFLAGS &= ~PFLAG_N); \ 216 Z_FLAG ? (PFLAGS &= ~PFLAG_Z) : (PFLAGS |= PFLAG_Z); \ 217 push_byte(PFLAGS | 0x20 | b_flag); next_cycle; \ 218 } 219 #else 220 #define push_flags(b_flag) \ 221 (N_FLAG & 0x80) ? (PFLAGS |= PFLAG_N) : (PFLAGS &= ~PFLAG_N); \ 222 Z_FLAG ? (PFLAGS &= ~PFLAG_Z) : (PFLAGS |= PFLAG_Z); \ 223 push_byte(PFLAGS | 0x20 | b_flag); next_cycle 224 #endif 225 226 // ADC operation 227 #define do_adc(byte) \ 228 if (PFLAGS & PFLAG_D) { \ 229 unsigned int tmp, tmp2; \ 230 tmp = (RA & 0x0f) + (byte & 0x0f) + (PFLAGS & PFLAG_C); \ 231 if (tmp > 9) tmp += 6; \ 232 tmp2 = (tmp & 0x0f) + (RA & 0xf0) + (byte & 0xf0); \ 233 if (tmp > 0x0f) tmp2 += 0x10; \ 234 Z_FLAG = RA + byte + (PFLAGS & PFLAG_C); \ 235 N_FLAG = tmp2; \ 236 (!((RA ^ byte) & 0x80) && ((RA ^ tmp2) & 0x80)) ? (PFLAGS |= PFLAG_V) : (PFLAGS &= ~PFLAG_V); \ 237 if ((tmp2 & 0x1f0) > 0x90) tmp2 += 0x60; \ 238 (tmp2 & 0xf00) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 239 RA = tmp2; \ 240 } else { \ 241 unsigned int tmp = RA + byte + (PFLAGS & PFLAG_C); \ 242 (tmp > 0xff) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 243 (!((RA ^ byte) & 0x80) && ((RA ^ tmp) & 0x80)) ? (PFLAGS |= PFLAG_V) : (PFLAGS &= ~PFLAG_V); \ 244 set_nz(RA = tmp); \ 245 } \ 246 break 247 248 // SBC operation 249 #define do_sbc(byte) \ 250 { \ 251 unsigned int tmp = RA - byte - ((PFLAGS & PFLAG_C) ? 0 : 1); \ 252 (((RA ^ tmp) & 0x80) && ((RA ^ byte) & 0x80)) ? (PFLAGS |= PFLAG_V) : (PFLAGS &= ~PFLAG_V); \ 253 if (PFLAGS & PFLAG_D) { \ 254 unsigned int tmp2 = (RA & 0x0f) - (byte & 0x0f) - ((PFLAGS & PFLAG_C) ? 0 : 1); \ 255 if (tmp2 & 0x10) \ 256 tmp2 = ((tmp2 - 6) & 0x0f) | ((RA & 0xf0) - (byte & 0xf0) - 0x10); \ 257 else \ 258 tmp2 = (tmp2 & 0x0f) | ((RA & 0xf0) - (byte & 0xf0)); \ 259 if (tmp2 & 0x100) tmp2 -= 0x60; \ 260 RA = tmp2; \ 261 } else { \ 262 RA = tmp; \ 263 } \ 264 (tmp < 0x100) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 265 set_nz(tmp); \ 266 break; \ 267 } 268 269 // CMP operation 270 #define do_cmp \ 271 unsigned int tmp = RA - t; \ 272 set_nz(tmp); \ 273 (tmp < 0x100) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 274 break 275 276 // CPX operation 277 #define do_cpx \ 278 unsigned int tmp = RX - t; \ 279 set_nz(tmp); \ 280 (tmp < 0x100) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 281 break 282 283 // CPY operation 284 #define do_cpy \ 285 unsigned int tmp = RY - t; \ 286 set_nz(tmp); \ 287 (tmp < 0x100) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 288 break 289 290 // BIT operation 291 #define do_bit \ 292 Z_FLAG = RA & t; \ 293 N_FLAG = t; \ 294 (t & 0x40) ? (PFLAGS |= PFLAG_V) : (PFLAGS &= ~PFLAG_V); \ 295 break 296 297 // ASL operation 298 #define do_asl(write_cmd) \ 299 (t & 0x80) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 300 next_cycle; write_cmd(ADR, set_nz(t << 1)); next_cycle; \ 301 break 302 303 // LSR operation 304 #define do_lsr(write_cmd) \ 305 (t & 0x01) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 306 next_cycle; write_cmd(ADR, set_nz(t >> 1)); next_cycle; \ 307 break 308 309 // ROL operation 310 #define do_rol(write_cmd) \ 311 next_cycle; write_cmd(ADR, set_nz((t << 1) | (PFLAGS & PFLAG_C))); next_cycle; \ 312 (t & 0x80) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 313 break 314 315 // ROR operation 316 #define do_ror(write_cmd) \ 317 next_cycle; write_cmd(ADR, set_nz((PFLAGS & PFLAG_C) ? (t >> 1) | 0x80 : (t >> 1))); next_cycle; \ 318 (t & 0x01) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 319 break 320 321 // Branch operation 322 #define branch(flag) \ 323 { \ 324 int8 tmp = read_opcode; inc_pc; next_cycle; \ 325 if (flag) { \ 326 /* Branch taken */ \ 327 ADR = RPC + (int8)tmp; \ 328 if ((ADR ^ RPC) & 0xff00) { \ 329 /* Page crossed */ \ 330 read_idle_opcode; next_cycle; \ 331 if (tmp & 0x80) { \ 332 read_idle(ADR + 0x100); next_cycle; \ 333 } else { \ 334 read_idle(ADR - 0x100); next_cycle; \ 335 } \ 336 jump(ADR); \ 337 } else { \ 338 /* No page crossed */ \ 339 opcode |= OPFLAG_INT_DELAYED; \ 340 read_idle_opcode; next_cycle; \ 341 jump(ADR); \ 342 } \ 343 } \ 344 break; \ 345 } 346 347 // SLO operation 348 #define do_slo(write_cmd) \ 349 (t & 0x80) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 350 next_cycle; write_cmd(ADR, t <<= 1); next_cycle; \ 351 set_nz(RA |= t); \ 352 break 353 354 // RLA operation 355 #define do_rla(write_cmd) \ 356 unsigned int t2 = (t << 1) | (PFLAGS & PFLAG_C); \ 357 next_cycle; write_cmd(ADR, t2); next_cycle; \ 358 (t & 0x80) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 359 set_nz(RA &= t2); \ 360 break 361 362 // SRE operation 363 #define do_sre(write_cmd) \ 364 (t & 0x01) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 365 next_cycle; write_cmd(ADR, t >>= 1); next_cycle; \ 366 set_nz(RA ^= t); \ 367 break 368 369 // RRA operation 370 #define do_rra(write_cmd) \ 371 unsigned int t2 = (PFLAGS & PFLAG_C) ? (t >> 1) | 0x80 : (t >> 1); \ 372 next_cycle; write_cmd(ADR, t2); next_cycle; \ 373 (t & 0x01) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 374 do_adc(t2); 375 376 // DCP operation 377 #define do_dcp(write_cmd) \ 378 t = (t - 1) & 0xff; \ 379 next_cycle; write_cmd(ADR, t); next_cycle; \ 380 t = RA - t; \ 381 set_nz(t); \ 382 (t < 0x100) ? (PFLAGS |= PFLAG_C) : (PFLAGS &= ~PFLAG_C); \ 383 break 384 385 // ISB operation 386 #define do_isb(write_cmd) \ 387 t = (t + 1) & 0xff; \ 388 next_cycle; write_cmd(ADR, t); next_cycle; \ 389 do_sbc(t); 390