Skip to content
Snippets Groups Projects
Verified Commit ddc63f98 authored by João Magalhães's avatar João Magalhães :rocket:
Browse files

feat: better memory mapping

parent 72340fc8
No related branches found
No related tags found
No related merge requests found
...@@ -28,7 +28,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [ ...@@ -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"),
(nop, 4, "NOP"), (nop, 4, "NOP"),
(nop, 4, "NOP"), (rla, 4, "RLA"),
(nop, 4, "NOP"), (nop, 4, "NOP"),
(nop, 4, "NOP"), (nop, 4, "NOP"),
(ld_a_mde, 8, "LD A, [DE]"), (ld_a_mde, 8, "LD A, [DE]"),
...@@ -208,8 +208,8 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [ ...@@ -208,8 +208,8 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
(nop, 4, "NOP"), (nop, 4, "NOP"),
(nop, 4, "NOP"), (nop, 4, "NOP"),
// 0xc opcodes // 0xc opcodes
(nop, 4, "NOP"), (ret_nz, 8, "RET NZ"),
(nop, 4, "NOP"), (pop_bc, 12, "POP BC"),
(nop, 4, "NOP"), (nop, 4, "NOP"),
(nop, 4, "NOP"), (nop, 4, "NOP"),
(nop, 4, "NOP"), (nop, 4, "NOP"),
...@@ -297,7 +297,7 @@ pub const BITWISE: [(fn(&mut Cpu), u8, &'static str); 176] = [ ...@@ -297,7 +297,7 @@ pub const BITWISE: [(fn(&mut Cpu), u8, &'static str); 176] = [
(nop, 4, "NOP"), (nop, 4, "NOP"),
// 0x1 opcodes // 0x1 opcodes
(nop, 4, "NOP"), (nop, 4, "NOP"),
(nop, 4, "NOP"), (rl_c, 8, "RL C"),
(nop, 4, "NOP"), (nop, 4, "NOP"),
(nop, 4, "NOP"), (nop, 4, "NOP"),
(nop, 4, "NOP"), (nop, 4, "NOP"),
...@@ -514,9 +514,10 @@ impl Cpu { ...@@ -514,9 +514,10 @@ impl Cpu {
let mut opcode = self.mmu.read(self.pc); let mut opcode = self.mmu.read(self.pc);
self.pc = self.pc.wrapping_add(1); self.pc = self.pc.wrapping_add(1);
let is_prefix = opcode == PREFIX;
let instruction: &(fn(&mut Cpu), u8, &str); let instruction: &(fn(&mut Cpu), u8, &str);
if opcode == PREFIX { if is_prefix {
opcode = self.mmu.read(self.pc); opcode = self.mmu.read(self.pc);
self.pc = self.pc.wrapping_add(1); self.pc = self.pc.wrapping_add(1);
instruction = &BITWISE[opcode as usize]; instruction = &BITWISE[opcode as usize];
...@@ -526,7 +527,10 @@ impl Cpu { ...@@ -526,7 +527,10 @@ impl Cpu {
let (instruction_fn, instruction_size, instruction_str) = instruction; 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); instruction_fn(self);
self.ticks = self.ticks.wrapping_add(*instruction_size as u32); self.ticks = self.ticks.wrapping_add(*instruction_size as u32);
...@@ -614,7 +618,7 @@ impl Cpu { ...@@ -614,7 +618,7 @@ impl Cpu {
} }
#[inline(always)] #[inline(always)]
fn push_byte(&mut self, byte: u8){ fn push_byte(&mut self, byte: u8) {
self.sp -= 1; self.sp -= 1;
self.mmu.write(self.sp, byte); self.mmu.write(self.sp, byte);
} }
...@@ -625,6 +629,19 @@ impl Cpu { ...@@ -625,6 +629,19 @@ impl Cpu {
self.push_byte(word as u8); 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)] #[inline(always)]
fn get_zero(&self) -> bool { fn get_zero(&self) -> bool {
self.zero self.zero
...@@ -748,6 +765,18 @@ fn ld_de_u16(cpu: &mut Cpu) { ...@@ -748,6 +765,18 @@ fn ld_de_u16(cpu: &mut Cpu) {
cpu.set_de(word); 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) { fn ld_a_mde(cpu: &mut Cpu) {
let byte = cpu.mmu.read(cpu.de()); let byte = cpu.mmu.read(cpu.de());
cpu.a = byte; cpu.a = byte;
...@@ -796,6 +825,20 @@ fn xor_a_a(cpu: &mut Cpu) { ...@@ -796,6 +825,20 @@ fn xor_a_a(cpu: &mut Cpu) {
cpu.set_carry(false); 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) { fn push_bc(cpu: &mut Cpu) {
cpu.push_word(cpu.bc()); cpu.push_word(cpu.bc());
} }
...@@ -815,10 +858,31 @@ fn ld_mff00c_a(cpu: &mut Cpu) { ...@@ -815,10 +858,31 @@ fn ld_mff00c_a(cpu: &mut Cpu) {
cpu.mmu.write(0xff0c + cpu.c as u16, cpu.a); 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) { fn bit_7_h(cpu: &mut Cpu) {
bit_h(cpu, 7); 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. /// Helper function to test one bit in a u8.
/// Returns true if bit is 0. /// Returns true if bit is 0.
fn bit_zero(val: u8, bit: u8) -> bool { fn bit_zero(val: u8, bit: u8) -> bool {
...@@ -826,7 +890,6 @@ 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) { fn bit_h(cpu: &mut Cpu, bit: u8) {
println!("{}", cpu.h);
cpu.set_sub(false); cpu.set_sub(false);
cpu.set_zero(bit_zero(cpu.h, bit)); cpu.set_zero(bit_zero(cpu.h, bit));
cpu.set_half_carry(true); cpu.set_half_carry(true);
......
...@@ -26,8 +26,7 @@ impl GameBoy { ...@@ -26,8 +26,7 @@ impl GameBoy {
pub fn load_boot(&mut self, path: &str) { pub fn load_boot(&mut self, path: &str) {
let data = read_file(path); let data = read_file(path);
self.cpu.mmu().write_buffer(0x0000, &data); self.cpu.mmu().write_boot(0x0000, &data);
println!("LOADED BOOT")
} }
pub fn load_boot_default(&mut self) { pub fn load_boot_default(&mut self) {
......
use crate::ppu::Ppu; use crate::ppu::Ppu;
pub const BIOS_SIZE: usize = 256;
pub const ROM_SIZE: usize = 32768;
pub const RAM_SIZE: usize = 8192; pub const RAM_SIZE: usize = 8192;
pub const ERAM_SIZE: usize = 8192;
pub const HRAM_SIZE: usize = 128;
pub struct Mmu { pub struct Mmu {
ppu: Ppu, ppu: Ppu,
boot_active: bool,
boot: [u8; BIOS_SIZE],
rom: [u8; ROM_SIZE],
ram: [u8; RAM_SIZE], ram: [u8; RAM_SIZE],
eram: [u8; RAM_SIZE],
hram: [u8; HRAM_SIZE],
} }
impl Mmu { impl Mmu {
pub fn new(ppu: Ppu) -> Mmu { pub fn new(ppu: Ppu) -> Mmu {
Mmu { Mmu {
ppu: ppu, ppu: ppu,
boot_active: true,
boot: [0u8; BIOS_SIZE],
rom: [0u8; ROM_SIZE],
ram: [0u8; RAM_SIZE], ram: [0u8; RAM_SIZE],
eram: [0u8; ERAM_SIZE],
hram: [0u8; HRAM_SIZE],
} }
} }
pub fn read(&self, addr: u16) -> u8 { 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) { pub fn write(&mut self, addr: u16, value: u8) {
match addr & 0xf000 { match addr & 0xf000 {
// BIOS // BOOT
0x0000 => { 0x0000 => {
println!("WRITING to BIOS") println!("WRITING to BOOT")
} }
// ROM0 // ROM0
0x1000 | 0x2000 | 0x3000 => { 0x1000 | 0x2000 | 0x3000 => {
...@@ -64,6 +138,7 @@ impl Mmu { ...@@ -64,6 +138,7 @@ impl Mmu {
0xf00 => { 0xf00 => {
if addr >= 0xff80 { if addr >= 0xff80 {
println!("WRITING TO Zero page"); println!("WRITING TO Zero page");
self.hram[(addr & 0x7f) as usize] = value;
} else { } else {
println!("WRITING TO IO control"); println!("WRITING TO IO control");
} }
...@@ -74,7 +149,11 @@ impl Mmu { ...@@ -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); self.ram[addr as usize..addr as usize + buffer.len()].clone_from_slice(buffer);
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment