implementing op codes
This commit is contained in:
6
.idea/dictionaries/project.xml
generated
6
.idea/dictionaries/project.xml
generated
@@ -5,6 +5,12 @@
|
|||||||
<w>adcn</w>
|
<w>adcn</w>
|
||||||
<w>addhl</w>
|
<w>addhl</w>
|
||||||
<w>addsp</w>
|
<w>addsp</w>
|
||||||
|
<w>dechl</w>
|
||||||
|
<w>inchl</w>
|
||||||
|
<w>jpcc</w>
|
||||||
|
<w>jphl</w>
|
||||||
|
<w>jrcc</w>
|
||||||
|
<w>reti</w>
|
||||||
<w>rrca</w>
|
<w>rrca</w>
|
||||||
<w>rrla</w>
|
<w>rrla</w>
|
||||||
</words>
|
</words>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
use crate::registers::FlagsRegister;
|
||||||
use crate::registers::Registers;
|
use crate::registers::Registers;
|
||||||
|
|
||||||
struct CPU {
|
struct CPU {
|
||||||
registers: Registers,
|
registers: Registers,
|
||||||
pc: u16,
|
pc: u16,
|
||||||
@@ -19,12 +19,46 @@ impl MemoryBus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
enum Target {
|
enum Target {
|
||||||
U8Register(TargetRegister),
|
U8Register(TargetRegister),
|
||||||
U16Register(TargetU16Register),
|
U16Register(TargetU16Register),
|
||||||
Address(u16),
|
Address(u16),
|
||||||
}
|
}
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum Condition {
|
||||||
|
NZ, // Not Zero
|
||||||
|
Z, // Zero
|
||||||
|
NC, // Not Carry
|
||||||
|
C, // Carry
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum LoadTarget{
|
||||||
|
CopyR8R8(TargetRegister, TargetRegister),
|
||||||
|
CopyR8N8(TargetRegister, u8),
|
||||||
|
CopyR16N16(TargetU16Register, u16),
|
||||||
|
CopyHLR8(TargetRegister),
|
||||||
|
CopyHLN8(u8),
|
||||||
|
CopyR8HL(TargetRegister),
|
||||||
|
CopyR16A(TargetU16Register),
|
||||||
|
CopyN16A(u16),
|
||||||
|
CopyHN16A(u16),
|
||||||
|
CopyHCA,
|
||||||
|
CopyAR16(TargetU16Register),
|
||||||
|
CopyAN16(u16),
|
||||||
|
CopyHAN16(u16),
|
||||||
|
CopyHAC,
|
||||||
|
CopyHLIA,
|
||||||
|
CopyHLDA,
|
||||||
|
CopyAHLD,
|
||||||
|
CopyAHLI,
|
||||||
|
CopySPN16(u16),
|
||||||
|
CopyN16SP(u16),
|
||||||
|
CopyHLSPE8(i8),
|
||||||
|
CopySPHL,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum Instruction {
|
enum Instruction {
|
||||||
@@ -34,27 +68,60 @@ enum Instruction {
|
|||||||
ADDSP(u8),
|
ADDSP(u8),
|
||||||
AND(Target),
|
AND(Target),
|
||||||
BIT(u8, Target),
|
BIT(u8, Target),
|
||||||
CALL(u16),
|
CALL(Condition, u16),
|
||||||
|
|
||||||
SUB(TargetRegister),
|
|
||||||
SBC(TargetRegister),
|
|
||||||
|
|
||||||
OR(TargetRegister),
|
|
||||||
XOR(TargetRegister),
|
|
||||||
CP(TargetRegister),
|
|
||||||
INC(TargetRegister),
|
|
||||||
DEC(TargetRegister),
|
|
||||||
CCF,
|
CCF,
|
||||||
SCF,
|
CP(Target),
|
||||||
RRA,
|
|
||||||
RLA,
|
|
||||||
RRCA,
|
|
||||||
CPL,
|
CPL,
|
||||||
|
DAA,
|
||||||
|
DEC(Target),
|
||||||
|
DECHL(TargetU16Register),
|
||||||
|
DI,
|
||||||
|
EI,
|
||||||
|
HALT,
|
||||||
|
INC(Target),
|
||||||
|
INCHL(TargetU16Register),
|
||||||
|
JP(Condition, u16),
|
||||||
|
JPHL,
|
||||||
|
JR(Condition, i8),
|
||||||
|
LD(LoadTarget),
|
||||||
|
NOP,
|
||||||
|
OR(Target),
|
||||||
|
POP(TargetU16Register),
|
||||||
|
PUSH(TargetU16Register),
|
||||||
|
RES(u8, Target),
|
||||||
|
RET(Condition),
|
||||||
|
RETI,
|
||||||
|
RL(Target),
|
||||||
|
RLC(Target),
|
||||||
|
RR(Target),
|
||||||
|
RRC(Target),
|
||||||
|
RST(u8),
|
||||||
|
SBC(Target),
|
||||||
|
SCF,
|
||||||
|
SET(u8, Target),
|
||||||
|
SLA(Target),
|
||||||
|
SRA(Target),
|
||||||
|
SRL(Target),
|
||||||
|
STOP,
|
||||||
|
SUB(Target),
|
||||||
|
SWAP(Target),
|
||||||
|
XOR(Target),
|
||||||
}
|
}
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
enum TargetRegister { A, B, C, D, E, H, L, }
|
enum TargetRegister { A, B, C, D, E, H, L, }
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
enum TargetU16Register {AF, BC, DE, HL, SP, PC}
|
enum TargetU16Register {AF, BC, DE, HL, SP, PC}
|
||||||
impl CPU {
|
impl CPU {
|
||||||
|
fn check_condition(&self, condition: Condition) -> bool {
|
||||||
|
match condition {
|
||||||
|
Condition::NZ => !self.registers.f.zero,
|
||||||
|
Condition::Z => self.registers.f.zero,
|
||||||
|
Condition::NC => !self.registers.f.carry,
|
||||||
|
Condition::C => self.registers.f.carry,
|
||||||
|
Condition::None => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_u8_reg_value(&mut self, target: TargetRegister) -> u8 {
|
fn get_u8_reg_value(&mut self, target: TargetRegister) -> u8 {
|
||||||
match target {
|
match target {
|
||||||
TargetRegister::A => { self.registers.a }
|
TargetRegister::A => { self.registers.a }
|
||||||
@@ -66,6 +133,17 @@ impl CPU {
|
|||||||
TargetRegister::L => { self.registers.l }
|
TargetRegister::L => { self.registers.l }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn set_u8_reg_value(&mut self, target: TargetRegister, value: u8) {
|
||||||
|
match target {
|
||||||
|
TargetRegister::A => { self.registers.a = value }
|
||||||
|
TargetRegister::B => { self.registers.b = value }
|
||||||
|
TargetRegister::C => { self.registers.c = value }
|
||||||
|
TargetRegister::D => { self.registers.d = value }
|
||||||
|
TargetRegister::E => { self.registers.e = value }
|
||||||
|
TargetRegister::H => { self.registers.h = value }
|
||||||
|
TargetRegister::L => { self.registers.l = value }
|
||||||
|
}
|
||||||
|
}
|
||||||
fn get_u16_reg_value(&mut self, target: TargetU16Register) -> u16 {
|
fn get_u16_reg_value(&mut self, target: TargetU16Register) -> u16 {
|
||||||
match target {
|
match target {
|
||||||
TargetU16Register::AF => {self.registers.get_af()}
|
TargetU16Register::AF => {self.registers.get_af()}
|
||||||
@@ -76,17 +154,50 @@ impl CPU {
|
|||||||
TargetU16Register::PC => {self.pc}
|
TargetU16Register::PC => {self.pc}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn set_u16_reg_value(&mut self, target: TargetU16Register, value: u16) {
|
||||||
|
match target {
|
||||||
|
TargetU16Register::AF => {self.registers.set_af(value)}
|
||||||
|
TargetU16Register::BC => {self.registers.set_bc(value)}
|
||||||
|
TargetU16Register::DE => {self.registers.set_de(value)}
|
||||||
|
TargetU16Register::HL => {self.registers.set_hl(value)}
|
||||||
|
TargetU16Register::SP => {self.sp=value}
|
||||||
|
TargetU16Register::PC => {self.pc=value}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn push_stack(&mut self, value: u16) {
|
||||||
|
let low = (value & 0xFF) as u8;
|
||||||
|
let high = (value >> 8) as u8;
|
||||||
|
self.bus.write_byte(self.sp - 1, high);
|
||||||
|
self.bus.write_byte(self.sp - 2, low);
|
||||||
|
self.sp = self.sp.wrapping_sub(2);
|
||||||
|
}
|
||||||
|
fn pop_stack(&mut self) -> u16 {
|
||||||
|
let low = (self.bus.read_byte(self.sp) as u16) << 8;
|
||||||
|
let high = self.bus.read_byte(self.sp + 1) as u16;
|
||||||
|
self.sp = self.sp.wrapping_add(2);
|
||||||
|
high | low
|
||||||
|
}
|
||||||
|
|
||||||
fn get_target_value(&mut self, target: Target) -> u8 {
|
fn get_target_value(&mut self, target: Target) -> u8 {
|
||||||
match target {
|
match target {
|
||||||
Target::U8Register(target_register) => { self.get_u8_reg_value(target_register) },
|
Target::U8Register(target_register) => { self.get_u8_reg_value(target_register) },
|
||||||
Target::U16Register(target_register) => {
|
Target::U16Register(target_register) => {
|
||||||
let address = self.get_u16_reg_value(target_register);
|
let address = self.get_u16_reg_value(target_register);
|
||||||
self.bus.read_byte(address)
|
self.bus.read_byte(address)
|
||||||
},
|
},
|
||||||
Target::Address(address) => { self.bus.read_byte(address) },
|
Target::Address(address) => { self.bus.read_byte(address) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn set_target_value(&mut self, target: Target, value: u8) {
|
||||||
|
match target {
|
||||||
|
Target::U8Register(target_register) => { self.set_u8_reg_value(target_register, value) },
|
||||||
|
Target::U16Register(target_register) => {
|
||||||
|
let address = self.get_u16_reg_value(target_register);
|
||||||
|
self.bus.write_byte(address, value)
|
||||||
|
},
|
||||||
|
Target::Address(address) => { self.bus.write_byte(address, value) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
fn execute(&mut self, instruction: Instruction) {
|
fn execute(&mut self, instruction: Instruction) {
|
||||||
@@ -142,33 +253,311 @@ impl CPU {
|
|||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.half_carry = true;
|
self.registers.f.half_carry = true;
|
||||||
}
|
}
|
||||||
Instruction::CALL(address) => {
|
Instruction::CALL(condition, address) => {
|
||||||
// Decrement stack pointer
|
if self.check_condition(condition) {
|
||||||
self.sp = self.sp.wrapping_sub(2);
|
self.sp = self.sp.wrapping_sub(2);
|
||||||
|
let pc = self.pc;
|
||||||
let pc = self.pc;
|
self.bus.write_byte(self.sp + 1, ((pc >> 8) & 0xFF) as u8);
|
||||||
self.bus.write_byte(self.sp + 1, ((pc >> 8) & 0xFF) as u8);
|
self.bus.write_byte(self.sp, (pc & 0xFF) as u8);
|
||||||
self.bus.write_byte(self.sp, (pc & 0xFF) as u8);
|
self.pc = address;
|
||||||
|
}
|
||||||
// Jump to the target address
|
|
||||||
self.pc = address;
|
|
||||||
}
|
}
|
||||||
|
Instruction::CCF => {
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
self.registers.f.carry = !self.registers.f.carry;
|
||||||
|
}
|
||||||
Instruction::SUB(target) => {
|
Instruction::CP(target) => {
|
||||||
let value = self.get_u8_reg_value(target);
|
let value = self.get_target_value(target);
|
||||||
let (new_value, did_overflow) = self.registers.a.overflowing_sub(value);
|
let (new_value, did_overflow) = self.registers.a.overflowing_sub(value);
|
||||||
self.registers.a = new_value;
|
|
||||||
self.registers.f.zero = new_value == 0;
|
self.registers.f.zero = new_value == 0;
|
||||||
self.registers.f.subtract = true;
|
self.registers.f.subtract = true;
|
||||||
self.registers.f.carry = did_overflow;
|
self.registers.f.carry = did_overflow;
|
||||||
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
|
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
|
||||||
}
|
}
|
||||||
|
Instruction::CPL => {
|
||||||
|
self.registers.a = !self.registers.a;
|
||||||
|
self.registers.f.subtract = true;
|
||||||
|
self.registers.f.half_carry = true;
|
||||||
|
}
|
||||||
|
Instruction::DAA => {
|
||||||
|
let new_value;
|
||||||
|
let did_overflow;
|
||||||
|
let mut adjustment: u8 = 0;
|
||||||
|
if self.registers.f.subtract {
|
||||||
|
if self.registers.f.half_carry {
|
||||||
|
adjustment += 0x6;
|
||||||
|
}
|
||||||
|
if self.registers.f.carry {
|
||||||
|
adjustment += 0x60;
|
||||||
|
}
|
||||||
|
(new_value, did_overflow) = self.registers.a.overflowing_sub(adjustment);
|
||||||
|
} else {
|
||||||
|
if self.registers.f.half_carry || self.registers.a & 0xF > 0x9 {
|
||||||
|
adjustment += 0x6;
|
||||||
|
}
|
||||||
|
if self.registers.f.carry || self.registers.a > 0x99 {
|
||||||
|
adjustment += 0x60;
|
||||||
|
}
|
||||||
|
(new_value, did_overflow) = self.registers.a.overflowing_add(adjustment);
|
||||||
|
}
|
||||||
|
self.registers.a = new_value;
|
||||||
|
self.registers.f.carry = did_overflow;
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::DEC(target) => {
|
||||||
|
match target {
|
||||||
|
Target::U8Register(target) => {
|
||||||
|
let value = self.get_u8_reg_value(target);
|
||||||
|
let (new_value, _) = value.overflowing_sub(1);
|
||||||
|
self.set_u8_reg_value(target, new_value);
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = true;
|
||||||
|
self.registers.f.half_carry = (new_value & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
}
|
||||||
|
Target::U16Register(target) => {
|
||||||
|
let value = self.get_u16_reg_value(target);
|
||||||
|
let new_value = value.wrapping_sub(1);
|
||||||
|
self.set_u16_reg_value(target, new_value);
|
||||||
|
}
|
||||||
|
Target::Address(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instruction::DECHL(register) => {
|
||||||
|
let target = Target::U16Register(register);
|
||||||
|
let value = self.get_target_value(target);
|
||||||
|
let new_value = value.wrapping_sub(1);
|
||||||
|
self.set_target_value(target, new_value);
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = true;
|
||||||
|
self.registers.f.half_carry = (new_value & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
}
|
||||||
|
Instruction::DI => {}
|
||||||
|
Instruction::EI => {}
|
||||||
|
Instruction::HALT => {todo!();}
|
||||||
|
|
||||||
|
Instruction::INC(target) => {
|
||||||
|
match target {
|
||||||
|
Target::U8Register(target) => {
|
||||||
|
let value = self.get_u8_reg_value(target);
|
||||||
|
let (new_value, _) = value.overflowing_add(1);
|
||||||
|
self.set_u8_reg_value(target, new_value);
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.half_carry = (new_value & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
}
|
||||||
|
Target::U16Register(target) => {
|
||||||
|
let value = self.get_u16_reg_value(target);
|
||||||
|
let new_value = value.wrapping_add(1);
|
||||||
|
self.set_u16_reg_value(target, new_value);
|
||||||
|
}
|
||||||
|
Target::Address(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instruction::INCHL(register) => {
|
||||||
|
let target = Target::U16Register(register);
|
||||||
|
let value = self.get_target_value(target);
|
||||||
|
let new_value = value.wrapping_add(1);
|
||||||
|
self.set_target_value(target, new_value);
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = true;
|
||||||
|
self.registers.f.half_carry = (new_value & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
}
|
||||||
|
Instruction::JP(condition, address) => {
|
||||||
|
if self.check_condition(condition) {
|
||||||
|
self.pc = address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instruction::JPHL => {
|
||||||
|
self.pc = self.registers.get_hl();
|
||||||
|
}
|
||||||
|
Instruction::JR(condition, offset) => {
|
||||||
|
if self.check_condition(condition) {
|
||||||
|
self.pc = if offset.is_negative() {
|
||||||
|
self.pc.wrapping_sub(offset.abs() as u16)
|
||||||
|
} else {
|
||||||
|
self.pc.wrapping_add(offset as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instruction::LD(target) => {
|
||||||
|
match target {
|
||||||
|
LoadTarget::CopyR8R8(dest_register, source_register) => {
|
||||||
|
let value = self.get_u8_reg_value(source_register);
|
||||||
|
self.set_u8_reg_value(dest_register, value);
|
||||||
|
}
|
||||||
|
LoadTarget::CopyR8N8(dest_register, value) => {
|
||||||
|
self.set_u8_reg_value(dest_register, value);
|
||||||
|
}
|
||||||
|
LoadTarget::CopyR16N16(dest_register, value) => {
|
||||||
|
self.set_u16_reg_value(dest_register, value);
|
||||||
|
}
|
||||||
|
LoadTarget::CopyHLR8(source_register) => {
|
||||||
|
let value = self.get_u8_reg_value(source_register);
|
||||||
|
let address = self.registers.get_hl();
|
||||||
|
self.bus.write_byte(address, value);
|
||||||
|
}
|
||||||
|
LoadTarget::CopyHLN8(value) => {
|
||||||
|
let address = self.registers.get_hl();
|
||||||
|
self.bus.write_byte(address, value);
|
||||||
|
}
|
||||||
|
LoadTarget::CopyR8HL(dest_register) => {
|
||||||
|
let address = self.registers.get_hl();
|
||||||
|
let value = self.bus.read_byte(address);
|
||||||
|
self.set_u8_reg_value(dest_register, value);
|
||||||
|
}
|
||||||
|
LoadTarget::CopyR16A(dest_register) => {
|
||||||
|
let address = self.get_u16_reg_value(dest_register);
|
||||||
|
self.bus.write_byte(address, self.registers.a);
|
||||||
|
}
|
||||||
|
LoadTarget::CopyN16A(address) => {
|
||||||
|
self.bus.write_byte(address, self.registers.a);
|
||||||
|
}
|
||||||
|
LoadTarget::CopyHN16A(address) => {
|
||||||
|
if address >= 0xFF00 {
|
||||||
|
self.bus.write_byte(address, self.registers.a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LoadTarget::CopyHCA => {
|
||||||
|
let address = 0xFF00 + self.registers.c as u16;
|
||||||
|
self.bus.write_byte(address, self.registers.a)
|
||||||
|
}
|
||||||
|
LoadTarget::CopyAR16(source_register) => {
|
||||||
|
let address = self.get_u16_reg_value(source_register);
|
||||||
|
self.registers.a = self.bus.read_byte(address);
|
||||||
|
}
|
||||||
|
LoadTarget::CopyAN16(address) => {
|
||||||
|
self.registers.a = self.bus.read_byte(address);
|
||||||
|
}
|
||||||
|
LoadTarget::CopyHAN16(address) => {
|
||||||
|
if address >= 0xFF00 {
|
||||||
|
self.registers.a = self.bus.read_byte(address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LoadTarget::CopyHAC => {
|
||||||
|
self.registers.a = self.bus.read_byte(0xFF00+self.registers.c as u16)
|
||||||
|
}
|
||||||
|
LoadTarget::CopyHLIA => {
|
||||||
|
let address = self.registers.get_hl();
|
||||||
|
self.bus.write_byte(address, self.registers.a);
|
||||||
|
self.registers.set_hl(address.wrapping_add(1));
|
||||||
|
}
|
||||||
|
LoadTarget::CopyHLDA => {
|
||||||
|
let address = self.registers.get_hl();
|
||||||
|
self.bus.write_byte(address, self.registers.a);
|
||||||
|
self.registers.set_hl(address.wrapping_sub(1));
|
||||||
|
}
|
||||||
|
LoadTarget::CopyAHLI => {
|
||||||
|
let address = self.registers.get_hl();
|
||||||
|
self.registers.a = self.bus.read_byte(address);
|
||||||
|
self.registers.set_hl(address.wrapping_add(1));
|
||||||
|
}
|
||||||
|
LoadTarget::CopyAHLD => {
|
||||||
|
let address = self.registers.get_hl();
|
||||||
|
self.registers.a = self.bus.read_byte(address);
|
||||||
|
self.registers.set_hl(address.wrapping_sub(1));
|
||||||
|
}
|
||||||
|
LoadTarget::CopySPN16(value) => {
|
||||||
|
self.sp = value;
|
||||||
|
}
|
||||||
|
LoadTarget::CopyN16SP(address) => {
|
||||||
|
self.bus.write_byte(address, (0xF & self.sp) as u8);
|
||||||
|
self.bus.write_byte(address + 1, (self.sp >> 8) as u8);
|
||||||
|
}
|
||||||
|
LoadTarget::CopyHLSPE8(value) => {
|
||||||
|
|
||||||
|
let new_value = match value.is_negative() {
|
||||||
|
true => { self.sp.wrapping_sub(value.abs() as u16) }
|
||||||
|
false => { self.sp.wrapping_add(value as u16) }
|
||||||
|
};
|
||||||
|
self.registers.set_hl(new_value);
|
||||||
|
self.registers.f.zero = false;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.carry = (new_value & 0xFF) + (self.sp & 0xFF) > 0xFF;
|
||||||
|
self.registers.f.half_carry = (new_value & 0xF) + (self.sp & 0xF) > 0xF;
|
||||||
|
|
||||||
|
}
|
||||||
|
LoadTarget::CopySPHL => {
|
||||||
|
self.sp = self.registers.get_hl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instruction::NOP => {}
|
||||||
|
Instruction::OR(target) => {
|
||||||
|
let value = self.get_target_value(target);
|
||||||
|
self.registers.a = value | self.registers.a;
|
||||||
|
self.registers.f.zero = self.registers.a == 0;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.carry = false;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::POP(target) => {
|
||||||
|
let value = self.pop_stack();
|
||||||
|
self.set_u16_reg_value(target, value);
|
||||||
|
}
|
||||||
|
Instruction::PUSH(target) => {
|
||||||
|
let value = self.get_u16_reg_value(target);
|
||||||
|
self.push_stack(value);
|
||||||
|
}
|
||||||
|
Instruction::RES(bit, target) => {
|
||||||
|
let mut value = self.get_target_value(target);
|
||||||
|
value &= !(1 << bit);
|
||||||
|
self.set_target_value(target, value);
|
||||||
|
}
|
||||||
|
Instruction::RET(condition) => {
|
||||||
|
if self.check_condition(condition) {
|
||||||
|
self.pc = self.pop_stack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instruction::RETI => {
|
||||||
|
self.pc = self.pop_stack();
|
||||||
|
}
|
||||||
|
Instruction::RL(target) => {
|
||||||
|
let old_value = self.get_target_value(target);
|
||||||
|
let old_carry = self.registers.f.carry;
|
||||||
|
self.registers.f.carry = old_value & 0x80 == 0x80;
|
||||||
|
let new_value = (self.registers.a << 1) | (if old_carry { 0x01 } else { 0 });
|
||||||
|
self.set_target_value(target, new_value);
|
||||||
|
self.registers.f.zero = false;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::RLC(target) => {
|
||||||
|
let old_value = self.get_target_value(target);
|
||||||
|
self.registers.f.carry = old_value & 0x80 == 0x80;
|
||||||
|
let new_value = (self.registers.a << 1) | (if self.registers.f.carry { 0x1 } else { 0 });
|
||||||
|
self.set_target_value(target, new_value);
|
||||||
|
self.registers.f.zero = false;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::RR(target) => {
|
||||||
|
let old_value = self.get_target_value(target);
|
||||||
|
let old_carry = self.registers.f.carry;
|
||||||
|
self.registers.f.carry = old_value & 0x1 == 0x1;
|
||||||
|
let new_value = (self.registers.a >> 1) | (if old_carry { 0x80 } else { 0 });
|
||||||
|
self.set_target_value(target, new_value);
|
||||||
|
self.registers.f.zero = false;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::RRC(target) => {
|
||||||
|
let old_value = self.get_target_value(target);
|
||||||
|
self.registers.f.carry = old_value & 0x1 == 0x1;
|
||||||
|
let new_value = (self.registers.a >> 1) | (if self.registers.f.carry { 0x80 } else { 0 });
|
||||||
|
self.set_target_value(target, new_value);
|
||||||
|
self.registers.f.zero = false;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::RST(idx) => {
|
||||||
|
self.push_stack(self.pc);
|
||||||
|
let address = self.bus.read_byte((idx as u16) * 8) as u16;
|
||||||
|
self.pc = address;
|
||||||
|
}
|
||||||
Instruction::SBC(target) => {
|
Instruction::SBC(target) => {
|
||||||
let value = self.get_u8_reg_value(target);
|
let value = self.get_target_value(target);
|
||||||
let (mut new_value, did_overflow) = self.registers.a.overflowing_sub(value);
|
let (mut new_value, did_overflow) = self.registers.a.overflowing_sub(value);
|
||||||
new_value -= did_overflow as u8;
|
new_value -= did_overflow as u8;
|
||||||
self.registers.a = new_value;
|
self.registers.a = new_value;
|
||||||
@@ -177,165 +566,72 @@ impl CPU {
|
|||||||
self.registers.f.carry = did_overflow;
|
self.registers.f.carry = did_overflow;
|
||||||
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
|
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
|
||||||
}
|
}
|
||||||
|
Instruction::SCF => {
|
||||||
Instruction::OR(target) => {
|
self.registers.f.carry = true;
|
||||||
let value = self.get_u8_reg_value(target);
|
self.registers.f.subtract = false;
|
||||||
self.registers.a = value | self.registers.a;
|
self.registers.f.half_carry = false;
|
||||||
self.registers.f.zero = self.registers.a == 0;
|
}
|
||||||
|
Instruction::SET(bit, target) => {
|
||||||
|
let mut value = self.get_target_value(target);
|
||||||
|
value |= 1 << bit;
|
||||||
|
self.set_target_value(target, value);
|
||||||
|
}
|
||||||
|
Instruction::SLA(target) => {
|
||||||
|
let value = self.get_target_value(target);
|
||||||
|
let new_value = value << 1;
|
||||||
|
self.set_target_value(target, new_value);
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.carry = value & 0x80 == 0x80;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::SRA(target) => {
|
||||||
|
let value = self.get_target_value(target);
|
||||||
|
let new_value = value >> 1 | (if value & 0x80 == 0x80 { 0x80 } else { 0 });
|
||||||
|
self.set_target_value(target, new_value);
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.carry = value & 0x80 == 0x80;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::SRL(target) => {
|
||||||
|
let value = self.get_target_value(target);
|
||||||
|
let new_value = value >> 1;
|
||||||
|
self.set_target_value(target, new_value);
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = false;
|
||||||
|
self.registers.f.carry = value & 0x1 == 0x1;
|
||||||
|
self.registers.f.half_carry = false;
|
||||||
|
}
|
||||||
|
Instruction::STOP => {
|
||||||
|
|
||||||
|
}
|
||||||
|
Instruction::SUB(target) => {
|
||||||
|
let value = self.get_target_value(target);
|
||||||
|
let (new_value, did_overflow) = self.registers.a.overflowing_sub(value);
|
||||||
|
self.registers.a = new_value;
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
|
self.registers.f.subtract = true;
|
||||||
|
self.registers.f.carry = did_overflow;
|
||||||
|
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
}
|
||||||
|
Instruction::SWAP(target) => {
|
||||||
|
let value = self.get_target_value(target);
|
||||||
|
let new_value = ((value & 0xF0) >> 4) | ((value & 0x0F) << 4);
|
||||||
|
self.set_target_value(target, new_value);
|
||||||
|
self.registers.f.zero = new_value == 0;
|
||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.carry = false;
|
self.registers.f.carry = false;
|
||||||
self.registers.f.half_carry = false;
|
self.registers.f.half_carry = false;
|
||||||
}
|
}
|
||||||
Instruction::XOR(target) => {
|
Instruction::XOR(target) => {
|
||||||
let value = self.get_u8_reg_value(target);
|
let value = self.get_target_value(target);
|
||||||
self.registers.a = value ^ self.registers.a;
|
self.registers.a = value ^ self.registers.a;
|
||||||
self.registers.f.zero = self.registers.a == 0;
|
self.registers.f.zero = self.registers.a == 0;
|
||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.carry = false;
|
self.registers.f.carry = false;
|
||||||
self.registers.f.half_carry = false;
|
self.registers.f.half_carry = false;
|
||||||
}
|
}
|
||||||
Instruction::CP(target) => {
|
|
||||||
let value = self.get_u8_reg_value(target);
|
|
||||||
let (new_value, did_overflow) = self.registers.a.overflowing_sub(value);
|
|
||||||
self.registers.f.zero = new_value == 0;
|
|
||||||
self.registers.f.subtract = true;
|
|
||||||
self.registers.f.carry = did_overflow;
|
|
||||||
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
|
|
||||||
}
|
|
||||||
Instruction::INC(target) => {
|
|
||||||
let (value, new_value) = match target {
|
|
||||||
TargetRegister::A => {
|
|
||||||
let value = self.registers.a;
|
|
||||||
let (new_value, _) = value.overflowing_add(1);
|
|
||||||
self.registers.a = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
},
|
|
||||||
TargetRegister::B => {
|
|
||||||
let value = self.registers.b;
|
|
||||||
let (new_value, _) = value.overflowing_add(1);
|
|
||||||
self.registers.b = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
},
|
|
||||||
TargetRegister::C => {
|
|
||||||
let value = self.registers.c;
|
|
||||||
let (new_value, _) = value.overflowing_add(1);
|
|
||||||
self.registers.c = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
},
|
|
||||||
TargetRegister::D => {
|
|
||||||
let value = self.registers.d;
|
|
||||||
let (new_value, _) = value.overflowing_add(1);
|
|
||||||
self.registers.d = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
},
|
|
||||||
TargetRegister::E => {
|
|
||||||
let value = self.registers.e;
|
|
||||||
let (new_value, _) = value.overflowing_add(1);
|
|
||||||
self.registers.e = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
},
|
|
||||||
TargetRegister::H => {
|
|
||||||
let value = self.registers.h;
|
|
||||||
let (new_value, _) = value.overflowing_add(1);
|
|
||||||
self.registers.h = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
},
|
|
||||||
TargetRegister::L => {
|
|
||||||
let value = self.registers.l;
|
|
||||||
let (new_value, _) = value.overflowing_add(1);
|
|
||||||
self.registers.l = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.registers.f.zero = new_value == 0;
|
|
||||||
self.registers.f.subtract = false;
|
|
||||||
self.registers.f.half_carry = (new_value & 0xF) + (value & 0xF) > 0xF;
|
|
||||||
}
|
|
||||||
Instruction::DEC(target) => {
|
|
||||||
let (value, new_value) = match target {
|
|
||||||
TargetRegister::A => {
|
|
||||||
let value = self.registers.a;
|
|
||||||
let (new_value, _) = value.overflowing_sub(1);
|
|
||||||
self.registers.a = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
},
|
|
||||||
TargetRegister::B => {
|
|
||||||
let value = self.registers.b;
|
|
||||||
let (new_value, _) = value.overflowing_sub(1);
|
|
||||||
self.registers.b = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
},
|
|
||||||
TargetRegister::C => {
|
|
||||||
let value = self.registers.c;
|
|
||||||
let (new_value, _) = value.overflowing_sub(1);
|
|
||||||
self.registers.c = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
},
|
|
||||||
TargetRegister::D => {
|
|
||||||
let value = self.registers.d;
|
|
||||||
let (new_value, _) = value.overflowing_sub(1);
|
|
||||||
self.registers.d = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
},
|
|
||||||
TargetRegister::E => {
|
|
||||||
let value = self.registers.e;
|
|
||||||
let (new_value, _) = value.overflowing_sub(1);
|
|
||||||
self.registers.e = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
},
|
|
||||||
TargetRegister::H => {
|
|
||||||
let value = self.registers.h;
|
|
||||||
let (new_value, _) = value.overflowing_sub(1);
|
|
||||||
self.registers.h = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
},
|
|
||||||
TargetRegister::L => {
|
|
||||||
let value = self.registers.l;
|
|
||||||
let (new_value, _) = value.overflowing_sub(1);
|
|
||||||
self.registers.l = new_value;
|
|
||||||
(value, new_value)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.registers.f.zero = new_value == 0;
|
|
||||||
self.registers.f.subtract = true;
|
|
||||||
self.registers.f.half_carry = (new_value & 0xF) + (value & 0xF) > 0xF;
|
|
||||||
}
|
|
||||||
Instruction::CCF => {
|
|
||||||
self.registers.f.carry = !self.registers.f.carry;
|
|
||||||
}
|
|
||||||
Instruction::SCF => {
|
|
||||||
self.registers.f.carry = true;
|
|
||||||
}
|
|
||||||
Instruction::RRA => {
|
|
||||||
let old_carry = self.registers.f.carry;
|
|
||||||
self.registers.f.carry = self.registers.a & 0x1 == 0x1;
|
|
||||||
self.registers.a = (self.registers.a >> 1) | (if old_carry { 0x80 } else { 0 });
|
|
||||||
self.registers.f.zero = false;
|
|
||||||
self.registers.f.subtract = false;
|
|
||||||
self.registers.f.half_carry = false;
|
|
||||||
}
|
|
||||||
Instruction::RLA => {
|
|
||||||
let old_carry = self.registers.f.carry;
|
|
||||||
self.registers.f.carry = self.registers.a & 0x80 == 0x80;
|
|
||||||
self.registers.a = (self.registers.a << 1) | (if old_carry { 0x01 } else { 0 });
|
|
||||||
self.registers.f.zero = false;
|
|
||||||
self.registers.f.subtract = false;
|
|
||||||
self.registers.f.half_carry = false;
|
|
||||||
}
|
|
||||||
Instruction::RRCA => {
|
|
||||||
self.registers.f.carry = self.registers.a & 0x1 == 0x1;
|
|
||||||
self.registers.a = self.registers.a >> 1;
|
|
||||||
self.registers.f.zero = false;
|
|
||||||
self.registers.f.subtract = false;
|
|
||||||
self.registers.f.half_carry = false;
|
|
||||||
}
|
|
||||||
Instruction::CPL => {
|
|
||||||
self.registers.a = !self.registers.a;
|
|
||||||
self.registers.f.subtract = true;
|
|
||||||
self.registers.f.half_carry = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user