mirror of
https://github.com/FranLMSP/rmg-001.git
synced 2024-11-23 10:12:11 +00:00
RAM for cgb
This commit is contained in:
parent
d6ef80afe4
commit
c109346dcf
23
src/bus.rs
23
src/bus.rs
@ -1,6 +1,7 @@
|
|||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
use crate::utils::join_bytes;
|
use crate::utils::join_bytes;
|
||||||
use crate::rom::{ROM, load_rom};
|
use crate::rom::{ROM, load_rom};
|
||||||
|
use crate::ram::{RAM, DMGRAM, CGBRAM, WRAM_BANK_SELECT_ADDRESS};
|
||||||
use crate::ppu::{
|
use crate::ppu::{
|
||||||
PPU,
|
PPU,
|
||||||
DMA_ADDRESS,
|
DMA_ADDRESS,
|
||||||
@ -29,6 +30,7 @@ pub const HIGH_RAM: RangeInclusive<u16> = 0xFF80..=0xFFFE;
|
|||||||
pub struct Bus {
|
pub struct Bus {
|
||||||
data: [u8; 0x10000],
|
data: [u8; 0x10000],
|
||||||
pub rom: Box<dyn ROM>,
|
pub rom: Box<dyn ROM>,
|
||||||
|
pub ram: Box<dyn RAM>,
|
||||||
pub ppu: PPU,
|
pub ppu: PPU,
|
||||||
pub joypad: Joypad,
|
pub joypad: Joypad,
|
||||||
pub timer: Timer,
|
pub timer: Timer,
|
||||||
@ -51,9 +53,15 @@ impl Bus {
|
|||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
let info = rom.info().clone();
|
||||||
|
let cgb_mode = info.cgb_features() || info.cgb_only();
|
||||||
let mut bus = Self {
|
let mut bus = Self {
|
||||||
data: [0x00; 0x10000],
|
data: [0x00; 0x10000],
|
||||||
rom,
|
rom,
|
||||||
|
ram: match cgb_mode {
|
||||||
|
true => Box::new(CGBRAM::new()),
|
||||||
|
false => Box::new(DMGRAM::new()),
|
||||||
|
},
|
||||||
ppu: PPU::new(),
|
ppu: PPU::new(),
|
||||||
joypad: Joypad::new(),
|
joypad: Joypad::new(),
|
||||||
timer: Timer::new(),
|
timer: Timer::new(),
|
||||||
@ -90,6 +98,10 @@ impl Bus {
|
|||||||
pub fn read(&self, address: u16) -> u8 {
|
pub fn read(&self, address: u16) -> u8 {
|
||||||
if BANK_ZERO.contains(&address) || BANK_SWITCHABLE.contains(&address) || EXTERNAL_RAM.contains(&address) {
|
if BANK_ZERO.contains(&address) || BANK_SWITCHABLE.contains(&address) || EXTERNAL_RAM.contains(&address) {
|
||||||
return self.rom.read(address);
|
return self.rom.read(address);
|
||||||
|
} else if WORK_RAM_1.contains(&address) || WORK_RAM_2.contains(&address) || address == WRAM_BANK_SELECT_ADDRESS {
|
||||||
|
return self.ram.read(address);
|
||||||
|
} else if ECHO_RAM.contains(&address) {
|
||||||
|
return self.ram.read(WORK_RAM_1.min().unwrap() + ((address - ECHO_RAM.min().unwrap()) & 0x1FFF));
|
||||||
} else if address == INTERRUPT_ENABLE_ADDRESS || address == INTERRUPT_FLAG_ADDRESS {
|
} else if address == INTERRUPT_ENABLE_ADDRESS || address == INTERRUPT_FLAG_ADDRESS {
|
||||||
return self.interrupts.read(address);
|
return self.interrupts.read(address);
|
||||||
} else if VIDEO_RAM.contains(&address) {
|
} else if VIDEO_RAM.contains(&address) {
|
||||||
@ -121,17 +133,12 @@ impl Bus {
|
|||||||
self.rom.write(address, data);
|
self.rom.write(address, data);
|
||||||
} else if address == INTERRUPT_ENABLE_ADDRESS || address == INTERRUPT_FLAG_ADDRESS {
|
} else if address == INTERRUPT_ENABLE_ADDRESS || address == INTERRUPT_FLAG_ADDRESS {
|
||||||
self.interrupts.write(address, data);
|
self.interrupts.write(address, data);
|
||||||
} else if WORK_RAM_1.contains(&address) || WORK_RAM_2.contains(&address) {
|
} else if WORK_RAM_1.contains(&address) || WORK_RAM_2.contains(&address) || address == WRAM_BANK_SELECT_ADDRESS {
|
||||||
self.data[address as usize] = data;
|
self.ram.write(address, data);
|
||||||
// Copy to the ECHO RAM
|
|
||||||
if address <= 0xDDFF {
|
|
||||||
self.data[(ECHO_RAM.min().unwrap() + (address - WORK_RAM_1.min().unwrap())) as usize] = data;
|
|
||||||
}
|
|
||||||
} else if EXTERNAL_RAM.contains(&address) {
|
} else if EXTERNAL_RAM.contains(&address) {
|
||||||
self.rom.write(address, data);
|
self.rom.write(address, data);
|
||||||
} else if ECHO_RAM.contains(&address) {
|
} else if ECHO_RAM.contains(&address) {
|
||||||
self.data[address as usize] = data;
|
self.ram.write(WORK_RAM_1.min().unwrap() + ((address - ECHO_RAM.min().unwrap()) & 0x1FFF), data);
|
||||||
self.data[(WORK_RAM_1.min().unwrap() + (address - ECHO_RAM.min().unwrap())) as usize] = data; // Copy to the working RAM
|
|
||||||
} else if Timer::is_io_register(address) {
|
} else if Timer::is_io_register(address) {
|
||||||
self.timer.set_register(address, data);
|
self.timer.set_register(address, data);
|
||||||
} else if Sound::is_io_register(address) {
|
} else if Sound::is_io_register(address) {
|
||||||
|
@ -4,6 +4,7 @@ pub mod ppu;
|
|||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod sound;
|
pub mod sound;
|
||||||
pub mod rom;
|
pub mod rom;
|
||||||
|
pub mod ram;
|
||||||
pub mod bus;
|
pub mod bus;
|
||||||
pub mod interrupts;
|
pub mod interrupts;
|
||||||
pub mod joypad;
|
pub mod joypad;
|
||||||
|
80
src/ram.rs
Normal file
80
src/ram.rs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
pub const WRAM_BANK_SELECT_ADDRESS: u16 = 0xFF70;
|
||||||
|
|
||||||
|
pub trait RAM {
|
||||||
|
fn read(&self, address: u16) -> u8;
|
||||||
|
fn write(&mut self, address: u16, value: u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DMGRAM {
|
||||||
|
data: [u8; 4096 * 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DMGRAM {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
data: [0; 4096 * 2],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RAM for DMGRAM {
|
||||||
|
fn read(&self, address: u16) -> u8 {
|
||||||
|
if address == WRAM_BANK_SELECT_ADDRESS {
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
self.data[(address - 0xC000) as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, address: u16, value: u8) {
|
||||||
|
if address == WRAM_BANK_SELECT_ADDRESS {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.data[(address - 0xC000) as usize] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct CGBRAM {
|
||||||
|
data: [u8; 4096 * 8],
|
||||||
|
bank: u8,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CGBRAM {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
data: [0; 4096 * 8],
|
||||||
|
bank: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn switch_bank(&mut self, bank: u8) {
|
||||||
|
self.bank = bank;
|
||||||
|
if self.bank > 7 {
|
||||||
|
self.bank = 7;
|
||||||
|
} else if bank == 0 {
|
||||||
|
self.bank = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RAM for CGBRAM {
|
||||||
|
fn read(&self, address: u16) -> u8 {
|
||||||
|
if address == WRAM_BANK_SELECT_ADDRESS {
|
||||||
|
return self.bank;
|
||||||
|
}
|
||||||
|
if address <= 0xCFFF {
|
||||||
|
return self.data[(address - 0xC000) as usize];
|
||||||
|
}
|
||||||
|
self.data[((address - 0xC000) as usize) * (self.bank as usize)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, address: u16, value: u8) {
|
||||||
|
if address == WRAM_BANK_SELECT_ADDRESS {
|
||||||
|
return self.switch_bank(value);
|
||||||
|
} else if address <= 0xCFFF {
|
||||||
|
return self.data[(address - 0xC000) as usize] = value;
|
||||||
|
}
|
||||||
|
self.data[((address - 0xC000) as usize) * (self.bank as usize)] = value;
|
||||||
|
}
|
||||||
|
}
|
11
src/rom.rs
11
src/rom.rs
@ -41,6 +41,7 @@ pub fn load_rom(_filename: &str) -> std::io::Result<Box<dyn ROM>> {
|
|||||||
filename: "".to_string(),
|
filename: "".to_string(),
|
||||||
publisher: "".to_string(),
|
publisher: "".to_string(),
|
||||||
title: "".to_string(),
|
title: "".to_string(),
|
||||||
|
cgb_features: false,
|
||||||
cgb_only: false,
|
cgb_only: false,
|
||||||
sgb_features: false,
|
sgb_features: false,
|
||||||
has_ram: false,
|
has_ram: false,
|
||||||
@ -150,6 +151,7 @@ pub struct ROMInfo {
|
|||||||
filename: String,
|
filename: String,
|
||||||
publisher: String,
|
publisher: String,
|
||||||
title: String,
|
title: String,
|
||||||
|
cgb_features: bool,
|
||||||
cgb_only: bool,
|
cgb_only: bool,
|
||||||
sgb_features: bool,
|
sgb_features: bool,
|
||||||
has_ram: bool,
|
has_ram: bool,
|
||||||
@ -161,6 +163,14 @@ pub struct ROMInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ROMInfo {
|
impl ROMInfo {
|
||||||
|
pub fn cgb_features(&self) -> bool {
|
||||||
|
self.cgb_features
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cgb_only(&self) -> bool {
|
||||||
|
self.cgb_only
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_filename(&mut self, filename: String) {
|
pub fn set_filename(&mut self, filename: String) {
|
||||||
self.filename = filename;
|
self.filename = filename;
|
||||||
}
|
}
|
||||||
@ -205,6 +215,7 @@ impl ROMInfo {
|
|||||||
},
|
},
|
||||||
publisher: "".to_string(), // TODO: Extract publisher
|
publisher: "".to_string(), // TODO: Extract publisher
|
||||||
title: "".to_string(), // TODO: Extract the game title
|
title: "".to_string(), // TODO: Extract the game title
|
||||||
|
cgb_features: bytes[CGB_FLAG_ADDRESS as usize] == 0x80,
|
||||||
cgb_only: bytes[CGB_FLAG_ADDRESS as usize] == 0xC0,
|
cgb_only: bytes[CGB_FLAG_ADDRESS as usize] == 0xC0,
|
||||||
sgb_features: bytes[SGB_FLAG_ADDRESS as usize] == 0x03,
|
sgb_features: bytes[SGB_FLAG_ADDRESS as usize] == 0x03,
|
||||||
has_ram: match rom_type {
|
has_ram: match rom_type {
|
||||||
|
Loading…
Reference in New Issue
Block a user