load.rsannotatedload.rssource497 lines · 15.4 KB · raw
1use crate::core::instructions::{BlockMode, InstructionExecutor, sign_flag, zero_flag};
2use crate::core::{Flags, IndexRegister, Register8, Register16};
3use crate::debug::BusDebugExt;
4use crate::traits::BusInterface;
5use std::mem;
6
7impl<B: BusInterface> InstructionExecutor<'_, '_, B> {
8    pub(super) fn ld_r_r(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 {
9        let write_target =
10            super::parse_register_from_opcode(opcode >> 3, index).expect("invalid opcode");
11        let read_target = super::parse_register_from_opcode(opcode, index).expect("invalid opcode");
12
13        let value = read_target.read_from(&self.cpu.registers);
14        write_target.write_to(value, &mut self.cpu.registers);
15
16        4
17    }
18
19    pub(super) fn ld_r_immediate(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 {
20        let write_target =
21            super::parse_register_from_opcode(opcode >> 3, index).expect("invalid opcode)");
22        let value = self.fetch_operand();
23
24        write_target.write_to(value, &mut self.cpu.registers);
25
26        7
27    }
28
29    pub(super) fn ld_r_hl(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 {
30        let write_target =
31            super::parse_register_from_opcode(opcode >> 3, None).expect("invalid opcode");
32        let address = self.fetch_indirect_hl_address(index);
33        let value = self.bus.read_memory_debug(address, self.cpu);
34
35        write_target.write_to(value, &mut self.cpu.registers);
36
37        match index {
38            Some(_) => 15,
39            None => 7,
40        }
41    }
42
43    pub(super) fn ld_hl_r(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 {
44        let read_target = super::parse_register_from_opcode(opcode, None).expect("invalid opcode");
45        let value = read_target.read_from(&self.cpu.registers);
46        let address = self.fetch_indirect_hl_address(index);
47
48        self.bus.write_memory_debug(address, value, self.cpu);
49
50        match index {
51            Some(_) => 15,
52            None => 7,
53        }
54    }
55
56    pub(super) fn ld_hl_immediate(&mut self, index: Option<IndexRegister>) -> u32 {
57        let address = self.fetch_indirect_hl_address(index);
58        let value = self.fetch_operand();
59
60        self.bus.write_memory_debug(address, value, self.cpu);
61
62        match index {
63            Some(_) => 15,
64            None => 10,
65        }
66    }
67
68    pub(super) fn ld_a_indirect(&mut self, register: Register16) -> u32 {
69        let address = register.read_from(&self.cpu.registers);
70        let value = self.bus.read_memory_debug(address, self.cpu);
71
72        self.cpu.registers.a = value;
73
74        7
75    }
76
77    pub(super) fn ld_a_direct(&mut self) -> u32 {
78        let address = self.fetch_operand_u16();
79        let value = self.bus.read_memory_debug(address, self.cpu);
80
81        self.cpu.registers.a = value;
82
83        13
84    }
85
86    pub(super) fn ld_indirect_a(&mut self, register: Register16) -> u32 {
87        let address = register.read_from(&self.cpu.registers);
88
89        self.bus.write_memory_debug(address, self.cpu.registers.a, self.cpu);
90
91        7
92    }
93
94    pub(super) fn ld_direct_a(&mut self) -> u32 {
95        let address = self.fetch_operand_u16();
96        self.bus.write_memory_debug(address, self.cpu.registers.a, self.cpu);
97
98        13
99    }
100
101    // LD A, I and LD A, R
102    pub(super) fn ld_a_ir(&mut self, register: Register8) -> u32 {
103        debug_assert!(register == Register8::I || register == Register8::R);
104
105        let value = register.read_from(&self.cpu.registers);
106        self.cpu.registers.a = value;
107
108        self.cpu.registers.f = Flags {
109            sign: sign_flag(value),
110            zero: zero_flag(value),
111            half_carry: false,
112            overflow: self.cpu.registers.iff2,
113            subtract: false,
114            ..self.cpu.registers.f
115        };
116
117        9
118    }
119
120    // LD I, A and LD R, A
121    pub(super) fn ld_ir_a(&mut self, register: Register8) -> u32 {
122        debug_assert!(register == Register8::I || register == Register8::R);
123
124        register.write_to(self.cpu.registers.a, &mut self.cpu.registers);
125
126        9
127    }
128
129    pub(super) fn ld_dd_immediate(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 {
130        let register = super::parse_dd_register(opcode, index);
131        let value = self.fetch_operand_u16();
132
133        register.write_to(value, &mut self.cpu.registers);
134
135        10
136    }
137
138    pub(super) fn ld_hl_direct(&mut self, index: Option<IndexRegister>) -> u32 {
139        let address = self.fetch_operand_u16();
140        let value = self.read_memory_u16(address);
141
142        let register = index.map_or(Register16::HL, IndexRegister::into);
143        register.write_to(value, &mut self.cpu.registers);
144
145        16
146    }
147
148    pub(super) fn ld_dd_direct(&mut self, opcode: u8) -> u32 {
149        let register = super::parse_dd_register(opcode, None);
150        let address = self.fetch_operand_u16();
151        let value = self.read_memory_u16(address);
152
153        register.write_to(value, &mut self.cpu.registers);
154
155        20
156    }
157
158    pub(super) fn ld_direct_hl(&mut self, index: Option<IndexRegister>) -> u32 {
159        let register = index.map_or(Register16::HL, IndexRegister::into);
160        let value = register.read_from(&self.cpu.registers);
161        let address = self.fetch_operand_u16();
162
163        self.write_memory_u16(address, value);
164
165        16
166    }
167
168    pub(super) fn ld_direct_dd(&mut self, opcode: u8) -> u32 {
169        let register = super::parse_dd_register(opcode, None);
170        let value = register.read_from(&self.cpu.registers);
171        let address = self.fetch_operand_u16();
172
173        self.write_memory_u16(address, value);
174
175        20
176    }
177
178    pub(super) fn ld_sp_hl(&mut self, index: Option<IndexRegister>) -> u32 {
179        let register = index.map_or(Register16::HL, IndexRegister::into);
180        let value = register.read_from(&self.cpu.registers);
181
182        self.cpu.registers.sp = value;
183
184        6
185    }
186
187    pub(super) fn push_qq(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 {
188        let register = super::parse_qq_register(opcode, index);
189        let value = register.read_from(&self.cpu.registers);
190
191        self.push_stack(value);
192
193        11
194    }
195
196    pub(super) fn pop_qq(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 {
197        let register = super::parse_qq_register(opcode, index);
198        let value = self.pop_stack();
199
200        register.write_to(value, &mut self.cpu.registers);
201
202        10
203    }
204
205    pub(super) fn exchange_de_hl(&mut self) -> u32 {
206        mem::swap(&mut self.cpu.registers.d, &mut self.cpu.registers.h);
207        mem::swap(&mut self.cpu.registers.e, &mut self.cpu.registers.l);
208
209        4
210    }
211
212    pub(super) fn exchange_af(&mut self) -> u32 {
213        mem::swap(&mut self.cpu.registers.a, &mut self.cpu.registers.ap);
214        mem::swap(&mut self.cpu.registers.f, &mut self.cpu.registers.fp);
215
216        4
217    }
218
219    pub(super) fn exchange_bcdehl(&mut self) -> u32 {
220        mem::swap(&mut self.cpu.registers.b, &mut self.cpu.registers.bp);
221        mem::swap(&mut self.cpu.registers.c, &mut self.cpu.registers.cp);
222        mem::swap(&mut self.cpu.registers.d, &mut self.cpu.registers.dp);
223        mem::swap(&mut self.cpu.registers.e, &mut self.cpu.registers.ep);
224        mem::swap(&mut self.cpu.registers.h, &mut self.cpu.registers.hp);
225        mem::swap(&mut self.cpu.registers.l, &mut self.cpu.registers.lp);
226
227        4
228    }
229
230    pub(super) fn exchange_stack_hl(&mut self, index: Option<IndexRegister>) -> u32 {
231        let register = index.map_or(Register16::HL, IndexRegister::into);
232        let register_value = register.read_from(&self.cpu.registers);
233        let stack_value = self.pop_stack();
234
235        register.write_to(stack_value, &mut self.cpu.registers);
236        self.push_stack(register_value);
237
238        19
239    }
240
241    pub(super) fn block_transfer(&mut self, mode: BlockMode, repeat: bool) -> u32 {
242        let hl = Register16::HL.read_from(&self.cpu.registers);
243        let de = Register16::DE.read_from(&self.cpu.registers);
244
245        let value = self.bus.read_memory_debug(hl, self.cpu);
246        self.bus.write_memory_debug(de, value, self.cpu);
247
248        let bc = Register16::BC.read_from(&self.cpu.registers);
249        Register16::BC.write_to(bc.wrapping_sub(1), &mut self.cpu.registers);
250
251        Register16::HL.write_to(mode.apply(hl), &mut self.cpu.registers);
252        Register16::DE.write_to(mode.apply(de), &mut self.cpu.registers);
253
254        let should_repeat = repeat && bc != 1;
255        if should_repeat {
256            self.cpu.registers.pc = self.cpu.registers.pc.wrapping_sub(2);
257        }
258
259        self.cpu.registers.f =
260            Flags { half_carry: false, overflow: bc != 1, subtract: false, ..self.cpu.registers.f };
261
262        if should_repeat { 21 } else { 16 }
263    }
264}
265
266#[cfg(test)]
267mod tests {
268    use super::*;
269    use crate::Z80;
270    use crate::traits::InMemoryBus;
271
272    const REAL_REGISTERS: &[Register8] = &[
273        Register8::B,
274        Register8::C,
275        Register8::D,
276        Register8::E,
277        Register8::H,
278        Register8::L,
279        Register8::A,
280    ];
281
282    fn register_opcode_bits(register: Register8) -> u8 {
283        use Register8::*;
284
285        match register {
286            B => 0x00,
287            C => 0x01,
288            D => 0x02,
289            E => 0x03,
290            H => 0x04,
291            L => 0x05,
292            A => 0x07,
293            _ => panic!("unexpected register: {register:?}"),
294        }
295    }
296
297    #[test]
298    fn load_r_r() {
299        let mut cpu = Z80::new();
300        let mut bus = InMemoryBus::new();
301
302        for &r in REAL_REGISTERS {
303            for &rp in REAL_REGISTERS {
304                let opcode = 0x40 | (register_opcode_bits(r) << 3) | register_opcode_bits(rp);
305
306                r.write_to(rand::random(), &mut cpu.registers);
307                let value = rand::random();
308                rp.write_to(value, &mut cpu.registers);
309
310                InstructionExecutor::new(&mut cpu, &mut bus).ld_r_r(opcode, None);
311
312                assert_eq!(r.read_from(&cpu.registers), value, "LD {r:?}, {rp:?}");
313                assert_eq!(rp.read_from(&cpu.registers), value, "LD {r:?}, {rp:?}");
314            }
315        }
316    }
317
318    #[test]
319    fn load_r_hl() {
320        let mut cpu = Z80::new();
321        let mut bus = InMemoryBus::new();
322
323        for &r in REAL_REGISTERS {
324            let opcode = 0x46 | (register_opcode_bits(r) << 3);
325
326            let address = rand::random();
327            let value = rand::random();
328
329            bus.write_memory(address, value);
330            r.write_to(rand::random(), &mut cpu.registers);
331            Register16::HL.write_to(address, &mut cpu.registers);
332
333            InstructionExecutor::new(&mut cpu, &mut bus).ld_r_hl(opcode, None);
334
335            assert_eq!(r.read_from(&cpu.registers), value, "LD {r:?}, (HL)");
336            assert_eq!(bus.read_memory(address), value, "LD {r:?}, (HL)");
337        }
338    }
339
340    #[test]
341    fn load_r_immediate() {
342        let mut cpu = Z80::new();
343        let mut bus = InMemoryBus::new();
344
345        for &r in REAL_REGISTERS {
346            let opcode = 0x06 | (register_opcode_bits(r) << 3);
347
348            let value = rand::random();
349            r.write_to(rand::random(), &mut cpu.registers);
350
351            let pc = rand::random();
352            cpu.registers.pc = pc;
353            bus.write_memory(cpu.registers.pc, value);
354
355            InstructionExecutor::new(&mut cpu, &mut bus).ld_r_immediate(opcode, None);
356
357            assert_eq!(cpu.registers.pc, pc.wrapping_add(1), "LD {r:?}, n");
358            assert_eq!(r.read_from(&cpu.registers), value, "LD {r:?}, n");
359        }
360    }
361
362    #[test]
363    fn load_hl_r() {
364        let mut cpu = Z80::new();
365        let mut bus = InMemoryBus::new();
366
367        for &r in REAL_REGISTERS {
368            let opcode = 0x70 | register_opcode_bits(r);
369
370            let address = rand::random();
371            let value = rand::random();
372
373            Register16::HL.write_to(address, &mut cpu.registers);
374            r.write_to(value, &mut cpu.registers);
375            let address = Register16::HL.read_from(&cpu.registers);
376
377            bus.write_memory(address, rand::random());
378
379            InstructionExecutor::new(&mut cpu, &mut bus).ld_hl_r(opcode, None);
380
381            assert_eq!(r.read_from(&cpu.registers), value, "LD (HL), {r:?}");
382            assert_eq!(bus.read_memory(address), value, "LD (HL), {r:?}");
383        }
384    }
385
386    #[test]
387    fn load_hl_immediate() {
388        let mut cpu = Z80::new();
389        let mut bus = InMemoryBus::new();
390
391        let address = rand::random();
392        let value = rand::random();
393
394        Register16::HL.write_to(address, &mut cpu.registers);
395
396        bus.write_memory(address, rand::random());
397
398        let pc = rand::random();
399        cpu.registers.pc = pc;
400        bus.write_memory(pc, value);
401
402        InstructionExecutor::new(&mut cpu, &mut bus).ld_hl_immediate(None);
403
404        assert_eq!(cpu.registers.pc, pc.wrapping_add(1), "LD (HL), n");
405        assert_eq!(bus.read_memory(address), value, "LD (HL), n");
406    }
407
408    #[test]
409    fn load_a_indirect() {
410        let mut cpu = Z80::new();
411        let mut bus = InMemoryBus::new();
412
413        for r16 in [Register16::BC, Register16::DE] {
414            let address = rand::random();
415            let value = rand::random();
416
417            r16.write_to(address, &mut cpu.registers);
418            bus.write_memory(address, value);
419
420            cpu.registers.a = rand::random();
421
422            InstructionExecutor::new(&mut cpu, &mut bus).ld_a_indirect(r16);
423
424            assert_eq!(cpu.registers.a, value, "LD A, ({r16:?})");
425            assert_eq!(bus.read_memory(address), value, "LD A, ({r16:?})");
426        }
427    }
428
429    #[test]
430    fn load_a_direct() {
431        let mut cpu = Z80::new();
432        let mut bus = InMemoryBus::new();
433
434        let address: u16 = rand::random();
435        let value = rand::random();
436        let pc = rand::random();
437
438        let [address_lsb, address_msb] = address.to_le_bytes();
439
440        cpu.registers.pc = pc;
441        bus.write_memory(pc, address_lsb);
442        bus.write_memory(pc.wrapping_add(1), address_msb);
443        bus.write_memory(address, value);
444
445        cpu.registers.a = rand::random();
446
447        InstructionExecutor::new(&mut cpu, &mut bus).ld_a_direct();
448
449        assert_eq!(cpu.registers.pc, pc.wrapping_add(2), "LD A, (nn)");
450        assert_eq!(cpu.registers.a, value, "LD A, (nn)");
451    }
452
453    #[test]
454    fn load_indirect_a() {
455        let mut cpu = Z80::new();
456        let mut bus = InMemoryBus::new();
457
458        for r16 in [Register16::BC, Register16::DE] {
459            let address = rand::random();
460            let value = rand::random();
461
462            r16.write_to(address, &mut cpu.registers);
463            cpu.registers.a = value;
464
465            bus.write_memory(address, rand::random());
466
467            InstructionExecutor::new(&mut cpu, &mut bus).ld_indirect_a(r16);
468
469            assert_eq!(bus.read_memory(address), value, "LD ({r16:?}), A");
470            assert_eq!(cpu.registers.a, value, "LD ({r16:?}), A");
471        }
472    }
473
474    #[test]
475    fn load_direct_a() {
476        let mut cpu = Z80::new();
477        let mut bus = InMemoryBus::new();
478
479        let address: u16 = rand::random();
480        let [address_lsb, address_msb] = address.to_le_bytes();
481        let value = rand::random();
482        let pc = rand::random();
483
484        cpu.registers.pc = pc;
485        cpu.registers.a = value;
486        bus.write_memory(pc, address_lsb);
487        bus.write_memory(pc.wrapping_add(1), address_msb);
488
489        bus.write_memory(address, rand::random());
490
491        InstructionExecutor::new(&mut cpu, &mut bus).ld_direct_a();
492
493        assert_eq!(cpu.registers.pc, pc.wrapping_add(2), "LD (nn), A");
494        assert_eq!(bus.read_memory(address), value, "LD (nn), A");
495        assert_eq!(cpu.registers.a, value, "LD (nn), A");
496    }
497}