Refactor boot process and instruction execution
Introduce clearer boot ROM handling and streamline `execute_next_instruction` for better readability and accuracy. Add program counter (`pc`) updates within each instruction, improving program flow consistency.
This commit is contained in:
171
src/main.rs
171
src/main.rs
@@ -119,12 +119,14 @@ struct CPU {
|
|||||||
pc: u16,
|
pc: u16,
|
||||||
bus: MemoryBus,
|
bus: MemoryBus,
|
||||||
sp: u16,
|
sp: u16,
|
||||||
boot_rom: Vec<u8>,
|
|
||||||
}
|
}
|
||||||
|
const BOOT_BEGIN: usize = 0x0000;
|
||||||
|
const BOOT_END: usize = 0x00FF;
|
||||||
|
const CART_BEGIN: usize = 0x0100;
|
||||||
|
const CART_END: usize = 0x7FFF;
|
||||||
const VRAM_BEGIN: usize = 0x8000;
|
const VRAM_BEGIN: usize = 0x8000;
|
||||||
const VRAM_END: usize = 0x9FFF;
|
const VRAM_END: usize = 0x9FFF;
|
||||||
const CART_BEGIN: usize = 0x0000;
|
|
||||||
const CART_END: usize = 0x7FFF;
|
|
||||||
struct GPU { vram: Vec<u8>, tile_set: [[[TilePixelValue; 8]; 8]; 384] }
|
struct GPU { vram: Vec<u8>, tile_set: [[[TilePixelValue; 8]; 8]; 384] }
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
enum TilePixelValue { Three, Two, One, Zero }
|
enum TilePixelValue { Three, Two, One, Zero }
|
||||||
@@ -134,7 +136,7 @@ impl GPU {
|
|||||||
self.vram[address]
|
self.vram[address]
|
||||||
}
|
}
|
||||||
fn write_vram(&mut self, index: usize, value: u8) {
|
fn write_vram(&mut self, index: usize, value: u8) {
|
||||||
self.vram[index] = value;
|
// self.vram[index] = value;
|
||||||
// If our index is greater than 0x1800, we're not writing to the tile set storage
|
// If our index is greater than 0x1800, we're not writing to the tile set storage
|
||||||
// so we can just return.
|
// so we can just return.
|
||||||
if index >= 0x1800 { return }
|
if index >= 0x1800 { return }
|
||||||
@@ -199,6 +201,7 @@ struct MemoryBus {
|
|||||||
memory: [u8; 0xFFFF],
|
memory: [u8; 0xFFFF],
|
||||||
gpu: GPU,
|
gpu: GPU,
|
||||||
rom: GameRom,
|
rom: GameRom,
|
||||||
|
boot: Vec<u8>,
|
||||||
}
|
}
|
||||||
impl MemoryBus {
|
impl MemoryBus {
|
||||||
fn read_byte(&self, address: u16) -> u8 {
|
fn read_byte(&self, address: u16) -> u8 {
|
||||||
@@ -207,8 +210,15 @@ impl MemoryBus {
|
|||||||
VRAM_BEGIN ..= VRAM_END => {
|
VRAM_BEGIN ..= VRAM_END => {
|
||||||
self.gpu.read_vram(address - VRAM_BEGIN)
|
self.gpu.read_vram(address - VRAM_BEGIN)
|
||||||
}
|
}
|
||||||
|
BOOT_BEGIN..=BOOT_END => {
|
||||||
|
if self.memory[0xFF50] == 0x00 {
|
||||||
|
self.boot[address]
|
||||||
|
}else {
|
||||||
|
self.rom.read_byte(address)
|
||||||
|
}
|
||||||
|
}
|
||||||
CART_BEGIN ..= CART_END => {self.rom.read_byte(address)}
|
CART_BEGIN ..= CART_END => {self.rom.read_byte(address)}
|
||||||
_ => self.memory[address as usize]
|
_ => self.memory[address]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn write_byte(&mut self, address: u16, value: u8) {
|
fn write_byte(&mut self, address: u16, value: u8) {
|
||||||
@@ -334,12 +344,7 @@ impl CPU {
|
|||||||
let l = self.bus.memory.len();
|
let l = self.bus.memory.len();
|
||||||
println!("{l}");
|
println!("{l}");
|
||||||
println!("CPU init");
|
println!("CPU init");
|
||||||
// println!("Boot ROM: {:02X?}", self.boot_rom);
|
self.bus.write_byte(0xFF50, 0x00);
|
||||||
for (address, byte) in self.boot_rom.iter().enumerate() {
|
|
||||||
self.bus.write_byte(address as u16, *byte);
|
|
||||||
}
|
|
||||||
// println!("Game ROM: {:02X?}", self.game_rom);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
fn check_condition(&self, condition: Condition) -> bool {
|
fn check_condition(&self, condition: Condition) -> bool {
|
||||||
match condition {
|
match condition {
|
||||||
@@ -942,6 +947,14 @@ impl CPU {
|
|||||||
_ => { panic!("Invalid u16 opcode: {:02X}", opcode); }
|
_ => { panic!("Invalid u16 opcode: {:02X}", opcode); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn execute_next_instruction(&mut self) {
|
||||||
|
if self.pc >= 0x100 {
|
||||||
|
println!("Boot Complete");
|
||||||
|
}
|
||||||
|
let inst = self.next_instruction();
|
||||||
|
println!("{} {:?}", self.pc, inst);
|
||||||
|
self.execute(inst);
|
||||||
|
}
|
||||||
fn execute(&mut self, instruction: Instruction) {
|
fn execute(&mut self, instruction: Instruction) {
|
||||||
match instruction {
|
match instruction {
|
||||||
Instruction::ADC(target) => {
|
Instruction::ADC(target) => {
|
||||||
@@ -953,6 +966,10 @@ impl CPU {
|
|||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
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;
|
||||||
|
self.pc += match target {
|
||||||
|
Target::Immediate(_) => {2}
|
||||||
|
_ => {1}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Instruction::ADD(target) => {
|
Instruction::ADD(target) => {
|
||||||
let value = self.get_target_value(target);
|
let value = self.get_target_value(target);
|
||||||
@@ -962,6 +979,10 @@ impl CPU {
|
|||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
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;
|
||||||
|
self.pc += match target {
|
||||||
|
Target::Immediate(_) => {2}
|
||||||
|
_ => {1}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Instruction::ADDHL(target) => {
|
Instruction::ADDHL(target) => {
|
||||||
let value = self.get_u16_reg_value(target);
|
let value = self.get_u16_reg_value(target);
|
||||||
@@ -971,6 +992,7 @@ impl CPU {
|
|||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.carry = did_overflow;
|
self.registers.f.carry = did_overflow;
|
||||||
self.registers.f.half_carry = (new_value & 0xFF) + (value & 0xFF) > 0xFF;
|
self.registers.f.half_carry = (new_value & 0xFF) + (value & 0xFF) > 0xFF;
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
Instruction::ADDSP(value) => {
|
Instruction::ADDSP(value) => {
|
||||||
let offset = (value as i16) as u16;
|
let offset = (value as i16) as u16;
|
||||||
@@ -980,6 +1002,7 @@ impl CPU {
|
|||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.carry = did_overflow;
|
self.registers.f.carry = did_overflow;
|
||||||
self.registers.f.half_carry = (new_value & 0xFF) + (offset & 0xFF) > 0xFF;
|
self.registers.f.half_carry = (new_value & 0xFF) + (offset & 0xFF) > 0xFF;
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
Instruction::AND(target) => {
|
Instruction::AND(target) => {
|
||||||
let value = self.get_target_value(target);
|
let value = self.get_target_value(target);
|
||||||
@@ -988,17 +1011,22 @@ impl CPU {
|
|||||||
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 = true;
|
self.registers.f.half_carry = true;
|
||||||
|
self.pc += match target {
|
||||||
|
Target::Immediate(_) => {2}
|
||||||
|
_ => {1}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Instruction::BIT(bit, target) => {
|
Instruction::BIT(bit, target) => {
|
||||||
let value = self.get_target_value(target);
|
let value = self.get_target_value(target);
|
||||||
self.registers.f.zero = value >> bit & 0x1 == 0;
|
self.registers.f.zero = value >> bit & 0x1 == 0;
|
||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.half_carry = true;
|
self.registers.f.half_carry = true;
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
Instruction::CALL(condition, address) => {
|
Instruction::CALL(condition, address) => {
|
||||||
if self.check_condition(condition) {
|
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+3;
|
||||||
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;
|
self.pc = address;
|
||||||
@@ -1008,6 +1036,7 @@ impl CPU {
|
|||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.half_carry = false;
|
self.registers.f.half_carry = false;
|
||||||
self.registers.f.carry = !self.registers.f.carry;
|
self.registers.f.carry = !self.registers.f.carry;
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
Instruction::CP(target) => {
|
Instruction::CP(target) => {
|
||||||
let value = self.get_target_value(target);
|
let value = self.get_target_value(target);
|
||||||
@@ -1016,11 +1045,16 @@ impl CPU {
|
|||||||
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;
|
||||||
|
self.pc += match target {
|
||||||
|
Target::Immediate(_) => {2}
|
||||||
|
_ => {1}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Instruction::CPL => {
|
Instruction::CPL => {
|
||||||
self.registers.a = !self.registers.a;
|
self.registers.a = !self.registers.a;
|
||||||
self.registers.f.subtract = true;
|
self.registers.f.subtract = true;
|
||||||
self.registers.f.half_carry = true;
|
self.registers.f.half_carry = true;
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
Instruction::DAA => {
|
Instruction::DAA => {
|
||||||
let new_value;
|
let new_value;
|
||||||
@@ -1047,6 +1081,7 @@ impl CPU {
|
|||||||
self.registers.f.carry = did_overflow;
|
self.registers.f.carry = did_overflow;
|
||||||
self.registers.f.zero = new_value == 0;
|
self.registers.f.zero = new_value == 0;
|
||||||
self.registers.f.half_carry = false;
|
self.registers.f.half_carry = false;
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
Instruction::DEC(target) => {
|
Instruction::DEC(target) => {
|
||||||
match target {
|
match target {
|
||||||
@@ -1066,6 +1101,7 @@ impl CPU {
|
|||||||
Target::Address(_) => {}
|
Target::Address(_) => {}
|
||||||
Target::Immediate(_) => {}
|
Target::Immediate(_) => {}
|
||||||
}
|
}
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
Instruction::DECHL(register) => {
|
Instruction::DECHL(register) => {
|
||||||
let target = Target::U16Register(register);
|
let target = Target::U16Register(register);
|
||||||
@@ -1075,10 +1111,17 @@ impl CPU {
|
|||||||
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.half_carry = (new_value & 0xF) + (value & 0xF) > 0xF;
|
self.registers.f.half_carry = (new_value & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
self.pc += 1;
|
||||||
|
}
|
||||||
|
Instruction::DI => {
|
||||||
|
self.pc += 1;
|
||||||
|
}
|
||||||
|
Instruction::EI => {
|
||||||
|
self.pc += 1;
|
||||||
|
}
|
||||||
|
Instruction::HALT => {
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
Instruction::DI => {}
|
|
||||||
Instruction::EI => {}
|
|
||||||
Instruction::HALT => {todo!();}
|
|
||||||
|
|
||||||
Instruction::INC(target) => {
|
Instruction::INC(target) => {
|
||||||
match target {
|
match target {
|
||||||
@@ -1098,6 +1141,7 @@ impl CPU {
|
|||||||
Target::Address(_) => {}
|
Target::Address(_) => {}
|
||||||
Target::Immediate(_) => {}
|
Target::Immediate(_) => {}
|
||||||
}
|
}
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
Instruction::INCHL(register) => {
|
Instruction::INCHL(register) => {
|
||||||
let target = Target::U16Register(register);
|
let target = Target::U16Register(register);
|
||||||
@@ -1107,6 +1151,7 @@ impl CPU {
|
|||||||
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.half_carry = (new_value & 0xF) + (value & 0xF) > 0xF;
|
self.registers.f.half_carry = (new_value & 0xF) + (value & 0xF) > 0xF;
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
Instruction::JP(condition, address) => {
|
Instruction::JP(condition, address) => {
|
||||||
if self.check_condition(condition) {
|
if self.check_condition(condition) {
|
||||||
@@ -1119,7 +1164,7 @@ impl CPU {
|
|||||||
Instruction::JR(condition, offset) => {
|
Instruction::JR(condition, offset) => {
|
||||||
if self.check_condition(condition) {
|
if self.check_condition(condition) {
|
||||||
self.pc = if offset.is_negative() {
|
self.pc = if offset.is_negative() {
|
||||||
self.pc.wrapping_sub(offset.abs() as u16)
|
self.pc.wrapping_sub(offset.abs() as u16 - 1)
|
||||||
} else {
|
} else {
|
||||||
self.pc.wrapping_add(offset as u16)
|
self.pc.wrapping_add(offset as u16)
|
||||||
}
|
}
|
||||||
@@ -1130,94 +1175,116 @@ impl CPU {
|
|||||||
LoadTarget::CopyR8R8(dest_register, source_register) => {
|
LoadTarget::CopyR8R8(dest_register, source_register) => {
|
||||||
let value = self.get_u8_reg_value(source_register);
|
let value = self.get_u8_reg_value(source_register);
|
||||||
self.set_u8_reg_value(dest_register, value);
|
self.set_u8_reg_value(dest_register, value);
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyR8N8(dest_register, value) => {
|
LoadTarget::CopyR8N8(dest_register, value) => {
|
||||||
self.set_u8_reg_value(dest_register, value);
|
self.set_u8_reg_value(dest_register, value);
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyR16N16(dest_register, value) => {
|
LoadTarget::CopyR16N16(dest_register, value) => {
|
||||||
self.set_u16_reg_value(dest_register, value);
|
self.set_u16_reg_value(dest_register, value);
|
||||||
|
self.pc += 3;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyHLR8(source_register) => {
|
LoadTarget::CopyHLR8(source_register) => {
|
||||||
let value = self.get_u8_reg_value(source_register);
|
let value = self.get_u8_reg_value(source_register);
|
||||||
let address = self.registers.get_hl();
|
let address = self.registers.get_hl();
|
||||||
self.bus.write_byte(address, value);
|
self.bus.write_byte(address, value);
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyHLN8(value) => {
|
LoadTarget::CopyHLN8(value) => {
|
||||||
let address = self.registers.get_hl();
|
let address = self.registers.get_hl();
|
||||||
self.bus.write_byte(address, value);
|
self.bus.write_byte(address, value);
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyR8HL(dest_register) => {
|
LoadTarget::CopyR8HL(dest_register) => {
|
||||||
let address = self.registers.get_hl();
|
let address = self.registers.get_hl();
|
||||||
let value = self.bus.read_byte(address);
|
let value = self.bus.read_byte(address);
|
||||||
self.set_u8_reg_value(dest_register, value);
|
self.set_u8_reg_value(dest_register, value);
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyR16A(dest_register) => {
|
LoadTarget::CopyR16A(dest_register) => {
|
||||||
let address = self.get_u16_reg_value(dest_register);
|
let address = self.get_u16_reg_value(dest_register);
|
||||||
self.bus.write_byte(address, self.registers.a);
|
self.bus.write_byte(address, self.registers.a);
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyN16A(address) => {
|
LoadTarget::CopyN16A(address) => {
|
||||||
self.bus.write_byte(address, self.registers.a);
|
self.bus.write_byte(address, self.registers.a);
|
||||||
|
self.pc += 3;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyPortA(target) => {
|
LoadTarget::CopyPortA(target) => {
|
||||||
let offset = self.get_target_value(target);
|
let offset = self.get_target_value(target);
|
||||||
let address = 0xFF00 | offset as u16;
|
let address = 0xFF00 | offset as u16;
|
||||||
self.bus.write_byte(address, self.registers.a);
|
self.bus.write_byte(address, self.registers.a);
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyAPort(target) => {
|
LoadTarget::CopyAPort(target) => {
|
||||||
let offset = self.get_target_value(target);
|
let offset = self.get_target_value(target);
|
||||||
let address = 0xFF00 | offset as u16;
|
let address = 0xFF00 | offset as u16;
|
||||||
self.registers.a = self.bus.read_byte(address);
|
self.registers.a = self.bus.read_byte(address);
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyHN16A(address) => {
|
LoadTarget::CopyHN16A(address) => {
|
||||||
if address >= 0xFF00 {
|
if address >= 0xFF00 {
|
||||||
self.bus.write_byte(address, self.registers.a)
|
self.bus.write_byte(address, self.registers.a)
|
||||||
}
|
}
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyHCA => {
|
LoadTarget::CopyHCA => {
|
||||||
let address = 0xFF00 + self.registers.c as u16;
|
let address = 0xFF00 + self.registers.c as u16;
|
||||||
self.bus.write_byte(address, self.registers.a)
|
self.bus.write_byte(address, self.registers.a);
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyAR16(source_register) => {
|
LoadTarget::CopyAR16(source_register) => {
|
||||||
let address = self.get_u16_reg_value(source_register);
|
let address = self.get_u16_reg_value(source_register);
|
||||||
self.registers.a = self.bus.read_byte(address);
|
self.registers.a = self.bus.read_byte(address);
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyAN16(address) => {
|
LoadTarget::CopyAN16(address) => {
|
||||||
self.registers.a = self.bus.read_byte(address);
|
self.registers.a = self.bus.read_byte(address);
|
||||||
|
self.pc += 3;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyHAN16(address) => {
|
LoadTarget::CopyHAN16(address) => {
|
||||||
if address >= 0xFF00 {
|
if address >= 0xFF00 {
|
||||||
self.registers.a = self.bus.read_byte(address)
|
self.registers.a = self.bus.read_byte(address);
|
||||||
}
|
}
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyHAC => {
|
LoadTarget::CopyHAC => {
|
||||||
self.registers.a = self.bus.read_byte(0xFF00+self.registers.c as u16)
|
self.registers.a = self.bus.read_byte(0xFF00+self.registers.c as u16);
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyHLIA => {
|
LoadTarget::CopyHLIA => {
|
||||||
let address = self.registers.get_hl();
|
let address = self.registers.get_hl();
|
||||||
self.bus.write_byte(address, self.registers.a);
|
self.bus.write_byte(address, self.registers.a);
|
||||||
self.registers.set_hl(address.wrapping_add(1));
|
self.registers.set_hl(address.wrapping_add(1));
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyHLDA => {
|
LoadTarget::CopyHLDA => {
|
||||||
let address = self.registers.get_hl();
|
let address = self.registers.get_hl();
|
||||||
self.bus.write_byte(address, self.registers.a);
|
self.bus.write_byte(address, self.registers.a);
|
||||||
self.registers.set_hl(address.wrapping_sub(1));
|
self.registers.set_hl(address.wrapping_sub(1));
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyAHLI => {
|
LoadTarget::CopyAHLI => {
|
||||||
let address = self.registers.get_hl();
|
let address = self.registers.get_hl();
|
||||||
self.registers.a = self.bus.read_byte(address);
|
self.registers.a = self.bus.read_byte(address);
|
||||||
self.registers.set_hl(address.wrapping_add(1));
|
self.registers.set_hl(address.wrapping_add(1));
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyAHLD => {
|
LoadTarget::CopyAHLD => {
|
||||||
let address = self.registers.get_hl();
|
let address = self.registers.get_hl();
|
||||||
self.registers.a = self.bus.read_byte(address);
|
self.registers.a = self.bus.read_byte(address);
|
||||||
self.registers.set_hl(address.wrapping_sub(1));
|
self.registers.set_hl(address.wrapping_sub(1));
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
LoadTarget::CopySPN16(value) => {
|
LoadTarget::CopySPN16(value) => {
|
||||||
self.sp = value;
|
self.sp = value;
|
||||||
|
self.pc += 3;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyN16SP(address) => {
|
LoadTarget::CopyN16SP(address) => {
|
||||||
self.bus.write_byte(address, (0xF & self.sp) as u8);
|
self.bus.write_byte(address, (0xF & self.sp) as u8);
|
||||||
self.bus.write_byte(address + 1, (self.sp >> 8) as u8);
|
self.bus.write_byte(address + 1, (self.sp >> 8) as u8);
|
||||||
|
self.pc += 3;
|
||||||
}
|
}
|
||||||
LoadTarget::CopyHLSPE8(value) => {
|
LoadTarget::CopyHLSPE8(value) => {
|
||||||
|
|
||||||
@@ -1230,14 +1297,17 @@ impl CPU {
|
|||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.carry = (new_value & 0xFF) + (self.sp & 0xFF) > 0xFF;
|
self.registers.f.carry = (new_value & 0xFF) + (self.sp & 0xFF) > 0xFF;
|
||||||
self.registers.f.half_carry = (new_value & 0xF) + (self.sp & 0xF) > 0xF;
|
self.registers.f.half_carry = (new_value & 0xF) + (self.sp & 0xF) > 0xF;
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
LoadTarget::CopySPHL => {
|
LoadTarget::CopySPHL => {
|
||||||
self.sp = self.registers.get_hl();
|
self.sp = self.registers.get_hl();
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instruction::NOP => {}
|
Instruction::NOP => {
|
||||||
|
self.pc += 1;
|
||||||
|
}
|
||||||
Instruction::OR(target) => {
|
Instruction::OR(target) => {
|
||||||
let value = self.get_target_value(target);
|
let value = self.get_target_value(target);
|
||||||
self.registers.a = value | self.registers.a;
|
self.registers.a = value | self.registers.a;
|
||||||
@@ -1245,23 +1315,32 @@ impl CPU {
|
|||||||
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;
|
||||||
|
self.pc += match target {
|
||||||
|
Target::Immediate(_) => {2}
|
||||||
|
_ => {1}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Instruction::POP(target) => {
|
Instruction::POP(target) => {
|
||||||
let value = self.pop_stack();
|
let value = self.pop_stack();
|
||||||
self.set_u16_reg_value(target, value);
|
self.set_u16_reg_value(target, value);
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
Instruction::PUSH(target) => {
|
Instruction::PUSH(target) => {
|
||||||
let value = self.get_u16_reg_value(target);
|
let value = self.get_u16_reg_value(target);
|
||||||
self.push_stack(value);
|
self.push_stack(value);
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
Instruction::RES(bit, target) => {
|
Instruction::RES(bit, target) => {
|
||||||
let mut value = self.get_target_value(target);
|
let mut value = self.get_target_value(target);
|
||||||
value &= !(1 << bit);
|
value &= !(1 << bit);
|
||||||
self.set_target_value(target, value);
|
self.set_target_value(target, value);
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
Instruction::RET(condition) => {
|
Instruction::RET(condition) => {
|
||||||
if self.check_condition(condition) {
|
if self.check_condition(condition) {
|
||||||
self.pc = self.pop_stack();
|
self.pc = self.pop_stack();
|
||||||
|
} else {
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instruction::RETI => {
|
Instruction::RETI => {
|
||||||
@@ -1276,6 +1355,10 @@ impl CPU {
|
|||||||
self.registers.f.zero = false;
|
self.registers.f.zero = false;
|
||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.half_carry = false;
|
self.registers.f.half_carry = false;
|
||||||
|
self.pc += match self.bus.read_byte(self.pc) {
|
||||||
|
0x17 => {1}
|
||||||
|
_ => {2}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Instruction::RLC(target) => {
|
Instruction::RLC(target) => {
|
||||||
let old_value = self.get_target_value(target);
|
let old_value = self.get_target_value(target);
|
||||||
@@ -1285,6 +1368,10 @@ impl CPU {
|
|||||||
self.registers.f.zero = false;
|
self.registers.f.zero = false;
|
||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.half_carry = false;
|
self.registers.f.half_carry = false;
|
||||||
|
self.pc += match self.bus.read_byte(self.pc) {
|
||||||
|
0x07 => {1}
|
||||||
|
_ => {2}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Instruction::RR(target) => {
|
Instruction::RR(target) => {
|
||||||
let old_value = self.get_target_value(target);
|
let old_value = self.get_target_value(target);
|
||||||
@@ -1295,6 +1382,10 @@ impl CPU {
|
|||||||
self.registers.f.zero = false;
|
self.registers.f.zero = false;
|
||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.half_carry = false;
|
self.registers.f.half_carry = false;
|
||||||
|
self.pc += match self.bus.read_byte(self.pc) {
|
||||||
|
0x1F => {1}
|
||||||
|
_ => {2}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Instruction::RRC(target) => {
|
Instruction::RRC(target) => {
|
||||||
let old_value = self.get_target_value(target);
|
let old_value = self.get_target_value(target);
|
||||||
@@ -1304,6 +1395,10 @@ impl CPU {
|
|||||||
self.registers.f.zero = false;
|
self.registers.f.zero = false;
|
||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.half_carry = false;
|
self.registers.f.half_carry = false;
|
||||||
|
self.pc += match self.bus.read_byte(self.pc) {
|
||||||
|
0x0F => {1}
|
||||||
|
_ => {2}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Instruction::RST(idx) => {
|
Instruction::RST(idx) => {
|
||||||
self.push_stack(self.pc);
|
self.push_stack(self.pc);
|
||||||
@@ -1319,16 +1414,22 @@ impl CPU {
|
|||||||
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;
|
||||||
|
self.pc += match target {
|
||||||
|
Target::Immediate(_) => {2}
|
||||||
|
_ => {1}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Instruction::SCF => {
|
Instruction::SCF => {
|
||||||
self.registers.f.carry = true;
|
self.registers.f.carry = true;
|
||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.half_carry = false;
|
self.registers.f.half_carry = false;
|
||||||
|
self.pc += 1;
|
||||||
}
|
}
|
||||||
Instruction::SET(bit, target) => {
|
Instruction::SET(bit, target) => {
|
||||||
let mut value = self.get_target_value(target);
|
let mut value = self.get_target_value(target);
|
||||||
value |= 1 << bit;
|
value |= 1 << bit;
|
||||||
self.set_target_value(target, value);
|
self.set_target_value(target, value);
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
Instruction::SLA(target) => {
|
Instruction::SLA(target) => {
|
||||||
let value = self.get_target_value(target);
|
let value = self.get_target_value(target);
|
||||||
@@ -1338,6 +1439,7 @@ impl CPU {
|
|||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.carry = value & 0x80 == 0x80;
|
self.registers.f.carry = value & 0x80 == 0x80;
|
||||||
self.registers.f.half_carry = false;
|
self.registers.f.half_carry = false;
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
Instruction::SRA(target) => {
|
Instruction::SRA(target) => {
|
||||||
let value = self.get_target_value(target);
|
let value = self.get_target_value(target);
|
||||||
@@ -1347,6 +1449,7 @@ impl CPU {
|
|||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.carry = value & 0x80 == 0x80;
|
self.registers.f.carry = value & 0x80 == 0x80;
|
||||||
self.registers.f.half_carry = false;
|
self.registers.f.half_carry = false;
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
Instruction::SRL(target) => {
|
Instruction::SRL(target) => {
|
||||||
let value = self.get_target_value(target);
|
let value = self.get_target_value(target);
|
||||||
@@ -1356,9 +1459,10 @@ impl CPU {
|
|||||||
self.registers.f.subtract = false;
|
self.registers.f.subtract = false;
|
||||||
self.registers.f.carry = value & 0x1 == 0x1;
|
self.registers.f.carry = value & 0x1 == 0x1;
|
||||||
self.registers.f.half_carry = false;
|
self.registers.f.half_carry = false;
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
Instruction::STOP(_) => {
|
Instruction::STOP(_) => {
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
Instruction::SUB(target) => {
|
Instruction::SUB(target) => {
|
||||||
let value = self.get_target_value(target);
|
let value = self.get_target_value(target);
|
||||||
@@ -1368,6 +1472,10 @@ impl CPU {
|
|||||||
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;
|
||||||
|
self.pc += match target {
|
||||||
|
Target::Immediate(_) => {2}
|
||||||
|
_ => {1}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Instruction::SWAP(target) => {
|
Instruction::SWAP(target) => {
|
||||||
let value = self.get_target_value(target);
|
let value = self.get_target_value(target);
|
||||||
@@ -1377,6 +1485,7 @@ impl CPU {
|
|||||||
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;
|
||||||
|
self.pc += 2;
|
||||||
}
|
}
|
||||||
Instruction::XOR(target) => {
|
Instruction::XOR(target) => {
|
||||||
let value = self.get_target_value(target);
|
let value = self.get_target_value(target);
|
||||||
@@ -1385,6 +1494,10 @@ impl CPU {
|
|||||||
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;
|
||||||
|
self.pc += match target {
|
||||||
|
Target::Immediate(_) => {2}
|
||||||
|
_ => {1}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1402,18 +1515,14 @@ fn main() {
|
|||||||
pc:0,
|
pc:0,
|
||||||
bus:MemoryBus{
|
bus:MemoryBus{
|
||||||
memory: [0xFFu8; 0xFFFF],
|
memory: [0xFFu8; 0xFFFF],
|
||||||
gpu:GPU{ vram: Vec::with_capacity(VRAM_END-VRAM_BEGIN), tile_set: [[[TilePixelValue::Zero; 8]; 8]; 384] },
|
gpu:GPU{ vram: vec![0xFFu8;VRAM_END-VRAM_BEGIN+1], tile_set: [[[TilePixelValue::Zero; 8]; 8]; 384] },
|
||||||
rom: game_rom,
|
rom: game_rom,
|
||||||
|
boot: boot_rom,
|
||||||
},
|
},
|
||||||
sp: 0,
|
sp: 0,
|
||||||
boot_rom,
|
|
||||||
};
|
};
|
||||||
gameboy.init();
|
gameboy.init();
|
||||||
let sp = gameboy.sp;
|
loop {
|
||||||
println!("{sp:?}");
|
gameboy.execute_next_instruction()
|
||||||
let f = gameboy.next_instruction();
|
}
|
||||||
println!("{f:?}");
|
|
||||||
gameboy.execute(f);
|
|
||||||
let sp = gameboy.sp;
|
|
||||||
println!("{sp:?}");
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user