implementing op codes

This commit is contained in:
2025-05-02 10:46:49 +01:00
parent a3e3fbaa6e
commit ae44d43175
4 changed files with 1273 additions and 640 deletions

View File

@@ -13,6 +13,7 @@
<w>reti</w> <w>reti</w>
<w>rrca</w> <w>rrca</w>
<w>rrla</w> <w>rrla</w>
<w>vram</w>
</words> </words>
</dictionary> </dictionary>
</component> </component>

View File

@@ -1,636 +0,0 @@
use crate::registers::Registers;
struct CPU {
registers: Registers,
pc: u16,
bus: MemoryBus,
sp: u16,
}
struct MemoryBus {
memory: [u8; 0xFFFF]
}
impl MemoryBus {
fn read_byte(&self, address: u16) -> u8 {
self.memory[address as usize]
}
fn write_byte(&mut self, address: u16, value: u8) {
self.memory[address as usize] = value;
}
}
#[derive(Clone, Copy)]
enum Target {
U8Register(TargetRegister),
U16Register(TargetU16Register),
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 {
ADC(Target),
ADD(Target),
ADDHL(TargetU16Register),
ADDSP(u8),
AND(Target),
BIT(u8, Target),
CALL(Condition, u16),
CCF,
CP(Target),
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, }
#[derive(Clone, Copy)]
enum TargetU16Register {AF, BC, DE, HL, SP, PC}
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 {
match target {
TargetRegister::A => { self.registers.a }
TargetRegister::B => { self.registers.b }
TargetRegister::C => { self.registers.c }
TargetRegister::D => { self.registers.d }
TargetRegister::E => { self.registers.e }
TargetRegister::H => { self.registers.h }
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 {
match target {
TargetU16Register::AF => {self.registers.get_af()}
TargetU16Register::BC => {self.registers.get_bc()}
TargetU16Register::DE => {self.registers.get_de()}
TargetU16Register::HL => {self.registers.get_hl()}
TargetU16Register::SP => {self.sp}
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 {
match target {
Target::U8Register(target_register) => { self.get_u8_reg_value(target_register) },
Target::U16Register(target_register) => {
let address = self.get_u16_reg_value(target_register);
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) {
match instruction {
Instruction::ADC(target) => {
let value = self.get_target_value(target);
let (mut new_value, did_overflow) = self.registers.a.overflowing_add(value);
new_value += did_overflow as u8;
self.registers.a = new_value;
self.registers.f.zero = new_value == 0;
self.registers.f.subtract = false;
self.registers.f.carry = did_overflow;
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
}
Instruction::ADD(target) => {
let value = self.get_target_value(target);
let (new_value, did_overflow) = self.registers.a.overflowing_add(value);
self.registers.a = new_value;
self.registers.f.zero = new_value == 0;
self.registers.f.subtract = false;
self.registers.f.carry = did_overflow;
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
}
Instruction::ADDHL(target) => {
let value = self.get_u16_reg_value(target);
let (new_value, did_overflow) = self.registers.get_hl().overflowing_add(value);
self.registers.set_hl(new_value);
self.registers.f.zero = new_value == 0;
self.registers.f.subtract = false;
self.registers.f.carry = did_overflow;
self.registers.f.half_carry = (new_value & 0xFF) + (value & 0xFF) > 0xFF;
}
Instruction::ADDSP(value) => {
let offset = (value as i16) as u16;
let (new_value, did_overflow) = self.sp.overflowing_add(offset);
self.sp = new_value;
self.registers.f.zero = false;
self.registers.f.subtract = false;
self.registers.f.carry = did_overflow;
self.registers.f.half_carry = (new_value & 0xFF) + (offset & 0xFF) > 0xFF;
}
Instruction::AND(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 = true;
}
Instruction::BIT(bit, target) => {
let value = self.get_target_value(target);
self.registers.f.zero = value >> bit & 0x1 == 0;
self.registers.f.subtract = false;
self.registers.f.half_carry = true;
}
Instruction::CALL(condition, address) => {
if self.check_condition(condition) {
self.sp = self.sp.wrapping_sub(2);
let pc = self.pc;
self.bus.write_byte(self.sp + 1, ((pc >> 8) & 0xFF) as u8);
self.bus.write_byte(self.sp, (pc & 0xFF) as u8);
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::CP(target) => {
let value = self.get_target_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::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) => {
let value = self.get_target_value(target);
let (mut new_value, did_overflow) = self.registers.a.overflowing_sub(value);
new_value -= did_overflow as u8;
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::SCF => {
self.registers.f.carry = true;
self.registers.f.subtract = false;
self.registers.f.half_carry = false;
}
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.carry = false;
self.registers.f.half_carry = false;
}
Instruction::XOR(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;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@ const SUBTRACT_FLAG_BYTE_POSITION: u8 = 6;
const HALF_CARRY_FLAG_BYTE_POSITION: u8 = 5; const HALF_CARRY_FLAG_BYTE_POSITION: u8 = 5;
const CARRY_FLAG_BYTE_POSITION: u8 = 4; const CARRY_FLAG_BYTE_POSITION: u8 = 4;
impl std::convert::From<FlagsRegister> for u8 { impl From<FlagsRegister> for u8 {
fn from(flag: FlagsRegister) -> u8 { fn from(flag: FlagsRegister) -> u8 {
(if flag.zero { 1 } else { 0 }) << ZERO_FLAG_BYTE_POSITION | (if flag.zero { 1 } else { 0 }) << ZERO_FLAG_BYTE_POSITION |
(if flag.subtract { 1 } else { 0 }) << SUBTRACT_FLAG_BYTE_POSITION | (if flag.subtract { 1 } else { 0 }) << SUBTRACT_FLAG_BYTE_POSITION |
@@ -21,7 +21,7 @@ impl std::convert::From<FlagsRegister> for u8 {
} }
} }
impl std::convert::From<u8> for FlagsRegister { impl From<u8> for FlagsRegister {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
let zero = ((byte >> ZERO_FLAG_BYTE_POSITION) & 0b1) != 0; let zero = ((byte >> ZERO_FLAG_BYTE_POSITION) & 0b1) != 0;
let subtract = ((byte >> SUBTRACT_FLAG_BYTE_POSITION) & 0b1) != 0; let subtract = ((byte >> SUBTRACT_FLAG_BYTE_POSITION) & 0b1) != 0;