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] = [
(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);
......
......@@ -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) {
......
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);
}
}
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