2023-01-17 09:09:53 +11:00
|
|
|
use std::{
|
|
|
|
mem::transmute,
|
|
|
|
ops::{BitAnd, BitOr, BitXor},
|
|
|
|
};
|
2023-01-16 19:28:03 +11:00
|
|
|
|
2023-01-16 12:13:53 +11:00
|
|
|
use crate::{Inner, Memory, Register, State};
|
|
|
|
|
2023-01-16 14:23:43 +11:00
|
|
|
#[allow(dead_code)]
|
2023-01-16 14:23:06 +11:00
|
|
|
enum FLAGS {
|
|
|
|
Z = 7,
|
|
|
|
N = 6,
|
|
|
|
H = 5,
|
|
|
|
C = 4,
|
|
|
|
}
|
|
|
|
|
2023-01-16 12:13:53 +11:00
|
|
|
pub struct CPU {
|
|
|
|
pub memory: Memory,
|
|
|
|
pub state: State,
|
2023-01-18 12:45:56 +11:00
|
|
|
pub last_instruction: u8,
|
|
|
|
pub last_instruction_addr: u16,
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
impl CPU {
|
2023-01-17 09:09:53 +11:00
|
|
|
pub fn exec_next(&mut self) {
|
2023-01-18 12:45:56 +11:00
|
|
|
unsafe { self.last_instruction_addr = self.state.pc.as_u16 };
|
2023-01-16 12:13:53 +11:00
|
|
|
let opcode = self.next_opcode();
|
2023-01-18 12:45:56 +11:00
|
|
|
self.last_instruction = opcode;
|
|
|
|
|
2023-01-16 12:13:53 +11:00
|
|
|
match opcode {
|
|
|
|
0x0 => {
|
|
|
|
// noop
|
|
|
|
}
|
2023-01-16 14:23:06 +11:00
|
|
|
0x01 => self.state.bc = self.ld_immediate_word(),
|
|
|
|
0x02 => unsafe {
|
|
|
|
let address = self.state.bc.as_u16;
|
|
|
|
self.memory.set(address, self.state.af.as_u8s.left);
|
|
|
|
},
|
2023-01-18 12:45:56 +11:00
|
|
|
0x03 => unsafe { self.state.bc.as_u16 = self.add_u16s(self.state.bc.as_u16, 1) },
|
2023-01-16 19:28:03 +11:00
|
|
|
0x04 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.bc.as_u8s.left = self.add_u8s(self.state.bc.as_u8s.left, 1)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x05 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.bc.as_u8s.left = self.sub_u8s(self.state.bc.as_u8s.left, 1)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
2023-01-16 14:23:06 +11:00
|
|
|
0x06 => self.state.bc.as_u8s.left = self.ld_immediate_byte(),
|
2023-01-17 09:30:42 +11:00
|
|
|
0x07 => panic!("RCLA rotate instruction: 0x07"),
|
2023-01-16 14:23:06 +11:00
|
|
|
0x08 => unsafe {
|
|
|
|
let address = self.ld_immediate_word().as_u16;
|
|
|
|
let word = self.state.sp;
|
|
|
|
self.store_word(address, word);
|
|
|
|
},
|
2023-01-16 19:28:03 +11:00
|
|
|
0x09 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.hl.as_u16 = self.add_u16s(self.state.hl.as_u16, self.state.bc.as_u16)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
2023-01-16 14:23:06 +11:00
|
|
|
0x0A => unsafe { self.state.af.as_u8s.left = self.memory.get(self.state.bc.as_u16) },
|
2023-01-18 12:45:56 +11:00
|
|
|
0x0B => unsafe { self.state.bc.as_u16 = self.sub_u16s(self.state.bc.as_u16, 0x1) },
|
2023-01-16 19:28:03 +11:00
|
|
|
0x0C => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.bc.as_u8s.right = self.add_u8s(self.state.bc.as_u8s.right, 0x1)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x0D => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.bc.as_u8s.right = self.sub_u8s(self.state.bc.as_u8s.right, 0x1)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
2023-01-16 14:23:06 +11:00
|
|
|
0x0E => self.state.bc.as_u8s.right = self.ld_immediate_byte(),
|
2023-01-17 09:30:42 +11:00
|
|
|
0x0F => panic!("RRCA rotate instruction: 0x0F"),
|
2023-01-16 14:23:06 +11:00
|
|
|
0x10 => panic!("STOP instruction"),
|
|
|
|
0x11 => self.state.de = self.ld_immediate_word(),
|
|
|
|
0x12 => unsafe {
|
|
|
|
let address = self.state.de.as_u16;
|
|
|
|
let data = self.state.af.as_u8s.left;
|
|
|
|
self.memory.set(address, data);
|
|
|
|
},
|
2023-01-18 12:45:56 +11:00
|
|
|
0x13 => unsafe { self.state.de.as_u16 = self.sub_u16s(self.state.de.as_u16, 0x1) },
|
2023-01-16 19:28:03 +11:00
|
|
|
0x14 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.de.as_u8s.left = self.add_u8s(self.state.de.as_u8s.left, 0x1)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x15 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.de.as_u8s.left = self.sub_u8s(self.state.de.as_u8s.left, 0x1)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
2023-01-16 14:23:06 +11:00
|
|
|
0x16 => self.state.de.as_u8s.left = self.ld_immediate_byte(),
|
2023-01-17 09:30:42 +11:00
|
|
|
0x17 => panic!("RLA rotate instruction: 0x17"),
|
2023-01-16 19:28:03 +11:00
|
|
|
0x18 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let t = (as_signed(self.ld_immediate_byte()) as i16) as u16;
|
|
|
|
self.state.pc.as_u16 = self.add_u16s(self.state.pc.as_u16, t)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x19 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.hl.as_u16 = self.add_u16s(self.state.hl.as_u16, self.state.de.as_u16)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
2023-01-18 12:45:56 +11:00
|
|
|
0x1A => unsafe {
|
|
|
|
// println!("loading from {:#X}", self.state.de.as_u16);
|
|
|
|
self.state.af.as_u8s.left = self.memory.get(self.state.de.as_u16);
|
|
|
|
},
|
|
|
|
0x1B => unsafe { self.state.de.as_u16 = self.sub_u16s(self.state.de.as_u16, 1) },
|
2023-01-16 19:28:03 +11:00
|
|
|
0x1C => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.de.as_u8s.right = self.add_u8s(self.state.de.as_u8s.right, 1)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x1D => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.de.as_u8s.right = self.sub_u8s(self.state.de.as_u8s.right, 1)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
2023-01-16 14:23:06 +11:00
|
|
|
0x1E => self.state.de.as_u8s.right = self.ld_immediate_byte(),
|
2023-01-17 09:30:42 +11:00
|
|
|
0x1F => panic!("RRA rotate instruction: 0x1F"),
|
2023-01-16 14:23:06 +11:00
|
|
|
0x20 => {
|
|
|
|
let jump_size = self.ld_immediate_byte();
|
|
|
|
if self.get_flag(FLAGS::Z) == 0 {
|
2023-01-16 19:28:03 +11:00
|
|
|
unsafe {
|
2023-01-17 09:09:53 +11:00
|
|
|
self.state.pc.as_u16 = self
|
2023-01-18 12:45:56 +11:00
|
|
|
.add_u16s(self.state.pc.as_u16, (as_signed(jump_size) as i16) as u16)
|
2023-01-16 19:28:03 +11:00
|
|
|
}
|
2023-01-16 14:23:06 +11:00
|
|
|
}
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
2023-01-16 14:23:06 +11:00
|
|
|
0x21 => self.state.hl = self.ld_immediate_word(),
|
|
|
|
0x22 => unsafe {
|
|
|
|
self.memory
|
|
|
|
.set(self.state.hl.as_u16, self.state.af.as_u8s.left);
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.hl.as_u16 = self.add_u16s(self.state.hl.as_u16, 1);
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
2023-01-18 12:45:56 +11:00
|
|
|
0x23 => unsafe { self.state.hl.as_u16 = self.add_u16s(self.state.hl.as_u16, 1) },
|
2023-01-16 19:28:03 +11:00
|
|
|
0x24 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.hl.as_u8s.left = self.add_u8s(self.state.hl.as_u8s.left, 1)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x25 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.hl.as_u8s.left = self.sub_u8s(self.state.hl.as_u8s.left, 1)
|
2023-01-16 14:23:06 +11:00
|
|
|
},
|
2023-01-16 14:43:27 +11:00
|
|
|
0x26 => self.state.hl.as_u8s.left = self.ld_immediate_byte(),
|
2023-01-17 09:30:42 +11:00
|
|
|
0x27 => unsafe {
|
|
|
|
println!("Running DAA instruction (0x27) that I'm not too sure about...");
|
|
|
|
if self.get_flag(FLAGS::N) == 0 {
|
|
|
|
if self.get_flag(FLAGS::C) == 1 || self.state.af.as_u8s.left > 0x99 {
|
|
|
|
self.state.af.as_u8s.left += 0x60;
|
|
|
|
}
|
|
|
|
if self.get_flag(FLAGS::H) == 1 || (self.state.af.as_u8s.left & 0x0f) > 0x09 {
|
|
|
|
self.state.af.as_u8s.left += 0x6;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if self.get_flag(FLAGS::C) == 1 {
|
|
|
|
self.state.af.as_u8s.left -= 0x60;
|
|
|
|
}
|
|
|
|
if self.get_flag(FLAGS::H) == 1 {
|
|
|
|
self.state.af.as_u8s.left -= 0x6;
|
|
|
|
}
|
|
|
|
}
|
2023-01-18 12:45:56 +11:00
|
|
|
println!(
|
|
|
|
" ...this set register a to {:#X}...",
|
|
|
|
self.state.af.as_u8s.left
|
|
|
|
);
|
2023-01-17 09:30:42 +11:00
|
|
|
},
|
2023-01-16 14:43:27 +11:00
|
|
|
0x28 => {
|
|
|
|
let jump_size = self.ld_immediate_byte();
|
|
|
|
if self.get_flag(FLAGS::Z) == 1 {
|
2023-01-16 19:28:03 +11:00
|
|
|
unsafe {
|
2023-01-17 09:09:53 +11:00
|
|
|
self.state.pc.as_u16 = self
|
2023-01-18 12:45:56 +11:00
|
|
|
.add_u16s(self.state.pc.as_u16, (as_signed(jump_size) as i16) as u16)
|
2023-01-16 19:28:03 +11:00
|
|
|
}
|
2023-01-16 14:43:27 +11:00
|
|
|
}
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
2023-01-16 14:43:27 +11:00
|
|
|
0x29 => unsafe { self.state.hl.as_u16 *= 2 },
|
|
|
|
0x2A => unsafe {
|
|
|
|
self.state.af.as_u8s.left = self.memory.get(self.state.hl.as_u16);
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.hl.as_u16 = self.add_u16s(self.state.hl.as_u16, 1);
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
2023-01-18 12:45:56 +11:00
|
|
|
0x2B => unsafe { self.state.hl.as_u16 = self.sub_u16s(self.state.hl.as_u16, 1) },
|
2023-01-16 19:28:03 +11:00
|
|
|
0x2C => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.hl.as_u8s.right = self.add_u8s(self.state.hl.as_u8s.right, 1)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x2D => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.hl.as_u8s.right = self.sub_u8s(self.state.hl.as_u8s.right, 1)
|
2023-01-16 14:43:27 +11:00
|
|
|
},
|
|
|
|
0x2E => self.state.hl.as_u8s.right = self.ld_immediate_byte(),
|
|
|
|
0x2F => unsafe { self.state.af.as_u8s.left = !self.state.af.as_u8s.left },
|
|
|
|
0x30 => {
|
|
|
|
let jump_size = self.ld_immediate_byte();
|
|
|
|
if self.get_flag(FLAGS::C) == 0 {
|
2023-01-16 19:28:03 +11:00
|
|
|
unsafe {
|
2023-01-17 09:09:53 +11:00
|
|
|
self.state.pc.as_u16 = self
|
2023-01-18 12:45:56 +11:00
|
|
|
.add_u16s(self.state.pc.as_u16, (as_signed(jump_size) as i16) as u16)
|
2023-01-16 19:28:03 +11:00
|
|
|
}
|
2023-01-16 14:43:27 +11:00
|
|
|
}
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
2023-01-16 14:43:27 +11:00
|
|
|
0x31 => self.state.sp = self.ld_immediate_word(),
|
|
|
|
0x32 => unsafe {
|
|
|
|
self.memory
|
|
|
|
.set(self.state.hl.as_u16, self.state.af.as_u8s.left);
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.hl.as_u16 = self.sub_u16s(self.state.hl.as_u16, 1);
|
2023-01-16 14:43:27 +11:00
|
|
|
},
|
2023-01-18 12:45:56 +11:00
|
|
|
0x33 => unsafe { self.state.sp.as_u16 = self.add_u16s(self.state.sp.as_u16, 1) },
|
2023-01-16 14:43:27 +11:00
|
|
|
0x34 => unsafe {
|
|
|
|
let address = self.state.hl.as_u16;
|
|
|
|
let data = self.memory.get(address) + 1;
|
|
|
|
self.memory.set(address, data);
|
|
|
|
},
|
|
|
|
0x35 => unsafe {
|
|
|
|
let address = self.state.hl.as_u16;
|
|
|
|
let data = self.memory.get(address) - 1;
|
|
|
|
self.memory.set(address, data);
|
|
|
|
},
|
|
|
|
0x36 => unsafe {
|
|
|
|
let data = self.ld_immediate_byte();
|
|
|
|
self.memory.set(self.state.hl.as_u16, data);
|
|
|
|
},
|
2023-01-16 19:28:03 +11:00
|
|
|
0x37 => self.set_flag(FLAGS::C),
|
2023-01-16 14:43:27 +11:00
|
|
|
0x38 => {
|
|
|
|
let jump_size = self.ld_immediate_byte();
|
|
|
|
if self.get_flag(FLAGS::C) == 1 {
|
2023-01-16 19:28:03 +11:00
|
|
|
unsafe {
|
2023-01-17 09:09:53 +11:00
|
|
|
self.state.pc.as_u16 = self
|
2023-01-18 12:45:56 +11:00
|
|
|
.add_u16s(self.state.pc.as_u16, (as_signed(jump_size) as i16) as u16)
|
2023-01-16 19:28:03 +11:00
|
|
|
}
|
2023-01-16 14:43:27 +11:00
|
|
|
}
|
|
|
|
}
|
2023-01-16 19:28:03 +11:00
|
|
|
0x39 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.hl.as_u16 = self.add_u16s(self.state.hl.as_u16, self.state.sp.as_u16)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
2023-01-16 14:43:27 +11:00
|
|
|
0x3A => unsafe {
|
|
|
|
self.state.af.as_u8s.left = self.memory.get(self.state.hl.as_u16);
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.hl.as_u16 = self.sub_u16s(self.state.hl.as_u16, 1);
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
2023-01-18 12:45:56 +11:00
|
|
|
0x3B => unsafe { self.state.sp.as_u16 = self.sub_u16s(self.state.sp.as_u16, 1) },
|
2023-01-16 19:28:03 +11:00
|
|
|
0x3C => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left = self.add_u8s(self.state.af.as_u8s.left, 1)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x3D => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left = self.sub_u8s(self.state.af.as_u8s.left, 1)
|
2023-01-16 14:43:27 +11:00
|
|
|
},
|
|
|
|
0x3E => self.state.af.as_u8s.left = self.ld_immediate_byte(),
|
2023-01-16 19:28:03 +11:00
|
|
|
0x3F => self.toggle_flag(FLAGS::C),
|
|
|
|
0x40 => {}
|
|
|
|
0x41 => unsafe { self.state.bc.as_u8s.left = self.state.bc.as_u8s.right },
|
|
|
|
0x42 => unsafe { self.state.bc.as_u8s.left = self.state.de.as_u8s.left },
|
|
|
|
0x43 => unsafe { self.state.bc.as_u8s.left = self.state.de.as_u8s.right },
|
|
|
|
0x44 => unsafe { self.state.bc.as_u8s.left = self.state.hl.as_u8s.left },
|
|
|
|
0x45 => unsafe { self.state.bc.as_u8s.left = self.state.hl.as_u8s.right },
|
|
|
|
0x46 => unsafe { self.state.bc.as_u8s.left = self.memory.get(self.state.hl.as_u16) },
|
|
|
|
0x47 => unsafe { self.state.bc.as_u8s.left = self.state.af.as_u8s.left },
|
|
|
|
0x48 => unsafe { self.state.bc.as_u8s.right = self.state.bc.as_u8s.left },
|
|
|
|
0x49 => {}
|
|
|
|
0x4A => unsafe { self.state.bc.as_u8s.right = self.state.de.as_u8s.left },
|
|
|
|
0x4B => unsafe { self.state.bc.as_u8s.right = self.state.de.as_u8s.right },
|
|
|
|
0x4C => unsafe { self.state.bc.as_u8s.right = self.state.hl.as_u8s.left },
|
|
|
|
0x4D => unsafe { self.state.bc.as_u8s.right = self.state.hl.as_u8s.right },
|
|
|
|
0x4E => unsafe { self.state.bc.as_u8s.right = self.memory.get(self.state.hl.as_u16) },
|
|
|
|
0x4F => unsafe { self.state.bc.as_u8s.right = self.state.af.as_u8s.left },
|
|
|
|
0x50 => unsafe { self.state.de.as_u8s.left = self.state.bc.as_u8s.left },
|
|
|
|
0x51 => unsafe { self.state.de.as_u8s.left = self.state.bc.as_u8s.right },
|
|
|
|
0x52 => {}
|
|
|
|
0x53 => unsafe { self.state.de.as_u8s.left = self.state.de.as_u8s.right },
|
|
|
|
0x54 => unsafe { self.state.de.as_u8s.left = self.state.hl.as_u8s.left },
|
|
|
|
0x55 => unsafe { self.state.de.as_u8s.left = self.state.hl.as_u8s.right },
|
|
|
|
0x56 => unsafe { self.state.de.as_u8s.left = self.memory.get(self.state.hl.as_u16) },
|
|
|
|
0x57 => unsafe { self.state.de.as_u8s.left = self.state.af.as_u8s.left },
|
|
|
|
0x58 => unsafe { self.state.de.as_u8s.right = self.state.bc.as_u8s.left },
|
|
|
|
0x59 => unsafe { self.state.de.as_u8s.right = self.state.bc.as_u8s.right },
|
|
|
|
0x5A => unsafe { self.state.de.as_u8s.right = self.state.de.as_u8s.left },
|
|
|
|
0x5B => {}
|
|
|
|
0x5C => unsafe { self.state.de.as_u8s.right = self.state.hl.as_u8s.left },
|
|
|
|
0x5D => unsafe { self.state.de.as_u8s.right = self.state.hl.as_u8s.right },
|
|
|
|
0x5E => unsafe { self.state.de.as_u8s.right = self.memory.get(self.state.hl.as_u16) },
|
|
|
|
0x5F => unsafe { self.state.de.as_u8s.right = self.state.af.as_u8s.left },
|
|
|
|
0x60 => unsafe { self.state.hl.as_u8s.left = self.state.bc.as_u8s.left },
|
|
|
|
0x61 => unsafe { self.state.hl.as_u8s.left = self.state.bc.as_u8s.right },
|
|
|
|
0x62 => unsafe { self.state.hl.as_u8s.left = self.state.de.as_u8s.left },
|
|
|
|
0x63 => unsafe { self.state.hl.as_u8s.left = self.state.de.as_u8s.right },
|
|
|
|
0x64 => {}
|
|
|
|
0x65 => unsafe { self.state.hl.as_u8s.left = self.state.hl.as_u8s.right },
|
|
|
|
0x66 => unsafe { self.state.hl.as_u8s.left = self.memory.get(self.state.hl.as_u16) },
|
|
|
|
0x67 => unsafe { self.state.hl.as_u8s.left = self.state.af.as_u8s.left },
|
|
|
|
0x68 => unsafe { self.state.hl.as_u8s.right = self.state.bc.as_u8s.left },
|
|
|
|
0x69 => unsafe { self.state.hl.as_u8s.right = self.state.bc.as_u8s.right },
|
|
|
|
0x6A => unsafe { self.state.hl.as_u8s.right = self.state.de.as_u8s.left },
|
|
|
|
0x6B => unsafe { self.state.hl.as_u8s.right = self.state.de.as_u8s.right },
|
|
|
|
0x6C => unsafe { self.state.hl.as_u8s.right = self.state.hl.as_u8s.left },
|
|
|
|
0x6D => {}
|
|
|
|
0x6E => unsafe { self.state.hl.as_u8s.right = self.memory.get(self.state.hl.as_u16) },
|
|
|
|
0x6F => unsafe { self.state.hl.as_u8s.right = self.state.af.as_u8s.left },
|
|
|
|
0x70 => unsafe {
|
|
|
|
self.memory
|
|
|
|
.set(self.state.hl.as_u16, self.state.bc.as_u8s.left)
|
|
|
|
},
|
|
|
|
0x71 => unsafe {
|
|
|
|
self.memory
|
|
|
|
.set(self.state.hl.as_u16, self.state.bc.as_u8s.right)
|
|
|
|
},
|
|
|
|
0x72 => unsafe {
|
|
|
|
self.memory
|
|
|
|
.set(self.state.hl.as_u16, self.state.de.as_u8s.left)
|
|
|
|
},
|
|
|
|
0x73 => unsafe {
|
|
|
|
self.memory
|
|
|
|
.set(self.state.hl.as_u16, self.state.de.as_u8s.right)
|
|
|
|
},
|
|
|
|
0x74 => unsafe {
|
|
|
|
self.memory
|
|
|
|
.set(self.state.hl.as_u16, self.state.hl.as_u8s.left)
|
|
|
|
},
|
|
|
|
0x75 => unsafe {
|
|
|
|
self.memory
|
|
|
|
.set(self.state.hl.as_u16, self.state.hl.as_u8s.right)
|
|
|
|
},
|
2023-01-17 09:32:49 +11:00
|
|
|
0x76 => panic!("HALT until interrupt... instruction: 0x76"),
|
2023-01-16 19:28:03 +11:00
|
|
|
0x77 => unsafe {
|
|
|
|
self.memory
|
|
|
|
.set(self.state.hl.as_u16, self.state.af.as_u8s.left)
|
|
|
|
},
|
|
|
|
0x78 => unsafe { self.state.af.as_u8s.left = self.state.bc.as_u8s.left },
|
|
|
|
0x79 => unsafe { self.state.af.as_u8s.left = self.state.bc.as_u8s.right },
|
|
|
|
0x7A => unsafe { self.state.af.as_u8s.left = self.state.de.as_u8s.left },
|
|
|
|
0x7B => unsafe { self.state.af.as_u8s.left = self.state.de.as_u8s.right },
|
|
|
|
0x7C => unsafe { self.state.af.as_u8s.left = self.state.hl.as_u8s.left },
|
|
|
|
0x7D => unsafe { self.state.af.as_u8s.left = self.state.hl.as_u8s.right },
|
|
|
|
0x7E => unsafe { self.state.af.as_u8s.left = self.memory.get(self.state.hl.as_u16) },
|
|
|
|
0x7F => {}
|
|
|
|
0x80 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.bc.as_u8s.left)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x81 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.bc.as_u8s.right)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x82 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.de.as_u8s.left)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x83 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.de.as_u8s.right)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x84 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.hl.as_u8s.left)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x85 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.hl.as_u8s.right)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x86 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left = self.add_u8s(
|
|
|
|
self.state.af.as_u8s.left,
|
|
|
|
self.memory.get(self.state.hl.as_u16),
|
|
|
|
)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x87 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.af.as_u8s.left)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x88 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.bc.as_u8s.left + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x89 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.bc.as_u8s.right + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x8A => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.de.as_u8s.left + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x8B => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.de.as_u8s.right + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x8C => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.hl.as_u8s.left + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x8D => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.hl.as_u8s.right + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x8E => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left = self.add_u8s(
|
|
|
|
self.state.af.as_u8s.left,
|
|
|
|
self.memory.get(self.state.hl.as_u16) + f,
|
|
|
|
)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x8F => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.add_u8s(self.state.af.as_u8s.left, self.state.af.as_u8s.left + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x90 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.bc.as_u8s.left)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x91 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.bc.as_u8s.right)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x92 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.de.as_u8s.left)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x93 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.de.as_u8s.right)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x94 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.hl.as_u8s.left)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x95 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.hl.as_u8s.right)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x96 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left = self.sub_u8s(
|
|
|
|
self.state.af.as_u8s.left,
|
|
|
|
self.memory.get(self.state.hl.as_u16),
|
|
|
|
)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x97 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.af.as_u8s.left)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x98 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.bc.as_u8s.left + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x99 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.bc.as_u8s.right + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x9A => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.de.as_u8s.left + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x9B => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.de.as_u8s.right + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x9C => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.hl.as_u8s.left + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x9D => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.hl.as_u8s.right + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x9E => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left = self.sub_u8s(
|
|
|
|
self.state.af.as_u8s.left,
|
|
|
|
self.memory.get(self.state.hl.as_u16) + f,
|
|
|
|
)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0x9F => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let f = self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.sub_u8s(self.state.af.as_u8s.left, self.state.af.as_u8s.left + f)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0xA0 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitand(self.state.bc.as_u8s.left)
|
|
|
|
},
|
|
|
|
0xA1 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitand(self.state.bc.as_u8s.right)
|
|
|
|
},
|
|
|
|
0xA2 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitand(self.state.de.as_u8s.left)
|
|
|
|
},
|
|
|
|
0xA3 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitand(self.state.de.as_u8s.right)
|
|
|
|
},
|
|
|
|
0xA4 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitand(self.state.hl.as_u8s.left)
|
|
|
|
},
|
|
|
|
0xA5 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitand(self.state.hl.as_u8s.right)
|
|
|
|
},
|
|
|
|
0xA6 => unsafe {
|
|
|
|
self.state.af.as_u8s.left = self
|
|
|
|
.state
|
|
|
|
.af
|
|
|
|
.as_u8s
|
|
|
|
.left
|
|
|
|
.bitand(self.memory.get(self.state.hl.as_u16))
|
|
|
|
},
|
|
|
|
0xA7 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitand(self.state.af.as_u8s.left)
|
|
|
|
},
|
|
|
|
0xA8 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitxor(self.state.bc.as_u8s.left)
|
|
|
|
},
|
|
|
|
0xA9 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitxor(self.state.bc.as_u8s.right)
|
|
|
|
},
|
|
|
|
0xAA => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitxor(self.state.de.as_u8s.left)
|
|
|
|
},
|
|
|
|
0xAB => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitxor(self.state.de.as_u8s.right)
|
|
|
|
},
|
|
|
|
0xAC => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitxor(self.state.hl.as_u8s.left)
|
|
|
|
},
|
|
|
|
0xAD => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitxor(self.state.hl.as_u8s.right)
|
|
|
|
},
|
|
|
|
0xAE => unsafe {
|
|
|
|
self.state.af.as_u8s.left = self
|
|
|
|
.state
|
|
|
|
.af
|
|
|
|
.as_u8s
|
|
|
|
.left
|
|
|
|
.bitxor(self.memory.get(self.state.hl.as_u16))
|
|
|
|
},
|
|
|
|
0xAF => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitxor(self.state.af.as_u8s.left)
|
|
|
|
},
|
|
|
|
0xB0 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitor(self.state.bc.as_u8s.left)
|
|
|
|
},
|
|
|
|
0xB1 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitor(self.state.bc.as_u8s.right)
|
|
|
|
},
|
|
|
|
0xB2 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitor(self.state.de.as_u8s.left)
|
|
|
|
},
|
|
|
|
0xB3 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitor(self.state.de.as_u8s.right)
|
|
|
|
},
|
|
|
|
0xB4 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitor(self.state.hl.as_u8s.left)
|
|
|
|
},
|
|
|
|
0xB5 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitor(self.state.hl.as_u8s.right)
|
|
|
|
},
|
|
|
|
0xB6 => unsafe {
|
|
|
|
self.state.af.as_u8s.left = self
|
|
|
|
.state
|
|
|
|
.af
|
|
|
|
.as_u8s
|
|
|
|
.left
|
|
|
|
.bitor(self.memory.get(self.state.hl.as_u16))
|
|
|
|
},
|
|
|
|
0xB7 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitor(self.state.af.as_u8s.left)
|
|
|
|
},
|
|
|
|
0xB8 => unsafe {
|
|
|
|
if self.state.af.as_u8s.left == self.state.bc.as_u8s.left {
|
|
|
|
self.set_flag(FLAGS::Z);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
0xB9 => unsafe {
|
|
|
|
if self.state.af.as_u8s.left == self.state.bc.as_u8s.right {
|
|
|
|
self.set_flag(FLAGS::Z);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
0xBA => unsafe {
|
|
|
|
if self.state.af.as_u8s.left == self.state.de.as_u8s.left {
|
|
|
|
self.set_flag(FLAGS::Z);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
0xBB => unsafe {
|
|
|
|
if self.state.af.as_u8s.left == self.state.de.as_u8s.right {
|
|
|
|
self.set_flag(FLAGS::Z);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
0xBC => unsafe {
|
|
|
|
if self.state.af.as_u8s.left == self.state.hl.as_u8s.left {
|
|
|
|
self.set_flag(FLAGS::Z);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
0xBD => unsafe {
|
|
|
|
if self.state.af.as_u8s.left == self.state.hl.as_u8s.right {
|
|
|
|
self.set_flag(FLAGS::Z);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
0xBE => unsafe {
|
|
|
|
if self.state.af.as_u8s.left == self.memory.get(self.state.hl.as_u16) {
|
|
|
|
self.set_flag(FLAGS::Z);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
0xBF => self.set_flag(FLAGS::Z),
|
|
|
|
0xC0 => unsafe {
|
|
|
|
if self.get_flag(FLAGS::Z) == 0 {
|
|
|
|
let address = self.state.sp.as_u16;
|
|
|
|
self.state.pc.as_u8s.left = self.memory.get(address);
|
|
|
|
self.state.pc.as_u8s.right = self.memory.get(address + 1);
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.sp.as_u16 = self.add_u16s(self.state.sp.as_u16, 2);
|
2023-01-16 19:28:03 +11:00
|
|
|
}
|
|
|
|
},
|
|
|
|
0xC1 => unsafe {
|
|
|
|
let address = self.state.sp.as_u16;
|
|
|
|
self.state.bc.as_u8s.left = self.memory.get(address);
|
|
|
|
self.state.bc.as_u8s.right = self.memory.get(address + 1);
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.sp.as_u16 = self.add_u16s(self.state.sp.as_u16, 2);
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0xC2 => {
|
|
|
|
let word = self.ld_immediate_word();
|
|
|
|
if self.get_flag(FLAGS::Z) == 0 {
|
|
|
|
self.state.pc = word;
|
|
|
|
}
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
2023-01-16 19:28:03 +11:00
|
|
|
0xC3 => {
|
|
|
|
self.state.pc = self.ld_immediate_word();
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
2023-01-16 19:28:03 +11:00
|
|
|
0xC4 => {
|
|
|
|
let maybe_next = self.ld_immediate_word();
|
|
|
|
if self.get_flag(FLAGS::Z) == 0 {
|
|
|
|
self.push(self.state.pc);
|
|
|
|
self.state.pc = maybe_next;
|
|
|
|
}
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
2023-01-16 19:28:03 +11:00
|
|
|
0xC5 => self.push(self.state.bc),
|
|
|
|
0xC6 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let t = self.ld_immediate_byte();
|
|
|
|
self.state.af.as_u8s.left = self.add_u8s(self.state.af.as_u8s.left, t)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0xC7 => self.rst(0x00),
|
|
|
|
0xC8 => {
|
|
|
|
if self.get_flag(FLAGS::Z) == 1 {
|
|
|
|
self.state.pc = self.pop_word()
|
|
|
|
}
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
2023-01-16 19:28:03 +11:00
|
|
|
0xC9 => self.state.pc = self.pop_word(),
|
|
|
|
0xCA => {
|
|
|
|
let maybe_next = self.ld_immediate_word();
|
|
|
|
if self.get_flag(FLAGS::Z) == 1 {
|
|
|
|
self.state.pc = maybe_next;
|
|
|
|
}
|
|
|
|
}
|
2023-01-17 09:09:53 +11:00
|
|
|
0xCB => {
|
|
|
|
let subop = self.ld_immediate_byte();
|
|
|
|
self.cb_subop(subop);
|
|
|
|
}
|
2023-01-16 19:28:03 +11:00
|
|
|
0xCC => {
|
|
|
|
let maybe_next = self.ld_immediate_word();
|
|
|
|
if self.get_flag(FLAGS::Z) == 1 {
|
|
|
|
self.push(self.state.pc);
|
|
|
|
self.state.pc = maybe_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
0xCD => {
|
|
|
|
self.push(self.state.pc);
|
2023-01-16 12:13:53 +11:00
|
|
|
self.state.pc = self.ld_immediate_word();
|
|
|
|
}
|
2023-01-16 19:28:03 +11:00
|
|
|
0xCE => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let t = self.ld_immediate_byte() + self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left = self.add_u8s(self.state.af.as_u8s.left, t)
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
0xCF => self.rst(0x08),
|
2023-01-17 09:09:53 +11:00
|
|
|
0xD0 => unsafe {
|
|
|
|
if self.get_flag(FLAGS::C) == 0 {
|
|
|
|
let address = self.state.sp.as_u16;
|
|
|
|
self.state.pc.as_u8s.left = self.memory.get(address);
|
|
|
|
self.state.pc.as_u8s.right = self.memory.get(address + 1);
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.sp.as_u16 = self.add_u16s(self.state.sp.as_u16, 2);
|
2023-01-17 09:09:53 +11:00
|
|
|
}
|
|
|
|
},
|
|
|
|
0xD1 => unsafe {
|
|
|
|
let address = self.state.sp.as_u16;
|
|
|
|
self.state.de.as_u8s.left = self.memory.get(address);
|
|
|
|
self.state.de.as_u8s.right = self.memory.get(address + 1);
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.sp.as_u16 = self.add_u16s(self.state.sp.as_u16, 2);
|
2023-01-17 09:09:53 +11:00
|
|
|
},
|
|
|
|
0xD2 => {
|
|
|
|
let word = self.ld_immediate_word();
|
|
|
|
if self.get_flag(FLAGS::C) == 0 {
|
|
|
|
self.state.pc = word;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
0xD3 => undefined(0xD3),
|
|
|
|
0xD4 => {
|
|
|
|
let maybe_next = self.ld_immediate_word();
|
|
|
|
if self.get_flag(FLAGS::C) == 0 {
|
|
|
|
self.push(self.state.pc);
|
|
|
|
self.state.pc = maybe_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
0xD5 => self.push(self.state.de),
|
|
|
|
0xD6 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let t = self.ld_immediate_byte();
|
|
|
|
self.state.af.as_u8s.left = self.sub_u8s(self.state.af.as_u8s.left, t)
|
2023-01-17 09:09:53 +11:00
|
|
|
},
|
|
|
|
0xD7 => self.rst(0x10),
|
|
|
|
0xD8 => {
|
|
|
|
if self.get_flag(FLAGS::C) == 1 {
|
|
|
|
self.state.pc = self.pop_word()
|
|
|
|
}
|
|
|
|
}
|
2023-01-17 09:30:42 +11:00
|
|
|
0xD9 => {
|
|
|
|
self.state.pc = self.pop_word();
|
2023-01-17 09:45:49 +11:00
|
|
|
self.memory.ime = true;
|
2023-01-17 09:30:42 +11:00
|
|
|
}
|
2023-01-17 09:09:53 +11:00
|
|
|
0xDA => {
|
|
|
|
let maybe_next = self.ld_immediate_word();
|
|
|
|
if self.get_flag(FLAGS::C) == 1 {
|
|
|
|
self.state.pc = maybe_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
0xDB => undefined(0xDB),
|
|
|
|
0xDC => {
|
|
|
|
let maybe_next = self.ld_immediate_word();
|
|
|
|
if self.get_flag(FLAGS::C) == 1 {
|
|
|
|
self.push(self.state.pc);
|
|
|
|
self.state.pc = maybe_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
0xDD => undefined(0xDE),
|
|
|
|
0xDE => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let t = self.ld_immediate_byte() + self.get_flag(FLAGS::C);
|
|
|
|
self.state.af.as_u8s.left = self.sub_u8s(self.state.af.as_u8s.left, t)
|
2023-01-17 09:09:53 +11:00
|
|
|
},
|
|
|
|
0xDF => self.rst(0x18),
|
|
|
|
0xE0 => {
|
|
|
|
unsafe {
|
|
|
|
let address = Register {
|
|
|
|
as_u8s: Inner {
|
|
|
|
left: self.ld_immediate_byte(),
|
|
|
|
right: 0xFF,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.memory.set(address.as_u16, self.state.af.as_u8s.left);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
0xE1 => unsafe {
|
|
|
|
let address = self.state.sp.as_u16;
|
|
|
|
self.state.hl.as_u8s.left = self.memory.get(address);
|
|
|
|
self.state.hl.as_u8s.right = self.memory.get(address + 1);
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.sp.as_u16 = self.add_u16s(self.state.sp.as_u16, 2);
|
2023-01-17 09:09:53 +11:00
|
|
|
},
|
|
|
|
0xE2 => {
|
|
|
|
unsafe {
|
|
|
|
let address = Register {
|
|
|
|
as_u8s: Inner {
|
|
|
|
left: self.state.bc.as_u8s.right,
|
|
|
|
right: 0xFF,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.memory.set(address.as_u16, self.state.af.as_u8s.left);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
0xE3 => undefined(0xE3),
|
|
|
|
0xE4 => undefined(0xE4),
|
|
|
|
0xE5 => self.push(self.state.hl),
|
|
|
|
0xE6 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitand(self.ld_immediate_byte())
|
|
|
|
},
|
|
|
|
0xE7 => self.rst(0x20),
|
|
|
|
0xE8 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let t = (as_signed(self.ld_immediate_byte()) as i16) as u16;
|
|
|
|
self.state.sp.as_u16 = self.add_u16s(self.state.sp.as_u16, t);
|
2023-01-17 09:09:53 +11:00
|
|
|
},
|
|
|
|
0xE9 => self.state.pc = self.state.hl,
|
|
|
|
0xEA => unsafe {
|
|
|
|
let address = self.ld_immediate_word().as_u16;
|
|
|
|
self.memory.set(address, self.state.af.as_u8s.left);
|
|
|
|
},
|
|
|
|
0xEB => undefined(0xEB),
|
|
|
|
0xEC => undefined(0xEC),
|
|
|
|
0xED => undefined(0xED),
|
|
|
|
0xEE => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitxor(self.ld_immediate_byte())
|
|
|
|
},
|
|
|
|
0xEF => self.rst(0x28),
|
|
|
|
0xF0 => {
|
2023-01-16 12:13:53 +11:00
|
|
|
unsafe {
|
2023-01-17 09:09:53 +11:00
|
|
|
let address = Register {
|
|
|
|
as_u8s: Inner {
|
|
|
|
left: self.ld_immediate_byte(),
|
|
|
|
right: 0xFF,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.state.af.as_u8s.left = self.memory.get(address.as_u16);
|
2023-01-16 12:13:53 +11:00
|
|
|
};
|
|
|
|
}
|
2023-01-17 09:09:53 +11:00
|
|
|
0xF1 => unsafe {
|
|
|
|
let address = self.state.sp.as_u16;
|
|
|
|
self.state.af.as_u8s.left = self.memory.get(address);
|
|
|
|
self.state.af.as_u8s.right = self.memory.get(address + 1);
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.sp.as_u16 = self.add_u16s(self.state.sp.as_u16, 2);
|
2023-01-17 09:09:53 +11:00
|
|
|
},
|
|
|
|
0xF2 => {
|
|
|
|
unsafe {
|
|
|
|
let address = Register {
|
|
|
|
as_u8s: Inner {
|
|
|
|
left: self.state.bc.as_u8s.right,
|
|
|
|
right: 0xFF,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
self.state.af.as_u8s.left = self.memory.get(address.as_u16);
|
|
|
|
};
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
2023-01-17 09:45:49 +11:00
|
|
|
0xF3 => self.memory.ime = false,
|
2023-01-17 09:09:53 +11:00
|
|
|
0xF4 => undefined(0xF4),
|
|
|
|
0xF5 => self.push(self.state.af),
|
|
|
|
0xF6 => unsafe {
|
|
|
|
self.state.af.as_u8s.left =
|
|
|
|
self.state.af.as_u8s.left.bitor(self.ld_immediate_byte())
|
|
|
|
},
|
|
|
|
0xF7 => self.rst(0x30),
|
|
|
|
0xF8 => unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
let t = (as_signed(self.ld_immediate_byte()) as i16) as u16;
|
|
|
|
self.state.hl.as_u16 = self.add_u16s(self.state.sp.as_u16, t)
|
2023-01-17 09:09:53 +11:00
|
|
|
},
|
|
|
|
0xF9 => self.state.sp = self.state.hl,
|
|
|
|
0xFA => unsafe {
|
|
|
|
let address = self.ld_immediate_word().as_u16;
|
|
|
|
self.state.af.as_u8s.left = self.memory.get(address);
|
|
|
|
},
|
2023-01-17 09:45:49 +11:00
|
|
|
0xFB => self.memory.ime = true,
|
2023-01-17 09:09:53 +11:00
|
|
|
0xFC => undefined(0xFC),
|
|
|
|
0xFD => undefined(0xFD),
|
|
|
|
0xFE => unsafe {
|
|
|
|
if self.ld_immediate_byte() == self.state.af.as_u8s.left {
|
|
|
|
self.set_flag(FLAGS::Z)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
0xFF => self.rst(0x38),
|
2023-01-16 12:13:53 +11:00
|
|
|
};
|
2023-01-17 09:09:53 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
fn cb_subop(&mut self, subop: u8) {
|
2023-01-18 12:45:56 +11:00
|
|
|
match subop {
|
|
|
|
0x7C => unsafe {
|
|
|
|
self.set_or_clear_flag(FLAGS::Z, !get_bit(self.state.hl.as_u8s.left, 7))
|
|
|
|
},
|
|
|
|
_ => panic!("Unimplemented sub-opcode: {:#X}", subop),
|
|
|
|
}
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
fn next_opcode(&mut self) -> u8 {
|
|
|
|
unsafe {
|
|
|
|
let opcode = self.memory.get(self.state.pc.as_u16);
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.pc.as_u16 += 0x1;
|
2023-01-16 12:13:53 +11:00
|
|
|
return opcode;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-01-16 19:28:03 +11:00
|
|
|
fn rst(&mut self, address: u16) {
|
|
|
|
self.push(self.state.pc);
|
|
|
|
self.state.pc.as_u8s.left = 0x0;
|
|
|
|
self.state.pc.as_u8s.right = self.memory.get(address);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn push(&mut self, register: Register) {
|
|
|
|
unsafe {
|
|
|
|
let address = self.state.sp.as_u16;
|
|
|
|
self.memory.set(address - 1, register.as_u8s.right);
|
|
|
|
self.memory.set(address - 2, register.as_u8s.left);
|
|
|
|
self.state.sp.as_u16 = address - 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pop_word(&mut self) -> Register {
|
|
|
|
unsafe {
|
|
|
|
let address = self.state.sp.as_u16;
|
2023-01-18 12:45:56 +11:00
|
|
|
self.state.sp.as_u16 += 0x2;
|
2023-01-16 19:28:03 +11:00
|
|
|
Register {
|
|
|
|
as_u8s: Inner {
|
|
|
|
left: self.memory.get(address),
|
|
|
|
right: self.memory.get(address + 1),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-16 14:23:06 +11:00
|
|
|
fn store_word(&mut self, address: u16, word: Register) {
|
|
|
|
unsafe {
|
|
|
|
self.memory.set(address, word.as_u8s.left);
|
|
|
|
self.memory.set(address + 1, word.as_u8s.right);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-01-16 12:13:53 +11:00
|
|
|
fn ld_immediate_word(&mut self) -> Register {
|
|
|
|
Register {
|
|
|
|
as_u8s: Inner {
|
|
|
|
left: self.next_opcode(),
|
|
|
|
right: self.next_opcode(),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn ld_immediate_byte(&mut self) -> u8 {
|
|
|
|
self.next_opcode()
|
|
|
|
}
|
2023-01-16 14:23:06 +11:00
|
|
|
|
|
|
|
fn get_flag(&mut self, flag: FLAGS) -> u8 {
|
|
|
|
unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
if get_bit(self.state.af.as_u8s.right, flag as u8) {
|
|
|
|
0x1
|
|
|
|
} else {
|
|
|
|
0x0
|
|
|
|
}
|
2023-01-16 14:23:06 +11:00
|
|
|
}
|
|
|
|
}
|
2023-01-16 19:28:03 +11:00
|
|
|
|
|
|
|
fn set_flag(&mut self, flag: FLAGS) {
|
|
|
|
unsafe {
|
|
|
|
self.state.af.as_u8s.right = self.state.af.as_u8s.right.bitor(1 << flag as u8);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clear_flag(&mut self, flag: FLAGS) {
|
|
|
|
unsafe {
|
|
|
|
self.state.af.as_u8s.right = self.state.af.as_u8s.right.bitand(!(1 << flag as u8));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
fn toggle_flag(&mut self, flag: FLAGS) {
|
|
|
|
unsafe {
|
|
|
|
self.state.af.as_u8s.right = self.state.af.as_u8s.right.bitxor(1 << flag as u8);
|
|
|
|
};
|
|
|
|
}
|
2023-01-18 12:45:56 +11:00
|
|
|
|
|
|
|
fn set_or_clear_flag(&mut self, flag: FLAGS, state: bool) {
|
|
|
|
if state {
|
|
|
|
self.set_flag(flag)
|
|
|
|
} else {
|
|
|
|
self.clear_flag(flag)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_u8s(&mut self, first: u8, second: u8) -> u8 {
|
|
|
|
let (result, carry) = first.overflowing_add(second);
|
|
|
|
self.clear_flag(FLAGS::N);
|
|
|
|
self.set_or_clear_flag(FLAGS::C, carry);
|
|
|
|
self.set_or_clear_flag(FLAGS::Z, !carry && result == 0x0);
|
|
|
|
self.set_or_clear_flag(FLAGS::H, (first & 0xF) + (second & 0xF) > 0xF);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_u16s(&mut self, first: u16, second: u16) -> u16 {
|
|
|
|
let (result, carry) = first.overflowing_add(second);
|
|
|
|
self.clear_flag(FLAGS::N);
|
|
|
|
self.set_or_clear_flag(FLAGS::C, carry);
|
|
|
|
self.set_or_clear_flag(FLAGS::Z, !carry && result == 0x0);
|
|
|
|
self.set_or_clear_flag(FLAGS::H, (first & 0xF) + (second & 0xF) > 0xF);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sub_u8s(&mut self, first: u8, second: u8) -> u8 {
|
|
|
|
let (result, carry) = first.overflowing_sub(second);
|
|
|
|
self.set_flag(FLAGS::N);
|
|
|
|
self.set_or_clear_flag(FLAGS::C, carry);
|
|
|
|
self.set_or_clear_flag(FLAGS::Z, !carry && result == 0x0);
|
|
|
|
self.set_or_clear_flag(
|
|
|
|
FLAGS::H,
|
|
|
|
((first & 0xF) as i32 - (second & 0xF) as i32) < 0xF,
|
|
|
|
);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sub_u16s(&mut self, first: u16, second: u16) -> u16 {
|
|
|
|
let (result, carry) = first.overflowing_sub(second);
|
|
|
|
self.set_flag(FLAGS::N);
|
|
|
|
self.set_or_clear_flag(FLAGS::C, carry);
|
|
|
|
self.set_or_clear_flag(FLAGS::Z, !carry && result == 0x0);
|
|
|
|
self.set_or_clear_flag(
|
|
|
|
FLAGS::H,
|
|
|
|
((first & 0xF) as i32 - (second & 0xF) as i32) < 0xF,
|
|
|
|
);
|
|
|
|
return result;
|
|
|
|
}
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
2023-01-17 09:09:53 +11:00
|
|
|
|
|
|
|
fn undefined(opcode: u8) {
|
|
|
|
println!("Undefined behaviour: opcode {:#X}", opcode);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_signed(unsigned: u8) -> i8 {
|
|
|
|
unsafe {
|
|
|
|
return transmute(unsigned);
|
|
|
|
}
|
|
|
|
}
|
2023-01-18 12:45:56 +11:00
|
|
|
|
|
|
|
fn get_bit(byte: u8, flag: u8) -> bool {
|
|
|
|
let mask = 1 << flag;
|
|
|
|
let got = byte & mask;
|
|
|
|
return got > 0x0;
|
|
|
|
}
|