1use crate::core::instructions::InstructionExecutor; 2use crate::core::{IndexRegister, Register16, Registers}; 3use crate::traits::BusInterface; 4 5#[derive(Debug, Clone, Copy, PartialEq, Eq)] 6enum JumpCondition { 7 NonZero, 8 Zero, 9 NoCarry, 10 Carry, 11 ParityOdd, 12 ParityEven, 13 Positive, 14 Negative, 15} 16 17impl JumpCondition { 18 fn from_opcode(opcode: u8) -> Self { 19 match opcode & 0x38 { 20 0x00 => Self::NonZero, 21 0x08 => Self::Zero, 22 0x10 => Self::NoCarry, 23 0x18 => Self::Carry, 24 0x20 => Self::ParityOdd, 25 0x28 => Self::ParityEven, 26 0x30 => Self::Positive, 27 0x38 => Self::Negative, 28 _ => unreachable!("value & 0x38 is always one of the above 8 values"), 29 } 30 } 31 32 fn check(self, registers: &Registers) -> bool { 33 match self { 34 Self::NonZero => !registers.f.zero, 35 Self::Zero => registers.f.zero, 36 Self::NoCarry => !registers.f.carry, 37 Self::Carry => registers.f.carry, 38 Self::ParityOdd => !registers.f.overflow, 39 Self::ParityEven => registers.f.overflow, 40 Self::Positive => !registers.f.sign, 41 Self::Negative => registers.f.sign, 42 } 43 } 44} 45 46macro_rules! impl_jr_op { 47 ($name:ident) => { 48 pub(super) fn $name(&mut self) -> u32 { 49 let offset = self.fetch_operand() as i8; 50 51 self.cpu.registers.pc = (i32::from(self.cpu.registers.pc) + i32::from(offset)) as u16; 52 53 12 54 } 55 }; 56 ($name:ident, $flag:ident == $flag_value:expr) => { 57 pub(super) fn $name(&mut self) -> u32 { 58 let offset = self.fetch_operand() as i8; 59 60 if self.cpu.registers.f.$flag == $flag_value { 61 self.cpu.registers.pc = 62 (i32::from(self.cpu.registers.pc) + i32::from(offset)) as u16; 63 12 64 } else { 65 7 66 } 67 } 68 }; 69} 70 71impl<B: BusInterface> InstructionExecutor<'_, '_, B> { 72 impl_jr_op!(jr_e); 73 impl_jr_op!(jr_c_e, carry == true); 74 impl_jr_op!(jr_nc_e, carry == false); 75 impl_jr_op!(jr_z_e, zero == true); 76 impl_jr_op!(jr_nz_e, zero == false); 77 78 pub(super) fn jp_nn(&mut self) -> u32 { 79 let address = self.fetch_operand_u16(); 80 self.cpu.registers.pc = address; 81 82 10 83 } 84 85 pub(super) fn jp_cc_nn(&mut self, opcode: u8) -> u32 { 86 let condition = JumpCondition::from_opcode(opcode); 87 let address = self.fetch_operand_u16(); 88 89 if condition.check(&self.cpu.registers) { 90 self.cpu.registers.pc = address; 91 } 92 93 10 94 } 95 96 pub(super) fn jp_hl(&mut self, index: Option<IndexRegister>) -> u32 { 97 let register = index.map_or(Register16::HL, IndexRegister::into); 98 let address = register.read_from(&self.cpu.registers); 99 100 self.cpu.registers.pc = address; 101 102 4 103 } 104 105 pub(super) fn djnz_e(&mut self) -> u32 { 106 let offset = self.fetch_operand() as i8; 107 108 let b = self.cpu.registers.b; 109 self.cpu.registers.b = b.wrapping_sub(1); 110 111 if b != 1 { 112 self.cpu.registers.pc = (i32::from(self.cpu.registers.pc) + i32::from(offset)) as u16; 113 13 114 } else { 115 8 116 } 117 } 118 119 pub(super) fn call_nn(&mut self) -> u32 { 120 let address = self.fetch_operand_u16(); 121 122 self.push_stack(self.cpu.registers.pc); 123 self.cpu.registers.pc = address; 124 125 17 126 } 127 128 pub(super) fn call_cc_nn(&mut self, opcode: u8) -> u32 { 129 let condition = JumpCondition::from_opcode(opcode); 130 let address = self.fetch_operand_u16(); 131 132 if condition.check(&self.cpu.registers) { 133 self.push_stack(self.cpu.registers.pc); 134 self.cpu.registers.pc = address; 135 136 17 137 } else { 138 10 139 } 140 } 141 142 pub(super) fn ret(&mut self) -> u32 { 143 self.cpu.registers.pc = self.pop_stack(); 144 145 10 146 } 147 148 pub(super) fn ret_cc(&mut self, opcode: u8) -> u32 { 149 let condition = JumpCondition::from_opcode(opcode); 150 151 if condition.check(&self.cpu.registers) { 152 self.cpu.registers.pc = self.pop_stack(); 153 11 154 } else { 155 5 156 } 157 } 158 159 // On systems that don't use the special RETI hardware line, RETI and RETN behave identically 160 pub(super) fn reti_retn(&mut self) -> u32 { 161 self.cpu.registers.pc = self.pop_stack(); 162 self.cpu.registers.iff1 = self.cpu.registers.iff2; 163 164 14 165 } 166 167 pub(super) fn rst_p(&mut self, opcode: u8) -> u32 { 168 let address = opcode & 0x38; 169 170 self.push_stack(self.cpu.registers.pc); 171 self.cpu.registers.pc = address.into(); 172 173 11 174 } 175}