1#[allow(clippy::wildcard_imports)] 2use super::*; 3use jgenesis_common::num::U16Ext; 4 5macro_rules! impl_branch { 6 ($name:ident $(, $flag:ident == $value:expr)?) => { 7 pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 8 match cpu.state.cycle { 9 1 => { 10 cpu.state.t0 = fetch_operand(cpu, bus); 11 12 // Check if branch should be taken; skip rest of instruction if not 13 $( 14 if cpu.registers.psw.$flag != $value { 15 cpu.state.cycle = 0; 16 } 17 )? 18 } 19 2 => { 20 bus.idle(); 21 } 22 3 => { 23 cpu.final_cycle(); 24 bus.idle(); 25 26 cpu.registers.pc = cpu.registers.pc.wrapping_add(cpu.state.t0 as i8 as u16); 27 } 28 _ => invalid_cycle!(cpu) 29 } 30 } 31 } 32} 33 34impl_branch!(bra); 35impl_branch!(beq, zero == true); 36impl_branch!(bne, zero == false); 37impl_branch!(bcs, carry == true); 38impl_branch!(bcc, carry == false); 39impl_branch!(bvs, overflow == true); 40impl_branch!(bvc, overflow == false); 41impl_branch!(bmi, negative == true); 42impl_branch!(bpl, negative == false); 43 44macro_rules! impl_branch_memory_bit { 45 ($name:ident, bit == $value:expr) => { 46 pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B, bit: u8) { 47 match cpu.state.cycle { 48 1 => { 49 cpu.state.t0 = fetch_operand(cpu, bus); 50 } 51 2 => { 52 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 53 cpu.state.t1 = bus.read(address); 54 } 55 3 | 5 => { 56 bus.idle(); 57 } 58 4 => { 59 cpu.state.t2 = fetch_operand(cpu, bus); 60 61 // Skip rest of instruction if specified bit is not set/clear 62 if cpu.state.t1.bit(bit) != $value { 63 cpu.state.cycle = 0; 64 } 65 } 66 6 => { 67 cpu.final_cycle(); 68 bus.idle(); 69 70 cpu.registers.pc = cpu.registers.pc.wrapping_add(cpu.state.t2 as i8 as u16); 71 } 72 _ => invalid_cycle!(cpu), 73 } 74 } 75 }; 76} 77 78impl_branch_memory_bit!(bbs, bit == true); 79impl_branch_memory_bit!(bbc, bit == false); 80 81pub(crate) fn cbne_dp<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 82 match cpu.state.cycle { 83 1 => { 84 cpu.state.t0 = fetch_operand(cpu, bus); 85 } 86 2 => { 87 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 88 cpu.state.t1 = bus.read(address); 89 } 90 3 | 5 => { 91 bus.idle(); 92 } 93 4 => { 94 cpu.state.t2 = fetch_operand(cpu, bus); 95 96 // Skip rest of instruction if A == (dp) 97 if cpu.registers.a == cpu.state.t1 { 98 cpu.state.cycle = 0; 99 } 100 } 101 // 5: Idle 102 6 => { 103 cpu.final_cycle(); 104 bus.idle(); 105 106 cpu.registers.pc = cpu.registers.pc.wrapping_add(cpu.state.t2 as i8 as u16); 107 } 108 _ => invalid_cycle!(cpu), 109 } 110} 111 112pub(crate) fn cbne_dpx<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 113 match cpu.state.cycle { 114 1 => { 115 cpu.state.t0 = fetch_operand(cpu, bus); 116 } 117 2 | 4 | 6 => { 118 bus.idle(); 119 } 120 3 => { 121 let address_lsb = cpu.state.t0.wrapping_add(cpu.registers.x); 122 let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]); 123 cpu.state.t1 = bus.read(address); 124 } 125 // 4: Idle 126 5 => { 127 cpu.state.t2 = fetch_operand(cpu, bus); 128 129 // Skip rest of instruction if A == (dp+X) 130 if cpu.registers.a == cpu.state.t1 { 131 cpu.state.cycle = 0; 132 } 133 } 134 // 6: Idle 135 7 => { 136 cpu.final_cycle(); 137 bus.idle(); 138 139 cpu.registers.pc = cpu.registers.pc.wrapping_add(cpu.state.t2 as i8 as u16); 140 } 141 _ => invalid_cycle!(cpu), 142 } 143} 144 145pub(crate) fn dbnz_dp<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 146 match cpu.state.cycle { 147 1 => { 148 cpu.state.t0 = fetch_operand(cpu, bus); 149 } 150 2 => { 151 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 152 cpu.state.t1 = bus.read(address); 153 } 154 3 => { 155 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 156 bus.write(address, cpu.state.t1.wrapping_sub(1)); 157 } 158 4 => { 159 cpu.state.t2 = fetch_operand(cpu, bus); 160 161 // Skip rest of instruction if --(dp) == 0 162 if cpu.state.t1 == 1 { 163 cpu.state.cycle = 0; 164 } 165 } 166 5 => { 167 bus.idle(); 168 } 169 6 => { 170 cpu.final_cycle(); 171 bus.idle(); 172 173 cpu.registers.pc = cpu.registers.pc.wrapping_add(cpu.state.t2 as i8 as u16); 174 } 175 _ => invalid_cycle!(cpu), 176 } 177} 178 179pub(crate) fn dbnz_y<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 180 match cpu.state.cycle { 181 1 | 2 | 4 => { 182 bus.idle(); 183 } 184 3 => { 185 cpu.state.t1 = fetch_operand(cpu, bus); 186 187 // Skip rest of instruction if --Y == 0 188 cpu.registers.y = cpu.registers.y.wrapping_sub(1); 189 if cpu.registers.y == 0 { 190 cpu.state.cycle = 0; 191 } 192 } 193 // 4: Idle 194 5 => { 195 cpu.final_cycle(); 196 bus.idle(); 197 198 cpu.registers.pc = cpu.registers.pc.wrapping_add(cpu.state.t1 as i8 as u16); 199 } 200 _ => invalid_cycle!(cpu), 201 } 202} 203 204pub(crate) fn jmp_abs<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 205 match cpu.state.cycle { 206 1 => { 207 cpu.state.t0 = fetch_operand(cpu, bus); 208 } 209 2 => { 210 cpu.final_cycle(); 211 212 let address_msb = fetch_operand(cpu, bus); 213 cpu.registers.pc = u16::from_le_bytes([cpu.state.t0, address_msb]); 214 } 215 _ => invalid_cycle!(cpu), 216 } 217} 218 219pub(crate) fn jmp_absx_ind<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 220 match cpu.state.cycle { 221 1 => { 222 cpu.state.t0 = fetch_operand(cpu, bus); 223 } 224 2 => { 225 cpu.state.t1 = fetch_operand(cpu, bus); 226 } 227 3 => { 228 bus.idle(); 229 } 230 4 => { 231 let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]) 232 .wrapping_add(cpu.registers.x.into()); 233 cpu.state.t2 = bus.read(address); 234 } 235 5 => { 236 cpu.final_cycle(); 237 238 let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]) 239 .wrapping_add(cpu.registers.x.into()) 240 .wrapping_add(1); 241 let jump_address_msb = bus.read(address); 242 cpu.registers.pc = u16::from_le_bytes([cpu.state.t2, jump_address_msb]); 243 } 244 _ => invalid_cycle!(cpu), 245 } 246} 247 248pub(crate) fn call<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 249 match cpu.state.cycle { 250 1 => { 251 cpu.state.t0 = fetch_operand(cpu, bus); 252 } 253 2 => { 254 cpu.state.t1 = fetch_operand(cpu, bus); 255 } 256 3 | 6 => { 257 bus.idle(); 258 } 259 4 => { 260 bus.write(cpu.stack_pointer(), cpu.registers.pc.msb()); 261 cpu.registers.sp = cpu.registers.sp.wrapping_sub(1); 262 } 263 5 => { 264 bus.write(cpu.stack_pointer(), cpu.registers.pc.lsb()); 265 cpu.registers.sp = cpu.registers.sp.wrapping_sub(1); 266 } 267 // 6: Idle 268 7 => { 269 cpu.final_cycle(); 270 bus.idle(); 271 272 cpu.registers.pc = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]); 273 } 274 _ => invalid_cycle!(cpu), 275 } 276} 277 278pub(crate) fn pcall<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 279 match cpu.state.cycle { 280 1 => { 281 cpu.state.t0 = fetch_operand(cpu, bus); 282 } 283 2 => { 284 bus.idle(); 285 } 286 3 => { 287 bus.write(cpu.stack_pointer(), cpu.registers.pc.msb()); 288 cpu.registers.sp = cpu.registers.sp.wrapping_sub(1); 289 } 290 4 => { 291 bus.write(cpu.stack_pointer(), cpu.registers.pc.lsb()); 292 cpu.registers.sp = cpu.registers.sp.wrapping_sub(1); 293 } 294 5 => { 295 cpu.final_cycle(); 296 bus.idle(); 297 298 cpu.registers.pc = u16::from_le_bytes([cpu.state.t0, 0xFF]); 299 } 300 _ => invalid_cycle!(cpu), 301 } 302} 303 304pub(crate) fn tcall<B: BusInterface>(cpu: &mut Spc700, bus: &mut B, n: u16) { 305 match cpu.state.cycle { 306 1 => { 307 // Dummy read 308 bus.read(cpu.registers.pc); 309 } 310 2 | 5 => { 311 bus.idle(); 312 } 313 3 => { 314 bus.write(cpu.stack_pointer(), cpu.registers.pc.msb()); 315 cpu.registers.sp = cpu.registers.sp.wrapping_sub(1); 316 } 317 4 => { 318 bus.write(cpu.stack_pointer(), cpu.registers.pc.lsb()); 319 cpu.registers.sp = cpu.registers.sp.wrapping_sub(1); 320 } 321 // 5: Idle 322 6 => { 323 let address = 0xFFC0 + 2 * (15 - n); 324 cpu.state.t0 = bus.read(address); 325 } 326 7 => { 327 cpu.final_cycle(); 328 329 let address = 0xFFC1 + 2 * (15 - n); 330 let jump_address_msb = bus.read(address); 331 cpu.registers.pc = u16::from_le_bytes([cpu.state.t0, jump_address_msb]); 332 } 333 _ => invalid_cycle!(cpu), 334 } 335} 336 337pub(crate) fn ret<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 338 match cpu.state.cycle { 339 1 | 2 => { 340 bus.idle(); 341 } 342 3 => { 343 cpu.registers.sp = cpu.registers.sp.wrapping_add(1); 344 cpu.state.t0 = bus.read(cpu.stack_pointer()); 345 } 346 4 => { 347 cpu.final_cycle(); 348 349 cpu.registers.sp = cpu.registers.sp.wrapping_add(1); 350 let pc_msb = bus.read(cpu.stack_pointer()); 351 cpu.registers.pc = u16::from_le_bytes([cpu.state.t0, pc_msb]); 352 } 353 _ => invalid_cycle!(cpu), 354 } 355} 356 357pub(crate) fn reti<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 358 match cpu.state.cycle { 359 1 | 2 => { 360 bus.idle(); 361 } 362 3 => { 363 cpu.registers.sp = cpu.registers.sp.wrapping_add(1); 364 cpu.registers.psw = bus.read(cpu.stack_pointer()).into(); 365 } 366 4 => { 367 cpu.registers.sp = cpu.registers.sp.wrapping_add(1); 368 cpu.state.t0 = bus.read(cpu.stack_pointer()); 369 } 370 5 => { 371 cpu.final_cycle(); 372 373 cpu.registers.sp = cpu.registers.sp.wrapping_add(1); 374 let pc_msb = bus.read(cpu.stack_pointer()); 375 cpu.registers.pc = u16::from_le_bytes([cpu.state.t0, pc_msb]); 376 } 377 _ => invalid_cycle!(cpu), 378 } 379} 380 381const BRK_VECTOR: u16 = 0xFFDE; 382 383pub(crate) fn brk<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 384 match cpu.state.cycle { 385 1 | 5 => { 386 bus.idle(); 387 } 388 2 => { 389 bus.write(cpu.stack_pointer(), cpu.registers.pc.msb()); 390 cpu.registers.sp = cpu.registers.sp.wrapping_sub(1); 391 } 392 3 => { 393 bus.write(cpu.stack_pointer(), cpu.registers.pc.lsb()); 394 cpu.registers.sp = cpu.registers.sp.wrapping_sub(1); 395 } 396 4 => { 397 bus.write(cpu.stack_pointer(), cpu.registers.psw.into()); 398 cpu.registers.sp = cpu.registers.sp.wrapping_sub(1); 399 } 400 // 5: Idle 401 6 => { 402 cpu.state.t0 = bus.read(BRK_VECTOR); 403 } 404 7 => { 405 cpu.final_cycle(); 406 407 let pc_msb = bus.read(BRK_VECTOR + 1); 408 cpu.registers.pc = u16::from_le_bytes([cpu.state.t0, pc_msb]); 409 cpu.registers.psw.break_flag = true; 410 cpu.registers.psw.interrupt_enabled = false; 411 } 412 _ => invalid_cycle!(cpu), 413 } 414} 415 416pub(crate) fn stop<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 417 cpu.final_cycle(); 418 bus.idle(); 419 cpu.state.stopped = true; 420}