1#[allow(clippy::wildcard_imports)] 2use super::*; 3 4impl_read_op!( 5 [ 6 immediate -> mov_a_imm, 7 x_indirect -> mov_a_xind, 8 x_indirect_postinc -> mov_a_xind_postinc, 9 direct_page -> mov_a_dp, 10 direct_page_x -> mov_a_dpx, 11 absolute -> mov_a_abs, 12 absolute_x -> mov_a_absx, 13 absolute_y -> mov_a_absy, 14 indirect_x -> mov_a_indx, 15 indirect_y -> mov_a_indy, 16 ] 17 (|registers, value| { 18 registers.a = value; 19 registers.psw.zero = value == 0; 20 registers.psw.negative = value.sign_bit(); 21 }) 22); 23 24impl_read_op!( 25 [ 26 immediate -> mov_x_imm, 27 direct_page -> mov_x_dp, 28 direct_page_y -> mov_x_dpy, 29 absolute -> mov_x_abs, 30 ] 31 (|registers, value| { 32 registers.x = value; 33 registers.psw.zero = value == 0; 34 registers.psw.negative = value.sign_bit(); 35 }) 36); 37 38impl_read_op!( 39 [ 40 immediate -> mov_y_imm, 41 direct_page -> mov_y_dp, 42 direct_page_x -> mov_y_dpx, 43 absolute -> mov_y_abs, 44 ] 45 (|registers, value| { 46 registers.y = value; 47 registers.psw.zero = value == 0; 48 registers.psw.negative = value.sign_bit(); 49 }) 50); 51 52macro_rules! impl_store_direct_page { 53 ($name:ident, $register:ident) => { 54 pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 55 match cpu.state.cycle { 56 1 => { 57 cpu.state.t0 = fetch_operand(cpu, bus); 58 } 59 2 => { 60 // Dummy read 61 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 62 bus.read(address); 63 } 64 3 => { 65 cpu.final_cycle(); 66 67 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 68 bus.write(address, cpu.registers.$register); 69 } 70 _ => invalid_cycle!(cpu), 71 } 72 } 73 }; 74} 75 76macro_rules! impl_store_direct_page_indexed { 77 ($name:ident, $register:ident, index: $index:ident) => { 78 pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 79 match cpu.state.cycle { 80 1 => { 81 cpu.state.t0 = fetch_operand(cpu, bus); 82 } 83 2 => { 84 bus.idle(); 85 } 86 3 => { 87 // Dummy read 88 let address_lsb = cpu.state.t0.wrapping_add(cpu.registers.$index); 89 let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]); 90 bus.read(address); 91 } 92 4 => { 93 cpu.final_cycle(); 94 95 let address_lsb = cpu.state.t0.wrapping_add(cpu.registers.$index); 96 let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]); 97 bus.write(address, cpu.registers.$register); 98 } 99 _ => invalid_cycle!(cpu), 100 } 101 } 102 }; 103} 104 105macro_rules! impl_store_absolute { 106 ($name:ident, $register:ident) => { 107 pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 108 match cpu.state.cycle { 109 1 => { 110 cpu.state.t0 = fetch_operand(cpu, bus); 111 } 112 2 => { 113 cpu.state.t1 = fetch_operand(cpu, bus); 114 } 115 3 => { 116 // Dummy read 117 let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]); 118 bus.read(address); 119 } 120 4 => { 121 cpu.final_cycle(); 122 123 let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]); 124 bus.write(address, cpu.registers.$register); 125 } 126 _ => invalid_cycle!(cpu), 127 } 128 } 129 }; 130} 131 132macro_rules! impl_store_a_absolute_indexed { 133 ($name:ident, index: $index:ident) => { 134 pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 135 match cpu.state.cycle { 136 1 => { 137 cpu.state.t0 = fetch_operand(cpu, bus); 138 } 139 2 => { 140 cpu.state.t1 = fetch_operand(cpu, bus); 141 } 142 3 => { 143 bus.idle(); 144 } 145 4 => { 146 // Dummy read 147 let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]) 148 .wrapping_add(cpu.registers.$index.into()); 149 bus.read(address); 150 } 151 5 => { 152 cpu.final_cycle(); 153 154 let address = u16::from_le_bytes([cpu.state.t0, cpu.state.t1]) 155 .wrapping_add(cpu.registers.$index.into()); 156 bus.write(address, cpu.registers.a); 157 } 158 _ => invalid_cycle!(cpu), 159 } 160 } 161 }; 162} 163 164impl_store_direct_page!(mov_dp_a, a); 165impl_store_direct_page_indexed!(mov_dpx_a, a, index: x); 166impl_store_absolute!(mov_abs_a, a); 167impl_store_a_absolute_indexed!(mov_absx_a, index: x); 168impl_store_a_absolute_indexed!(mov_absy_a, index: y); 169 170impl_store_direct_page!(mov_dp_x, x); 171impl_store_direct_page_indexed!(mov_dpy_x, x, index: y); 172impl_store_absolute!(mov_abs_x, x); 173 174impl_store_direct_page!(mov_dp_y, y); 175impl_store_direct_page_indexed!(mov_dpx_y, y, index: x); 176impl_store_absolute!(mov_abs_y, y); 177 178pub(crate) fn mov_xind_a<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 179 match cpu.state.cycle { 180 1 => { 181 bus.idle(); 182 } 183 2 => { 184 // Dummy read 185 let address = u16::from_le_bytes([cpu.registers.x, cpu.direct_page_msb()]); 186 bus.read(address); 187 } 188 3 => { 189 cpu.final_cycle(); 190 191 let address = u16::from_le_bytes([cpu.registers.x, cpu.direct_page_msb()]); 192 bus.write(address, cpu.registers.a); 193 } 194 _ => invalid_cycle!(cpu), 195 } 196} 197 198pub(crate) fn mov_xind_postinc_a<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 199 match cpu.state.cycle { 200 1 | 2 => { 201 bus.idle(); 202 } 203 3 => { 204 cpu.final_cycle(); 205 206 let address = u16::from_le_bytes([cpu.registers.x, cpu.direct_page_msb()]); 207 bus.write(address, cpu.registers.a); 208 cpu.registers.x = cpu.registers.x.wrapping_add(1); 209 } 210 _ => invalid_cycle!(cpu), 211 } 212} 213 214pub(crate) fn mov_indx_a<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 215 match cpu.state.cycle { 216 1 => { 217 cpu.state.t0 = fetch_operand(cpu, bus); 218 } 219 2 => { 220 bus.idle(); 221 } 222 3 => { 223 let address_lsb = cpu.state.t0.wrapping_add(cpu.registers.x); 224 let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]); 225 cpu.state.t1 = bus.read(address); 226 } 227 4 => { 228 let address_lsb = cpu.state.t0.wrapping_add(cpu.registers.x).wrapping_add(1); 229 let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]); 230 cpu.state.t2 = bus.read(address); 231 } 232 5 => { 233 // Dummy read 234 let address = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]); 235 bus.read(address); 236 } 237 6 => { 238 cpu.final_cycle(); 239 240 let address = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]); 241 bus.write(address, cpu.registers.a); 242 } 243 _ => invalid_cycle!(cpu), 244 } 245} 246 247pub(crate) fn mov_indy_a<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 248 match cpu.state.cycle { 249 1 => { 250 cpu.state.t0 = fetch_operand(cpu, bus); 251 } 252 2 => { 253 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 254 cpu.state.t1 = bus.read(address); 255 } 256 3 => { 257 let address_lsb = cpu.state.t0.wrapping_add(1); 258 let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]); 259 cpu.state.t2 = bus.read(address); 260 } 261 4 => { 262 bus.idle(); 263 } 264 5 => { 265 // Dummy read 266 let address = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]) 267 .wrapping_add(cpu.registers.y.into()); 268 bus.read(address); 269 } 270 6 => { 271 cpu.final_cycle(); 272 273 let address = u16::from_le_bytes([cpu.state.t1, cpu.state.t2]) 274 .wrapping_add(cpu.registers.y.into()); 275 bus.write(address, cpu.registers.a); 276 } 277 _ => invalid_cycle!(cpu), 278 } 279} 280 281macro_rules! impl_transfer_op { 282 (@set_flags sp, $registers:expr) => {}; 283 (@set_flags $to:ident, $registers:expr) => { 284 $registers.psw.zero = $registers.$to == 0; 285 $registers.psw.negative = $registers.$to.sign_bit(); 286 }; 287 ($name:ident, $to:ident <- $from:ident) => { 288 impl_registers_op!($name, |registers| { 289 registers.$to = registers.$from; 290 impl_transfer_op!(@set_flags $to, registers); 291 }); 292 } 293} 294 295impl_transfer_op!(mov_a_x, a <- x); 296impl_transfer_op!(mov_a_y, a <- y); 297impl_transfer_op!(mov_x_a, x <- a); 298impl_transfer_op!(mov_y_a, y <- a); 299impl_transfer_op!(mov_x_sp, x <- sp); 300impl_transfer_op!(mov_sp_x, sp <- x); 301 302pub(crate) fn mov_dp_dp<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 303 match cpu.state.cycle { 304 1 => { 305 cpu.state.t0 = fetch_operand(cpu, bus); 306 } 307 2 => { 308 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 309 cpu.state.t1 = bus.read(address); 310 } 311 3 => { 312 cpu.state.t2 = fetch_operand(cpu, bus); 313 } 314 4 => { 315 cpu.final_cycle(); 316 317 let address = u16::from_le_bytes([cpu.state.t2, cpu.direct_page_msb()]); 318 bus.write(address, cpu.state.t1); 319 } 320 _ => invalid_cycle!(cpu), 321 } 322} 323 324pub(crate) fn mov_dp_imm<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 325 match cpu.state.cycle { 326 1 => { 327 cpu.state.t0 = fetch_operand(cpu, bus); 328 } 329 2 => { 330 cpu.state.t1 = fetch_operand(cpu, bus); 331 } 332 3 => { 333 // No-op read 334 let address = u16::from_le_bytes([cpu.state.t1, cpu.direct_page_msb()]); 335 bus.read(address); 336 } 337 4 => { 338 cpu.final_cycle(); 339 340 let address = u16::from_le_bytes([cpu.state.t1, cpu.direct_page_msb()]); 341 bus.write(address, cpu.state.t0); 342 } 343 _ => invalid_cycle!(cpu), 344 } 345} 346 347pub(crate) fn movw_ya_dp<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 348 match cpu.state.cycle { 349 1 => { 350 cpu.state.t0 = fetch_operand(cpu, bus); 351 } 352 2 => { 353 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 354 cpu.state.t1 = bus.read(address); 355 } 356 3 => { 357 bus.idle(); 358 } 359 4 => { 360 cpu.final_cycle(); 361 362 let address_lsb = cpu.state.t0.wrapping_add(1); 363 let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]); 364 let value_msb = bus.read(address); 365 366 cpu.registers.a = cpu.state.t1; 367 cpu.registers.y = value_msb; 368 369 cpu.registers.psw.zero = cpu.state.t1 == 0 && value_msb == 0; 370 cpu.registers.psw.negative = value_msb.sign_bit(); 371 } 372 _ => invalid_cycle!(cpu), 373 } 374} 375 376pub(crate) fn movw_dp_ya<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 377 match cpu.state.cycle { 378 1 => { 379 cpu.state.t0 = fetch_operand(cpu, bus); 380 } 381 2 => { 382 // No-op read 383 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 384 bus.read(address); 385 } 386 3 => { 387 let address = u16::from_le_bytes([cpu.state.t0, cpu.direct_page_msb()]); 388 bus.write(address, cpu.registers.a); 389 } 390 4 => { 391 cpu.final_cycle(); 392 393 let address_lsb = cpu.state.t0.wrapping_add(1); 394 let address = u16::from_le_bytes([address_lsb, cpu.direct_page_msb()]); 395 bus.write(address, cpu.registers.y); 396 } 397 _ => invalid_cycle!(cpu), 398 } 399} 400 401macro_rules! impl_push { 402 ($name:ident, $register:ident) => { 403 pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 404 match cpu.state.cycle { 405 1 => { 406 bus.idle(); 407 } 408 2 => { 409 bus.write(cpu.stack_pointer(), cpu.registers.$register.into()); 410 cpu.registers.sp = cpu.registers.sp.wrapping_sub(1); 411 } 412 3 => { 413 cpu.final_cycle(); 414 bus.idle(); 415 } 416 _ => invalid_cycle!(cpu), 417 } 418 } 419 }; 420} 421 422impl_push!(push_a, a); 423impl_push!(push_x, x); 424impl_push!(push_y, y); 425impl_push!(push_psw, psw); 426 427macro_rules! impl_pop { 428 ($name:ident, $register:ident) => { 429 pub(crate) fn $name<B: BusInterface>(cpu: &mut Spc700, bus: &mut B) { 430 match cpu.state.cycle { 431 1 | 2 => { 432 bus.idle(); 433 } 434 3 => { 435 cpu.final_cycle(); 436 437 cpu.registers.sp = cpu.registers.sp.wrapping_add(1); 438 cpu.registers.$register = bus.read(cpu.stack_pointer()).into(); 439 } 440 _ => invalid_cycle!(cpu), 441 } 442 } 443 }; 444} 445 446impl_pop!(pop_a, a); 447impl_pop!(pop_x, x); 448impl_pop!(pop_y, y); 449impl_pop!(pop_psw, psw);