all opcodes implemented-ish
This commit is contained in:
parent
e40bf4f786
commit
e6cbedc59b
1 changed files with 222 additions and 16 deletions
238
src/processor.rs
238
src/processor.rs
|
@ -1,4 +1,7 @@
|
|||
use std::ops::{BitAnd, BitOr, BitXor};
|
||||
use std::{
|
||||
mem::transmute,
|
||||
ops::{BitAnd, BitOr, BitXor},
|
||||
};
|
||||
|
||||
use crate::{Inner, Memory, Register, State};
|
||||
|
||||
|
@ -16,9 +19,9 @@ pub struct CPU {
|
|||
}
|
||||
|
||||
impl CPU {
|
||||
pub fn exec_next(&mut self) -> u8 {
|
||||
pub fn exec_next(&mut self) {
|
||||
let opcode = self.next_opcode();
|
||||
unsafe { println!("exec {:#4X} from {:#4X}", opcode, self.state.pc.as_u16 - 1) };
|
||||
// unsafe { println!("exec {:#4X} from {:#4X}", opcode, self.state.pc.as_u16 - 1) };
|
||||
match opcode {
|
||||
0x0 => {
|
||||
// noop
|
||||
|
@ -76,7 +79,7 @@ impl CPU {
|
|||
.state
|
||||
.pc
|
||||
.as_u16
|
||||
.wrapping_add(self.ld_immediate_byte() as u16)
|
||||
.wrapping_add((as_signed(self.ld_immediate_byte()) as i16) as u16)
|
||||
},
|
||||
0x19 => unsafe {
|
||||
self.state.hl.as_u16 = self.state.hl.as_u16.wrapping_add(self.state.de.as_u16)
|
||||
|
@ -95,7 +98,11 @@ impl CPU {
|
|||
let jump_size = self.ld_immediate_byte();
|
||||
if self.get_flag(FLAGS::Z) == 0 {
|
||||
unsafe {
|
||||
self.state.pc.as_u16 = self.state.pc.as_u16.wrapping_add(jump_size as u16)
|
||||
self.state.pc.as_u16 = self
|
||||
.state
|
||||
.pc
|
||||
.as_u16
|
||||
.wrapping_add((as_signed(jump_size) as i16) as u16)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +125,11 @@ impl CPU {
|
|||
let jump_size = self.ld_immediate_byte();
|
||||
if self.get_flag(FLAGS::Z) == 1 {
|
||||
unsafe {
|
||||
self.state.pc.as_u16 = self.state.pc.as_u16.wrapping_add(jump_size as u16)
|
||||
self.state.pc.as_u16 = self
|
||||
.state
|
||||
.pc
|
||||
.as_u16
|
||||
.wrapping_add((as_signed(jump_size) as i16) as u16)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +151,11 @@ impl CPU {
|
|||
let jump_size = self.ld_immediate_byte();
|
||||
if self.get_flag(FLAGS::C) == 0 {
|
||||
unsafe {
|
||||
self.state.pc.as_u16 = self.state.pc.as_u16.wrapping_add(jump_size as u16)
|
||||
self.state.pc.as_u16 = self
|
||||
.state
|
||||
.pc
|
||||
.as_u16
|
||||
.wrapping_add((as_signed(jump_size) as i16) as u16)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +185,11 @@ impl CPU {
|
|||
let jump_size = self.ld_immediate_byte();
|
||||
if self.get_flag(FLAGS::C) == 1 {
|
||||
unsafe {
|
||||
self.state.pc.as_u16 = self.state.pc.as_u16.wrapping_add(jump_size as u16)
|
||||
self.state.pc.as_u16 = self
|
||||
.state
|
||||
.pc
|
||||
.as_u16
|
||||
.wrapping_add((as_signed(jump_size) as i16) as u16)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -723,7 +742,10 @@ impl CPU {
|
|||
self.state.pc = maybe_next;
|
||||
}
|
||||
}
|
||||
0xCB => println!("Undefined behaviour: opcode CB"),
|
||||
0xCB => {
|
||||
let subop = self.ld_immediate_byte();
|
||||
self.cb_subop(subop);
|
||||
}
|
||||
0xCC => {
|
||||
let maybe_next = self.ld_immediate_word();
|
||||
if self.get_flag(FLAGS::Z) == 1 {
|
||||
|
@ -744,18 +766,192 @@ impl CPU {
|
|||
.wrapping_add(self.ld_immediate_byte() + self.get_flag(FLAGS::C))
|
||||
},
|
||||
0xCF => self.rst(0x08),
|
||||
|
||||
0xEA => {
|
||||
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);
|
||||
self.state.sp.as_u16 = self.state.sp.as_u16.wrapping_add(2);
|
||||
}
|
||||
},
|
||||
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);
|
||||
self.state.sp.as_u16 = self.state.sp.as_u16.wrapping_add(2);
|
||||
},
|
||||
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 {
|
||||
self.state.af.as_u8s.left = self
|
||||
.state
|
||||
.af
|
||||
.as_u8s
|
||||
.left
|
||||
.wrapping_sub(self.ld_immediate_byte())
|
||||
},
|
||||
0xD7 => self.rst(0x10),
|
||||
0xD8 => {
|
||||
if self.get_flag(FLAGS::C) == 1 {
|
||||
self.state.pc = self.pop_word()
|
||||
}
|
||||
}
|
||||
0xD9 => panic!("RETI: 0xD9"),
|
||||
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 {
|
||||
self.state.af.as_u8s.left = self
|
||||
.state
|
||||
.af
|
||||
.as_u8s
|
||||
.left
|
||||
.wrapping_sub(self.ld_immediate_byte() + self.get_flag(FLAGS::C))
|
||||
},
|
||||
0xDF => self.rst(0x18),
|
||||
0xE0 => {
|
||||
unsafe {
|
||||
let address = self.ld_immediate_word().as_u16;
|
||||
self.memory.set(address, self.state.af.as_u8s.left);
|
||||
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);
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
panic!("unimplemented opcode: {:#X}", opcode);
|
||||
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);
|
||||
self.state.sp.as_u16 = self.state.sp.as_u16.wrapping_add(2);
|
||||
},
|
||||
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 {
|
||||
self.state.sp.as_u16 = self
|
||||
.state
|
||||
.sp
|
||||
.as_u16
|
||||
.wrapping_add((as_signed(self.ld_immediate_byte()) as i16) as u16);
|
||||
},
|
||||
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 => {
|
||||
unsafe {
|
||||
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);
|
||||
};
|
||||
}
|
||||
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);
|
||||
self.state.sp.as_u16 = self.state.sp.as_u16.wrapping_add(2);
|
||||
},
|
||||
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);
|
||||
};
|
||||
}
|
||||
0xF3 => panic!("DI IME instruction: 0xF3"),
|
||||
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 {
|
||||
self.state.hl.as_u16 = self
|
||||
.state
|
||||
.sp
|
||||
.as_u16
|
||||
.wrapping_add((as_signed(self.ld_immediate_byte()) as i16) as u16)
|
||||
},
|
||||
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);
|
||||
},
|
||||
0xFB => panic!("EI IME instruction: 0xFB"),
|
||||
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),
|
||||
};
|
||||
return opcode;
|
||||
}
|
||||
|
||||
fn cb_subop(&mut self, subop: u8) {
|
||||
panic!("Unimplemented sub-opcode: {:#X}", subop);
|
||||
}
|
||||
|
||||
fn next_opcode(&mut self) -> u8 {
|
||||
|
@ -839,3 +1035,13 @@ impl CPU {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn undefined(opcode: u8) {
|
||||
println!("Undefined behaviour: opcode {:#X}", opcode);
|
||||
}
|
||||
|
||||
fn as_signed(unsigned: u8) -> i8 {
|
||||
unsafe {
|
||||
return transmute(unsigned);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue