2021-10-16 00:18:00 +00:00
|
|
|
use crate::utils::{join_bytes};
|
2021-10-14 00:38:37 +00:00
|
|
|
use crate::rom::ROM;
|
|
|
|
|
2021-10-13 17:56:00 +00:00
|
|
|
pub enum MemoryMap {
|
|
|
|
BankZero,
|
|
|
|
BankSwitchable,
|
|
|
|
VideoRAM,
|
|
|
|
ExternalRAM,
|
|
|
|
WorkRAM1,
|
|
|
|
WorkRAM2,
|
|
|
|
EchoRAM,
|
|
|
|
SpriteAttributeTable,
|
|
|
|
NotUsable,
|
|
|
|
IORegisters,
|
|
|
|
HighRAM,
|
|
|
|
InterruptEnableRegister,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MemoryMap {
|
|
|
|
pub fn get_map(address: u16) -> Self {
|
2021-10-14 00:38:37 +00:00
|
|
|
match address {
|
|
|
|
0x0000..=0x3FFF => Self::BankZero,
|
|
|
|
0x4000..=0x7FFF => Self::BankSwitchable,
|
|
|
|
0x8000..=0x9FFF => Self::VideoRAM,
|
|
|
|
0xA000..=0xBFFF => Self::ExternalRAM,
|
|
|
|
0xC000..=0xCFFF => Self::WorkRAM1,
|
|
|
|
0xD000..=0xDFFF => Self::WorkRAM2,
|
|
|
|
0xE000..=0xFDFF => Self::EchoRAM, // Mirror of C000~DDFF
|
|
|
|
0xFE00..=0xFE9F => Self::SpriteAttributeTable,
|
|
|
|
0xFEA0..=0xFEFF => Self::NotUsable,
|
|
|
|
0xFF00..=0xFF7F => Self::IORegisters,
|
|
|
|
0xFF80..=0xFFFE => Self::HighRAM,
|
|
|
|
0xFFFF => Self::InterruptEnableRegister,
|
|
|
|
_ => Self::BankZero,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Bus {
|
|
|
|
game_rom: ROM,
|
2021-10-14 18:25:20 +00:00
|
|
|
data: [u8; 0x10000],
|
2021-10-14 00:38:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Bus {
|
|
|
|
pub fn new() -> Self {
|
2021-10-19 16:04:52 +00:00
|
|
|
let game_rom = match ROM::load_file("roms/cpu_instrs_individual/02-interrupts.gb".to_string()) {
|
2021-10-14 00:38:37 +00:00
|
|
|
Ok(rom) => rom,
|
|
|
|
_ => ROM::from_bytes(&[0; 0xFFFF])
|
|
|
|
};
|
|
|
|
Self {
|
2021-10-17 17:29:02 +00:00
|
|
|
data: [0xFF; 0x10000],
|
2021-10-14 00:38:37 +00:00
|
|
|
game_rom,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn read(&self, address: u16) -> u8 {
|
|
|
|
match MemoryMap::get_map(address) {
|
|
|
|
MemoryMap::BankZero => self.game_rom.read(address),
|
2021-10-14 18:25:20 +00:00
|
|
|
MemoryMap::BankSwitchable => self.game_rom.read(address),
|
2021-10-17 17:02:33 +00:00
|
|
|
MemoryMap::WorkRAM1 | MemoryMap::WorkRAM2 | MemoryMap::InterruptEnableRegister => self.data[address as usize],
|
|
|
|
MemoryMap::IORegisters => match address {
|
|
|
|
0xFF44 => 0x90,
|
|
|
|
0xFF4D => 0xFF,
|
|
|
|
_ => self.data[address as usize],
|
|
|
|
}
|
2021-10-14 00:38:37 +00:00
|
|
|
_ => self.data[address as usize],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-16 00:18:00 +00:00
|
|
|
pub fn read_16bit(&self, address: u16) -> u16 {
|
|
|
|
join_bytes(self.read(address + 1), self.read(address))
|
|
|
|
}
|
|
|
|
|
2021-10-14 00:38:37 +00:00
|
|
|
pub fn write(&mut self, address: u16, data: u8) {
|
2021-10-17 17:02:33 +00:00
|
|
|
match MemoryMap::get_map(address) {
|
2021-10-17 17:29:02 +00:00
|
|
|
MemoryMap::BankZero | MemoryMap::BankSwitchable => {
|
|
|
|
// println!("WRITING TO ROM");
|
|
|
|
},
|
2021-10-17 17:02:33 +00:00
|
|
|
MemoryMap::WorkRAM1 | MemoryMap::WorkRAM2 => {
|
|
|
|
self.data[address as usize] = data;
|
|
|
|
// Copy to the ECHO RAM
|
|
|
|
if address <= 0xDDFF {
|
|
|
|
self.data[(0xE000 + (address - 0xC000)) as usize] = data;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
MemoryMap::EchoRAM => {
|
|
|
|
self.data[address as usize] = data;
|
2021-10-17 17:29:02 +00:00
|
|
|
self.data[(0xC000 + (address - 0xE000)) as usize] = data; // Copy to the working RAM
|
2021-10-17 17:02:33 +00:00
|
|
|
},
|
|
|
|
_ => self.data[address as usize] = data,
|
|
|
|
};
|
2021-10-13 17:56:00 +00:00
|
|
|
}
|
2021-10-16 00:18:00 +00:00
|
|
|
|
|
|
|
pub fn write_16bit(&mut self, address: u16, data: u16) {
|
2021-10-19 14:53:50 +00:00
|
|
|
let bytes = data.to_le_bytes();
|
|
|
|
self.write(address, bytes[0]);
|
|
|
|
self.write(address + 1, bytes[1]);
|
2021-10-16 00:18:00 +00:00
|
|
|
}
|
2021-10-13 17:56:00 +00:00
|
|
|
}
|