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};
|
use crate::{Inner, Memory, Register, State};
|
||||||
|
|
||||||
|
@ -16,9 +19,9 @@ pub struct CPU {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CPU {
|
impl CPU {
|
||||||
pub fn exec_next(&mut self) -> u8 {
|
pub fn exec_next(&mut self) {
|
||||||
let opcode = self.next_opcode();
|
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 {
|
match opcode {
|
||||||
0x0 => {
|
0x0 => {
|
||||||
// noop
|
// noop
|
||||||
|
@ -76,7 +79,7 @@ impl CPU {
|
||||||
.state
|
.state
|
||||||
.pc
|
.pc
|
||||||
.as_u16
|
.as_u16
|
||||||
.wrapping_add(self.ld_immediate_byte() as u16)
|
.wrapping_add((as_signed(self.ld_immediate_byte()) as i16) as u16)
|
||||||
},
|
},
|
||||||
0x19 => unsafe {
|
0x19 => unsafe {
|
||||||
self.state.hl.as_u16 = self.state.hl.as_u16.wrapping_add(self.state.de.as_u16)
|
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();
|
let jump_size = self.ld_immediate_byte();
|
||||||
if self.get_flag(FLAGS::Z) == 0 {
|
if self.get_flag(FLAGS::Z) == 0 {
|
||||||
unsafe {
|
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();
|
let jump_size = self.ld_immediate_byte();
|
||||||
if self.get_flag(FLAGS::Z) == 1 {
|
if self.get_flag(FLAGS::Z) == 1 {
|
||||||
unsafe {
|
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();
|
let jump_size = self.ld_immediate_byte();
|
||||||
if self.get_flag(FLAGS::C) == 0 {
|
if self.get_flag(FLAGS::C) == 0 {
|
||||||
unsafe {
|
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();
|
let jump_size = self.ld_immediate_byte();
|
||||||
if self.get_flag(FLAGS::C) == 1 {
|
if self.get_flag(FLAGS::C) == 1 {
|
||||||
unsafe {
|
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;
|
self.state.pc = maybe_next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0xCB => println!("Undefined behaviour: opcode CB"),
|
0xCB => {
|
||||||
|
let subop = self.ld_immediate_byte();
|
||||||
|
self.cb_subop(subop);
|
||||||
|
}
|
||||||
0xCC => {
|
0xCC => {
|
||||||
let maybe_next = self.ld_immediate_word();
|
let maybe_next = self.ld_immediate_word();
|
||||||
if self.get_flag(FLAGS::Z) == 1 {
|
if self.get_flag(FLAGS::Z) == 1 {
|
||||||
|
@ -744,18 +766,192 @@ impl CPU {
|
||||||
.wrapping_add(self.ld_immediate_byte() + self.get_flag(FLAGS::C))
|
.wrapping_add(self.ld_immediate_byte() + self.get_flag(FLAGS::C))
|
||||||
},
|
},
|
||||||
0xCF => self.rst(0x08),
|
0xCF => self.rst(0x08),
|
||||||
|
0xD0 => unsafe {
|
||||||
0xEA => {
|
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 {
|
unsafe {
|
||||||
let address = self.ld_immediate_word().as_u16;
|
let address = Register {
|
||||||
self.memory.set(address, self.state.af.as_u8s.left);
|
as_u8s: Inner {
|
||||||
|
left: self.ld_immediate_byte(),
|
||||||
|
right: 0xFF,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
self.memory.set(address.as_u16, self.state.af.as_u8s.left);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
_ => {
|
0xE1 => unsafe {
|
||||||
panic!("unimplemented opcode: {:#X}", opcode);
|
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 {
|
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