From ddc63f98b2d2b293c1b50332af24835f97fba575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com> Date: Tue, 28 Jun 2022 23:02:53 +0100 Subject: [PATCH] feat: better memory mapping --- src/cpu.rs | 79 ++++++++++++++++++++++++++++++++++++++++++++----- src/gb.rs | 3 +- src/mmu.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 155 insertions(+), 14 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index d663cdf8..a28049fd 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -28,7 +28,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [ (nop, 4, "NOP"), (nop, 4, "NOP"), (nop, 4, "NOP"), - (nop, 4, "NOP"), + (rla, 4, "RLA"), (nop, 4, "NOP"), (nop, 4, "NOP"), (ld_a_mde, 8, "LD A, [DE]"), @@ -208,8 +208,8 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [ (nop, 4, "NOP"), (nop, 4, "NOP"), // 0xc opcodes - (nop, 4, "NOP"), - (nop, 4, "NOP"), + (ret_nz, 8, "RET NZ"), + (pop_bc, 12, "POP BC"), (nop, 4, "NOP"), (nop, 4, "NOP"), (nop, 4, "NOP"), @@ -297,7 +297,7 @@ pub const BITWISE: [(fn(&mut Cpu), u8, &'static str); 176] = [ (nop, 4, "NOP"), // 0x1 opcodes (nop, 4, "NOP"), - (nop, 4, "NOP"), + (rl_c, 8, "RL C"), (nop, 4, "NOP"), (nop, 4, "NOP"), (nop, 4, "NOP"), @@ -514,9 +514,10 @@ impl Cpu { let mut opcode = self.mmu.read(self.pc); self.pc = self.pc.wrapping_add(1); + let is_prefix = opcode == PREFIX; let instruction: &(fn(&mut Cpu), u8, &str); - if opcode == PREFIX { + if is_prefix { opcode = self.mmu.read(self.pc); self.pc = self.pc.wrapping_add(1); instruction = &BITWISE[opcode as usize]; @@ -526,7 +527,10 @@ impl Cpu { let (instruction_fn, instruction_size, instruction_str) = instruction; - println!("{}\t(0x{:02x})\t${:04x}", instruction_str, opcode, pc); + println!( + "{}\t(0x{:02x})\t${:04x} {}", + instruction_str, opcode, pc, is_prefix + ); instruction_fn(self); self.ticks = self.ticks.wrapping_add(*instruction_size as u32); @@ -614,7 +618,7 @@ impl Cpu { } #[inline(always)] - fn push_byte(&mut self, byte: u8){ + fn push_byte(&mut self, byte: u8) { self.sp -= 1; self.mmu.write(self.sp, byte); } @@ -625,6 +629,19 @@ impl Cpu { self.push_byte(word as u8); } + #[inline(always)] + fn pop_byte(&mut self) -> u8 { + let byte = self.mmu.read(self.sp); + self.sp += 1; + byte + } + + #[inline(always)] + fn pop_word(&mut self) -> u16 { + let word = self.pop_byte() as u16 | ((self.pop_byte() as u16) << 8); + word + } + #[inline(always)] fn get_zero(&self) -> bool { self.zero @@ -748,6 +765,18 @@ fn ld_de_u16(cpu: &mut Cpu) { cpu.set_de(word); } +fn rla(cpu: &mut Cpu) { + let carry = cpu.get_carry(); + + cpu.set_carry(cpu.a & 0x80 == 0x80); + + cpu.a = cpu.a << 1 | carry as u8; + + cpu.set_sub(false); + cpu.set_zero(false); + cpu.set_half_carry(false); +} + fn ld_a_mde(cpu: &mut Cpu) { let byte = cpu.mmu.read(cpu.de()); cpu.a = byte; @@ -796,6 +825,20 @@ fn xor_a_a(cpu: &mut Cpu) { cpu.set_carry(false); } +fn ret_nz(cpu: &mut Cpu) { + if cpu.get_zero() { + return; + } + + cpu.pc = cpu.pop_word(); + cpu.ticks = cpu.ticks.wrapping_add(12); +} + +fn pop_bc(cpu: &mut Cpu) { + let word = cpu.pop_word(); + cpu.set_bc(word); +} + fn push_bc(cpu: &mut Cpu) { cpu.push_word(cpu.bc()); } @@ -815,10 +858,31 @@ fn ld_mff00c_a(cpu: &mut Cpu) { cpu.mmu.write(0xff0c + cpu.c as u16, cpu.a); } +fn rl_c(cpu: &mut Cpu) { + cpu.c = rl(cpu, cpu.c); +} + fn bit_7_h(cpu: &mut Cpu) { bit_h(cpu, 7); } +/// Helper function that rotates (shifts) the given +/// byte (probably from a register) and updates the +/// proper flag registers. +fn rl(cpu: &mut Cpu, byte: u8) -> u8 { + let carry = cpu.get_carry(); + + cpu.set_carry(byte & 0x80 == 0x80); + + let result = (byte << 1) | carry as u8; + + cpu.set_sub(false); + cpu.set_zero(result == 0); + cpu.set_half_carry(false); + + result +} + /// Helper function to test one bit in a u8. /// Returns true if bit is 0. fn bit_zero(val: u8, bit: u8) -> bool { @@ -826,7 +890,6 @@ fn bit_zero(val: u8, bit: u8) -> bool { } fn bit_h(cpu: &mut Cpu, bit: u8) { - println!("{}", cpu.h); cpu.set_sub(false); cpu.set_zero(bit_zero(cpu.h, bit)); cpu.set_half_carry(true); diff --git a/src/gb.rs b/src/gb.rs index 8b2a4a9b..0d1da401 100644 --- a/src/gb.rs +++ b/src/gb.rs @@ -26,8 +26,7 @@ impl GameBoy { pub fn load_boot(&mut self, path: &str) { let data = read_file(path); - self.cpu.mmu().write_buffer(0x0000, &data); - println!("LOADED BOOT") + self.cpu.mmu().write_boot(0x0000, &data); } pub fn load_boot_default(&mut self) { diff --git a/src/mmu.rs b/src/mmu.rs index d2adbdd7..3cd912f1 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -1,29 +1,103 @@ use crate::ppu::Ppu; +pub const BIOS_SIZE: usize = 256; +pub const ROM_SIZE: usize = 32768; pub const RAM_SIZE: usize = 8192; +pub const ERAM_SIZE: usize = 8192; +pub const HRAM_SIZE: usize = 128; pub struct Mmu { ppu: Ppu, + boot_active: bool, + boot: [u8; BIOS_SIZE], + rom: [u8; ROM_SIZE], ram: [u8; RAM_SIZE], + eram: [u8; RAM_SIZE], + hram: [u8; HRAM_SIZE], } impl Mmu { pub fn new(ppu: Ppu) -> Mmu { Mmu { ppu: ppu, + boot_active: true, + boot: [0u8; BIOS_SIZE], + rom: [0u8; ROM_SIZE], ram: [0u8; RAM_SIZE], + eram: [0u8; ERAM_SIZE], + hram: [0u8; HRAM_SIZE], } } pub fn read(&self, addr: u16) -> u8 { - self.ram[addr as usize] + match addr & 0xf000 { + // BIOS + 0x0000 => { + //@todo we still need to control if we're reading from boot + // if(MMU._inboot) + // { + // if(addr < 0x0100) + // return MMU._boot[addr]; + // else if(Z80._r.pc == 0x0100) + // MMU._inboot = 0; + //} + //return MMU._rom[addr]; + if self.boot_active { + if addr < 0x0100 { + return self.boot[addr as usize]; + } + //else if self @todo implementar isto + } + self.rom[addr as usize] + } + // ROM0 + 0x1000 | 0x2000 | 0x3000 => self.rom[addr as usize], + // ROM1 (unbanked) (16k) + 0x4000 | 0x5000 | 0x6000 | 0x7000 => self.rom[addr as usize], + // Graphics: VRAM (8k) + 0x8000 | 0x9000 => { + println!("READING FROM VRAM"); + self.ppu.vram[(addr & 0x1fff) as usize] + } + // External RAM (8k) + 0xa000 | 0xb000 => { + println!("READING FROM ERAM"); + self.eram[(addr & 0x1fff) as usize] + } + // Working RAM (8k) + 0xc000 | 0xd000 => self.ram[(addr & 0x1fff) as usize], + // Working RAM shadow + 0xe000 => { + println!("READING FROM RAM Shadow"); + self.ram[(addr & 0x1fff) as usize] + } + // Working RAM shadow, I/O, Zero-page RAM + 0xf000 => match addr & 0x0f00 { + 0x000 | 0x100 | 0x200 | 0x300 | 0x400 | 0x500 | 0x600 | 0x700 | 0x800 | 0x900 + | 0xa00 | 0xb00 | 0xc00 | 0xd00 => self.ram[(addr & 0x1fff) as usize], + 0xe00 => { + println!("READING FROM GPU OAM - NOT IMPLEMENTED"); + 0x00 + } + 0xf00 => { + if addr >= 0xff80 { + self.ram[(addr & 0x7f) as usize] + } else { + println!("WRITING TO IO control"); + 0x00 + } + } + addr => panic!("Reading from unknown location 0x{:04x}", addr), + }, + addr => panic!("Reading from unknown location 0x{:04x}", addr), + } } pub fn write(&mut self, addr: u16, value: u8) { match addr & 0xf000 { - // BIOS + // BOOT 0x0000 => { - println!("WRITING to BIOS") + println!("WRITING to BOOT") } // ROM0 0x1000 | 0x2000 | 0x3000 => { @@ -64,6 +138,7 @@ impl Mmu { 0xf00 => { if addr >= 0xff80 { println!("WRITING TO Zero page"); + self.hram[(addr & 0x7f) as usize] = value; } else { println!("WRITING TO IO control"); } @@ -74,7 +149,11 @@ impl Mmu { } } - pub fn write_buffer(&mut self, addr: u16, buffer: &[u8]) { + pub fn write_boot(&mut self, addr: u16, buffer: &[u8]) { + self.boot[addr as usize..addr as usize + buffer.len()].clone_from_slice(buffer); + } + + pub fn write_ram(&mut self, addr: u16, buffer: &[u8]) { self.ram[addr as usize..addr as usize + buffer.len()].clone_from_slice(buffer); } } -- GitLab