use crate::{Inner, Memory, Register, State}; #[allow(dead_code)] enum FLAGS { Z = 7, N = 6, H = 5, C = 4, } pub struct CPU { pub memory: Memory, pub state: State, } impl CPU { pub fn exec_next(&mut self) -> u8 { let opcode = self.next_opcode(); match opcode { 0x0 => { // noop } 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); }, 0x03 => unsafe { self.state.bc.as_u16 += 1 }, 0x04 => unsafe { self.state.bc.as_u8s.left += 1 }, 0x05 => unsafe { self.state.bc.as_u8s.left -= 1 }, 0x06 => self.state.bc.as_u8s.left = self.ld_immediate_byte(), 0x07 => panic!("RCLA instruction: 0x07"), 0x08 => unsafe { let address = self.ld_immediate_word().as_u16; let word = self.state.sp; self.store_word(address, word); }, 0x09 => unsafe { self.state.hl.as_u16 += self.state.bc.as_u16 }, 0x0A => unsafe { self.state.af.as_u8s.left = self.memory.get(self.state.bc.as_u16) }, 0x0B => unsafe { self.state.bc.as_u16 -= 0x1 }, 0x0C => unsafe { self.state.bc.as_u8s.right += 0x1 }, 0x0D => unsafe { self.state.bc.as_u8s.right -= 0x1 }, 0x0E => self.state.bc.as_u8s.right = self.ld_immediate_byte(), 0x0F => panic!("RRCA instruction: 0x0F"), 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); }, 0x13 => unsafe { self.state.de.as_u16 -= 0x1 }, 0x14 => unsafe { self.state.de.as_u8s.left += 0x1 }, 0x15 => unsafe { self.state.de.as_u8s.left -= 0x1 }, 0x16 => self.state.de.as_u8s.left = self.ld_immediate_byte(), 0x17 => panic!("RLA instruction: 0x17"), 0x18 => unsafe { self.state.pc.as_u16 += self.ld_immediate_byte() as u16 }, 0x19 => unsafe { self.state.hl.as_u16 += self.state.de.as_u16 }, 0x1A => unsafe { self.state.af.as_u8s.left = self.memory.get(self.state.de.as_u16) }, 0x1B => unsafe { self.state.de.as_u16 -= 1 }, 0x1C => unsafe { self.state.de.as_u8s.right += 1 }, 0x1D => unsafe { self.state.de.as_u8s.right -= 1 }, 0x1E => self.state.de.as_u8s.right = self.ld_immediate_byte(), 0x1F => panic!("RRA instruction: 0x1F"), 0x20 => { let jump_size = self.ld_immediate_byte(); if self.get_flag(FLAGS::Z) == 0 { unsafe { self.state.pc.as_u16 += jump_size as u16 } } } 0x21 => self.state.hl = self.ld_immediate_word(), 0x22 => unsafe { self.memory .set(self.state.hl.as_u16, self.state.af.as_u8s.left); self.state.hl.as_u16 += 1; }, 0x23 => unsafe { self.state.hl.as_u16 += 1 }, 0x24 => unsafe { self.state.hl.as_u8s.left += 1 }, 0x25 => unsafe { self.state.hl.as_u8s.left -= 1 }, 0x26 => self.state.hl.as_u8s.left = self.ld_immediate_byte(), 0x27 => panic!("DAA instruction: 0x27"), 0x28 => { let jump_size = self.ld_immediate_byte(); if self.get_flag(FLAGS::Z) == 1 { unsafe { self.state.pc.as_u16 += jump_size as u16 } } } 0x29 => unsafe { self.state.hl.as_u16 *= 2 }, 0x2A => unsafe { self.state.af.as_u8s.left = self.memory.get(self.state.hl.as_u16); self.state.hl.as_u16 += 1; }, 0x2B => unsafe { self.state.hl.as_u16 -= 1 }, 0x2C => unsafe { self.state.hl.as_u8s.right += 1 }, 0x2D => unsafe { self.state.hl.as_u8s.right -= 1 }, 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 { unsafe { self.state.pc.as_u16 += jump_size as u16 } } } 0x31 => self.state.sp = self.ld_immediate_word(), 0x32 => unsafe { self.memory .set(self.state.hl.as_u16, self.state.af.as_u8s.left); self.state.hl.as_u16 -= 1; }, 0x33 => unsafe { self.state.sp.as_u16 += 1 }, 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); }, 0x37 => panic!("SCF instruction: 0x37 - set carry flag"), 0x38 => { let jump_size = self.ld_immediate_byte(); if self.get_flag(FLAGS::C) == 1 { unsafe { self.state.pc.as_u16 += jump_size as u16 } } } 0x39 => unsafe { self.state.hl.as_u16 += self.state.sp.as_u16 }, 0x3A => unsafe { self.state.af.as_u8s.left = self.memory.get(self.state.hl.as_u16); self.state.hl.as_u16 -= 1; }, 0x3B => unsafe { self.state.sp.as_u16 -= 1 }, 0x3C => unsafe { self.state.af.as_u8s.left += 1 }, 0x3D => unsafe { self.state.af.as_u8s.left -= 1 }, 0x3E => self.state.af.as_u8s.left = self.ld_immediate_byte(), 0x3F => panic!("CCF instruction: 0x3F - flip carry flag"), 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; }; } 0x53 => { unsafe { self.state.de.as_u8s.left = self.state.de.as_u8s.right; }; } 0x66 => { unsafe { self.state.hl.as_u8s.left = self.memory.get(self.state.hl.as_u16); }; } 0xC3 => { self.state.pc = self.ld_immediate_word(); } 0xEA => { unsafe { let address = self.ld_immediate_word().as_u16; self.memory.set(address, self.state.af.as_u8s.left); }; } _ => { panic!("unimplemented opcode: {:#X}", opcode); } }; return opcode; } fn next_opcode(&mut self) -> u8 { unsafe { let opcode = self.memory.get(self.state.pc.as_u16); self.state.pc.as_u16 += 0x1; return opcode; }; } 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); }; } 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() } fn get_flag(&mut self, flag: FLAGS) -> u8 { unsafe { return self.state.af.as_u8s.right & (1 << flag as u8); } } }