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:
2025-05-06 16:20:23 +01:00
parent 74e86f1ab7
commit 9be93f4aa9

View File

@@ -119,12 +119,14 @@ struct CPU {
pc: u16,
bus: MemoryBus,
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_END: usize = 0x9FFF;
const CART_BEGIN: usize = 0x0000;
const CART_END: usize = 0x7FFF;
struct GPU { vram: Vec<u8>, tile_set: [[[TilePixelValue; 8]; 8]; 384] }
#[derive(Copy, Clone)]
enum TilePixelValue { Three, Two, One, Zero }
@@ -134,7 +136,7 @@ impl GPU {
self.vram[address]
}
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
// so we can just return.
if index >= 0x1800 { return }
@@ -199,6 +201,7 @@ struct MemoryBus {
memory: [u8; 0xFFFF],
gpu: GPU,
rom: GameRom,
boot: Vec<u8>,
}
impl MemoryBus {
fn read_byte(&self, address: u16) -> u8 {
@@ -207,8 +210,15 @@ impl MemoryBus {
VRAM_BEGIN ..= VRAM_END => {
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)}
_ => self.memory[address as usize]
_ => self.memory[address]
}
}
fn write_byte(&mut self, address: u16, value: u8) {
@@ -334,12 +344,7 @@ impl CPU {
let l = self.bus.memory.len();
println!("{l}");
println!("CPU init");
// println!("Boot ROM: {:02X?}", self.boot_rom);
for (address, byte) in self.boot_rom.iter().enumerate() {
self.bus.write_byte(address as u16, *byte);
}
// println!("Game ROM: {:02X?}", self.game_rom);
self.bus.write_byte(0xFF50, 0x00);
}
fn check_condition(&self, condition: Condition) -> bool {
match condition {
@@ -942,6 +947,14 @@ impl CPU {
_ => { 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) {
match instruction {
Instruction::ADC(target) => {
@@ -953,6 +966,10 @@ impl CPU {
self.registers.f.subtract = false;
self.registers.f.carry = did_overflow;
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
self.pc += match target {
Target::Immediate(_) => {2}
_ => {1}
};
}
Instruction::ADD(target) => {
let value = self.get_target_value(target);
@@ -962,6 +979,10 @@ impl CPU {
self.registers.f.subtract = false;
self.registers.f.carry = did_overflow;
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
self.pc += match target {
Target::Immediate(_) => {2}
_ => {1}
};
}
Instruction::ADDHL(target) => {
let value = self.get_u16_reg_value(target);
@@ -971,6 +992,7 @@ impl CPU {
self.registers.f.subtract = false;
self.registers.f.carry = did_overflow;
self.registers.f.half_carry = (new_value & 0xFF) + (value & 0xFF) > 0xFF;
self.pc += 1;
}
Instruction::ADDSP(value) => {
let offset = (value as i16) as u16;
@@ -980,6 +1002,7 @@ impl CPU {
self.registers.f.subtract = false;
self.registers.f.carry = did_overflow;
self.registers.f.half_carry = (new_value & 0xFF) + (offset & 0xFF) > 0xFF;
self.pc += 2;
}
Instruction::AND(target) => {
let value = self.get_target_value(target);
@@ -988,17 +1011,22 @@ impl CPU {
self.registers.f.subtract = false;
self.registers.f.carry = false;
self.registers.f.half_carry = true;
self.pc += match target {
Target::Immediate(_) => {2}
_ => {1}
};
}
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;
self.pc += 2;
}
Instruction::CALL(condition, address) => {
if self.check_condition(condition) {
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, (pc & 0xFF) as u8);
self.pc = address;
@@ -1008,6 +1036,7 @@ impl CPU {
self.registers.f.subtract = false;
self.registers.f.half_carry = false;
self.registers.f.carry = !self.registers.f.carry;
self.pc += 1;
}
Instruction::CP(target) => {
let value = self.get_target_value(target);
@@ -1016,11 +1045,16 @@ impl CPU {
self.registers.f.subtract = true;
self.registers.f.carry = did_overflow;
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
self.pc += match target {
Target::Immediate(_) => {2}
_ => {1}
};
}
Instruction::CPL => {
self.registers.a = !self.registers.a;
self.registers.f.subtract = true;
self.registers.f.half_carry = true;
self.pc += 1;
}
Instruction::DAA => {
let new_value;
@@ -1047,6 +1081,7 @@ impl CPU {
self.registers.f.carry = did_overflow;
self.registers.f.zero = new_value == 0;
self.registers.f.half_carry = false;
self.pc += 1;
}
Instruction::DEC(target) => {
match target {
@@ -1066,6 +1101,7 @@ impl CPU {
Target::Address(_) => {}
Target::Immediate(_) => {}
}
self.pc += 1;
}
Instruction::DECHL(register) => {
let target = Target::U16Register(register);
@@ -1075,10 +1111,17 @@ impl CPU {
self.registers.f.zero = new_value == 0;
self.registers.f.subtract = true;
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) => {
match target {
@@ -1098,6 +1141,7 @@ impl CPU {
Target::Address(_) => {}
Target::Immediate(_) => {}
}
self.pc += 1;
}
Instruction::INCHL(register) => {
let target = Target::U16Register(register);
@@ -1107,6 +1151,7 @@ impl CPU {
self.registers.f.zero = new_value == 0;
self.registers.f.subtract = true;
self.registers.f.half_carry = (new_value & 0xF) + (value & 0xF) > 0xF;
self.pc += 1;
}
Instruction::JP(condition, address) => {
if self.check_condition(condition) {
@@ -1119,7 +1164,7 @@ impl CPU {
Instruction::JR(condition, offset) => {
if self.check_condition(condition) {
self.pc = if offset.is_negative() {
self.pc.wrapping_sub(offset.abs() as u16)
self.pc.wrapping_sub(offset.abs() as u16 - 1)
} else {
self.pc.wrapping_add(offset as u16)
}
@@ -1130,94 +1175,116 @@ impl CPU {
LoadTarget::CopyR8R8(dest_register, source_register) => {
let value = self.get_u8_reg_value(source_register);
self.set_u8_reg_value(dest_register, value);
self.pc += 1;
}
LoadTarget::CopyR8N8(dest_register, value) => {
self.set_u8_reg_value(dest_register, value);
self.pc += 2;
}
LoadTarget::CopyR16N16(dest_register, value) => {
self.set_u16_reg_value(dest_register, value);
self.pc += 3;
}
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);
self.pc += 1;
}
LoadTarget::CopyHLN8(value) => {
let address = self.registers.get_hl();
self.bus.write_byte(address, value);
self.pc += 2;
}
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);
self.pc += 1;
}
LoadTarget::CopyR16A(dest_register) => {
let address = self.get_u16_reg_value(dest_register);
self.bus.write_byte(address, self.registers.a);
self.pc += 1;
}
LoadTarget::CopyN16A(address) => {
self.bus.write_byte(address, self.registers.a);
self.pc += 3;
}
LoadTarget::CopyPortA(target) => {
let offset = self.get_target_value(target);
let address = 0xFF00 | offset as u16;
self.bus.write_byte(address, self.registers.a);
self.pc += 2;
}
LoadTarget::CopyAPort(target) => {
let offset = self.get_target_value(target);
let address = 0xFF00 | offset as u16;
self.registers.a = self.bus.read_byte(address);
self.pc += 2;
}
LoadTarget::CopyHN16A(address) => {
if address >= 0xFF00 {
self.bus.write_byte(address, self.registers.a)
}
self.pc += 2;
}
LoadTarget::CopyHCA => {
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) => {
let address = self.get_u16_reg_value(source_register);
self.registers.a = self.bus.read_byte(address);
self.pc += 1;
}
LoadTarget::CopyAN16(address) => {
self.registers.a = self.bus.read_byte(address);
self.pc += 3;
}
LoadTarget::CopyHAN16(address) => {
if address >= 0xFF00 {
self.registers.a = self.bus.read_byte(address)
self.registers.a = self.bus.read_byte(address);
}
self.pc += 2;
}
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 => {
let address = self.registers.get_hl();
self.bus.write_byte(address, self.registers.a);
self.registers.set_hl(address.wrapping_add(1));
self.pc += 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));
self.pc += 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));
self.pc += 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));
self.pc += 1;
}
LoadTarget::CopySPN16(value) => {
self.sp = value;
self.pc += 3;
}
LoadTarget::CopyN16SP(address) => {
self.bus.write_byte(address, (0xF & self.sp) as u8);
self.bus.write_byte(address + 1, (self.sp >> 8) as u8);
self.pc += 3;
}
LoadTarget::CopyHLSPE8(value) => {
@@ -1230,14 +1297,17 @@ impl CPU {
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;
self.pc += 2;
}
LoadTarget::CopySPHL => {
self.sp = self.registers.get_hl();
self.pc += 1;
}
}
}
Instruction::NOP => {}
Instruction::NOP => {
self.pc += 1;
}
Instruction::OR(target) => {
let value = self.get_target_value(target);
self.registers.a = value | self.registers.a;
@@ -1245,23 +1315,32 @@ impl CPU {
self.registers.f.subtract = false;
self.registers.f.carry = false;
self.registers.f.half_carry = false;
self.pc += match target {
Target::Immediate(_) => {2}
_ => {1}
};
}
Instruction::POP(target) => {
let value = self.pop_stack();
self.set_u16_reg_value(target, value);
self.pc += 1;
}
Instruction::PUSH(target) => {
let value = self.get_u16_reg_value(target);
self.push_stack(value);
self.pc += 1;
}
Instruction::RES(bit, target) => {
let mut value = self.get_target_value(target);
value &= !(1 << bit);
self.set_target_value(target, value);
self.pc += 2;
}
Instruction::RET(condition) => {
if self.check_condition(condition) {
self.pc = self.pop_stack();
} else {
self.pc += 1;
}
}
Instruction::RETI => {
@@ -1276,6 +1355,10 @@ impl CPU {
self.registers.f.zero = false;
self.registers.f.subtract = false;
self.registers.f.half_carry = false;
self.pc += match self.bus.read_byte(self.pc) {
0x17 => {1}
_ => {2}
}
}
Instruction::RLC(target) => {
let old_value = self.get_target_value(target);
@@ -1285,6 +1368,10 @@ impl CPU {
self.registers.f.zero = false;
self.registers.f.subtract = false;
self.registers.f.half_carry = false;
self.pc += match self.bus.read_byte(self.pc) {
0x07 => {1}
_ => {2}
}
}
Instruction::RR(target) => {
let old_value = self.get_target_value(target);
@@ -1295,6 +1382,10 @@ impl CPU {
self.registers.f.zero = false;
self.registers.f.subtract = false;
self.registers.f.half_carry = false;
self.pc += match self.bus.read_byte(self.pc) {
0x1F => {1}
_ => {2}
}
}
Instruction::RRC(target) => {
let old_value = self.get_target_value(target);
@@ -1304,6 +1395,10 @@ impl CPU {
self.registers.f.zero = false;
self.registers.f.subtract = false;
self.registers.f.half_carry = false;
self.pc += match self.bus.read_byte(self.pc) {
0x0F => {1}
_ => {2}
}
}
Instruction::RST(idx) => {
self.push_stack(self.pc);
@@ -1319,16 +1414,22 @@ impl CPU {
self.registers.f.subtract = true;
self.registers.f.carry = did_overflow;
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
self.pc += match target {
Target::Immediate(_) => {2}
_ => {1}
};
}
Instruction::SCF => {
self.registers.f.carry = true;
self.registers.f.subtract = false;
self.registers.f.half_carry = false;
self.pc += 1;
}
Instruction::SET(bit, target) => {
let mut value = self.get_target_value(target);
value |= 1 << bit;
self.set_target_value(target, value);
self.pc += 2;
}
Instruction::SLA(target) => {
let value = self.get_target_value(target);
@@ -1338,6 +1439,7 @@ impl CPU {
self.registers.f.subtract = false;
self.registers.f.carry = value & 0x80 == 0x80;
self.registers.f.half_carry = false;
self.pc += 2;
}
Instruction::SRA(target) => {
let value = self.get_target_value(target);
@@ -1347,6 +1449,7 @@ impl CPU {
self.registers.f.subtract = false;
self.registers.f.carry = value & 0x80 == 0x80;
self.registers.f.half_carry = false;
self.pc += 2;
}
Instruction::SRL(target) => {
let value = self.get_target_value(target);
@@ -1356,9 +1459,10 @@ impl CPU {
self.registers.f.subtract = false;
self.registers.f.carry = value & 0x1 == 0x1;
self.registers.f.half_carry = false;
self.pc += 2;
}
Instruction::STOP(_) => {
self.pc += 2;
}
Instruction::SUB(target) => {
let value = self.get_target_value(target);
@@ -1368,6 +1472,10 @@ impl CPU {
self.registers.f.subtract = true;
self.registers.f.carry = did_overflow;
self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
self.pc += match target {
Target::Immediate(_) => {2}
_ => {1}
};
}
Instruction::SWAP(target) => {
let value = self.get_target_value(target);
@@ -1377,6 +1485,7 @@ impl CPU {
self.registers.f.subtract = false;
self.registers.f.carry = false;
self.registers.f.half_carry = false;
self.pc += 2;
}
Instruction::XOR(target) => {
let value = self.get_target_value(target);
@@ -1385,6 +1494,10 @@ impl CPU {
self.registers.f.subtract = false;
self.registers.f.carry = false;
self.registers.f.half_carry = false;
self.pc += match target {
Target::Immediate(_) => {2}
_ => {1}
};
}
}
}
@@ -1402,18 +1515,14 @@ fn main() {
pc:0,
bus:MemoryBus{
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,
boot: boot_rom,
},
sp: 0,
boot_rom,
};
gameboy.init();
let sp = gameboy.sp;
println!("{sp:?}");
let f = gameboy.next_instruction();
println!("{f:?}");
gameboy.execute(f);
let sp = gameboy.sp;
println!("{sp:?}");
loop {
gameboy.execute_next_instruction()
}
}