load.rsannotatedload.rssource449 lines · 13.6 KB · raw
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);