rmg-001/src/bus.rs

197 lines
8.1 KiB
Rust
Raw Normal View History

2021-10-29 03:13:23 +00:00
use crate::utils::{
get_bit,
BitIndex,
join_bytes
};
use crate::rom::ROM;
2021-11-01 18:04:09 +00:00
use crate::ppu::{
LCD_STATUS_ADDRESS,
LCD_CONTROL_ADDRESS,
LCD_Y_ADDRESS,
DMA_ADDRESS,
2021-11-01 18:04:09 +00:00
};
2021-10-29 20:40:47 +00:00
use crate::cpu::{Interrupt};
2021-10-30 14:13:31 +00:00
use crate::timer::{TIMER_DIVIDER_REGISTER_ADDRESS};
2021-11-01 02:02:09 +00:00
use crate::joypad::{Joypad, JOYPAD_ADDRESS};
2021-10-22 20:32:12 +00:00
pub struct AddressRange {
begin: u16,
end: u16,
2021-10-13 17:56:00 +00:00
}
2021-10-22 20:32:12 +00:00
impl AddressRange {
pub fn begin(&self) -> u16 {
self.begin
}
pub fn end(&self) -> u16 {
self.end
}
pub fn in_range(&self, address: u16) -> bool {
address >= self.begin && address <= self.end
}
}
2021-10-22 20:32:12 +00:00
pub const BANK_ZERO: AddressRange = AddressRange{begin: 0x0000, end: 0x3FFF};
pub const BANK_SWITCHABLE: AddressRange = AddressRange{begin: 0x4000, end: 0x7FFF};
pub const VIDEO_RAM: AddressRange = AddressRange{begin: 0x8000, end: 0x9FFF};
pub const EXTERNAL_RAM: AddressRange = AddressRange{begin: 0xA000, end: 0xBFFF};
pub const WORK_RAM_1: AddressRange = AddressRange{begin: 0xC000, end: 0xCFFF};
pub const WORK_RAM_2: AddressRange = AddressRange{begin: 0xD000, end: 0xDFFF};
pub const ECHO_RAM: AddressRange = AddressRange{begin: 0xE000, end: 0xFDFF};
pub const SPRITE_ATTRIBUTE_TABLE: AddressRange = AddressRange{begin: 0xFE00, end: 0xFE9F};
pub const NOT_USABLE: AddressRange = AddressRange{begin: 0xFEA0, end: 0xFEFF};
pub const IO_REGISTERS: AddressRange = AddressRange{begin: 0xFF00, end: 0xFF7F};
pub const HIGH_RAM: AddressRange = AddressRange{begin: 0xFF80, end: 0xFFFE};
pub const INTERRUPT_ENABLE_REGISTER: AddressRange = AddressRange{begin: 0xFFFF, end: 0xFFFF};
2021-10-29 20:40:47 +00:00
pub const INTERRUPT_ENABLE_ADDRESS: u16 = 0xFFFF;
2021-10-29 03:13:23 +00:00
pub const INTERRUPT_FLAG_ADDRESS: u16 = 0xFF0F;
2021-10-22 20:32:12 +00:00
pub struct Bus {
game_rom: ROM,
2021-10-14 18:25:20 +00:00
data: [u8; 0x10000],
2021-11-02 03:22:43 +00:00
pub reset_timer: bool,
pub joypad: Joypad,
}
impl Bus {
pub fn new() -> Self {
2021-11-06 00:08:51 +00:00
let game_rom = match ROM::load_file("ignore/dr-mario.gb".to_string()) {
// let game_rom = match ROM::load_file("ignore/mooneye/emulator-only/mbc1/bits_bank1.gb".to_string()) {
2021-10-29 00:38:30 +00:00
// let game_rom = match ROM::load_file("roms/cpu_instrs.gb".to_string()) {
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/01-special.gb".to_string()) {
2021-11-06 00:08:51 +00:00
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/02-interrupts.gb".to_string()) {
2021-10-20 02:55:35 +00:00
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/03-op sp,hl.gb".to_string()) {
2021-10-20 03:36:10 +00:00
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/04-op r,imm.gb".to_string()) {
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/05-op rp.gb".to_string()) {
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/06-ld r,r.gb".to_string()) {
2021-10-20 18:39:39 +00:00
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/07-jr,jp,call,ret,rst.gb".to_string()) {
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/08-misc instrs.gb".to_string()) {
2021-10-20 18:47:59 +00:00
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/09-op r,r.gb".to_string()) {
2021-10-20 19:33:11 +00:00
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/10-bit ops.gb".to_string()) {
2021-10-20 23:16:45 +00:00
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/11-op a,(hl).gb".to_string()) {
Ok(rom) => rom,
// _ => ROM::from_bytes(&[0; 0xFFFF])
_ => panic!("Could not read ROM"),
};
2021-11-01 02:02:09 +00:00
let mut data = [0x00; 0x10000];
2021-11-03 13:36:30 +00:00
// Hardware registers after the bootrom
2021-11-03 16:59:48 +00:00
data[0xFF00] = 0xCF;
2021-11-01 18:04:09 +00:00
data[0xFF01] = 0x00;
data[0xFF02] = 0x7E;
data[0xFF04] = 0x18;
data[0xFF05] = 0x00;
data[0xFF06] = 0x00;
data[0xFF07] = 0xF8;
data[0xFF0F] = 0xE1;
data[0xFF40] = 0x91;
data[0xFF41] = 0x81;
data[0xFF42] = 0x00;
data[0xFF43] = 0x00;
data[0xFF44] = 0x91;
data[0xFF45] = 0x00;
data[0xFF46] = 0xFF;
data[0xFF47] = 0xFC;
data[0xFF4A] = 0x00;
data[0xFF4B] = 0x00;
data[0xFFFF] = 0x00;
2021-11-01 18:04:09 +00:00
Self {
2021-11-01 02:02:09 +00:00
data,
game_rom,
2021-11-02 03:22:43 +00:00
reset_timer: false,
joypad: Joypad::new(),
}
}
pub fn read(&self, address: u16) -> u8 {
2021-11-05 19:20:10 +00:00
if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) || EXTERNAL_RAM.in_range(address) {
2021-10-22 20:32:12 +00:00
return self.game_rom.read(address);
2021-11-04 18:13:22 +00:00
} else if address == INTERRUPT_ENABLE_ADDRESS || address == INTERRUPT_FLAG_ADDRESS {
return 0b11100000 | self.data[address as usize];
} else if address == JOYPAD_ADDRESS {
return self.joypad.read(self.data[address as usize]);
}
2021-10-22 20:32:12 +00:00
self.data[address as usize]
}
2021-10-16 00:18:00 +00:00
pub fn read_16bit(&self, address: u16) -> u16 {
2021-10-22 14:56:54 +00:00
join_bytes(self.read(address.wrapping_add(1)), self.read(address))
2021-10-16 00:18:00 +00:00
}
pub fn write(&mut self, address: u16, data: u8) {
2021-10-20 17:29:55 +00:00
if address == 0xFF01 {
2021-10-29 22:03:02 +00:00
// print!("{}", data as char);
2021-10-20 17:29:55 +00:00
}
2021-10-22 20:32:12 +00:00
2021-11-05 19:20:10 +00:00
if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) || EXTERNAL_RAM.in_range(address) {
self.game_rom.write(address, data);
2021-10-29 22:03:02 +00:00
// println!("WRITING TO ROM");
2021-10-22 20:32:12 +00:00
} else if WORK_RAM_1.in_range(address) || WORK_RAM_2.in_range(address) {
self.data[address as usize] = data;
// Copy to the ECHO RAM
if address <= 0xDDFF {
self.data[(ECHO_RAM.begin() + (address - WORK_RAM_1.begin())) as usize] = data;
}
2021-11-05 15:08:17 +00:00
} else if EXTERNAL_RAM.in_range(address) {
// self.game_rom.write(address, data);
2021-10-22 20:32:12 +00:00
} else if ECHO_RAM.in_range(address) {
self.data[address as usize] = data;
self.data[(WORK_RAM_1.begin() + (address - ECHO_RAM.begin())) as usize] = data; // Copy to the working RAM
2021-10-30 14:13:31 +00:00
} else if address == TIMER_DIVIDER_REGISTER_ADDRESS {
2021-11-02 03:22:43 +00:00
self.reset_timer = true;
} else if address == LCD_CONTROL_ADDRESS && get_bit(data, BitIndex::I7) {
self.data[address as usize] = data;
self.data[LCD_Y_ADDRESS as usize] = 0x00;
2021-11-03 16:59:48 +00:00
} else if address == LCD_Y_ADDRESS {
// println!("Write to LCD_Y not allowed");
} else if address == LCD_STATUS_ADDRESS {
let byte = self.data[address as usize];
self.data[address as usize] = (data & 0b11111000) | (byte & 0b00000111);
} else if address == JOYPAD_ADDRESS {
let byte = self.data[address as usize];
self.data[address as usize] = (data & 0b11110000) | (byte & 0b00001111);
} else if address == DMA_ADDRESS {
// the idea is: when something gets written to $FF46, multiply it by 0x100, then copy 160 bytes starting from that memory location into OAM
self.data[address as usize] = data;
let source = (data as usize) * 0x100;
let mut count = 0;
let oam_addr = SPRITE_ATTRIBUTE_TABLE.begin() as usize;
while count < 160 {
self.data[oam_addr + count] = self.data[source + count];
count += 1;
}
2021-10-29 03:13:23 +00:00
} else {
self.data[address as usize] = data;
2021-10-22 20:32:12 +00:00
}
2021-10-13 17:56:00 +00:00
}
2021-10-16 00:18:00 +00:00
2021-11-01 02:02:09 +00:00
pub fn force_write(&mut self, address: u16, data: u8) {
self.data[address as usize] = data;
}
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]);
2021-10-22 14:56:54 +00:00
self.write(address.wrapping_add(1), bytes[1]);
2021-10-16 00:18:00 +00:00
}
2021-10-29 03:13:23 +00:00
pub fn set_interrupt_enable(&mut self, interrupt: Interrupt, val: bool) {
2021-10-29 20:40:47 +00:00
let byte = self.read(INTERRUPT_ENABLE_ADDRESS);
2021-10-29 23:27:21 +00:00
self.write(INTERRUPT_ENABLE_ADDRESS, interrupt.set(byte, val));
2021-10-29 20:40:47 +00:00
}
pub fn set_interrupt_flag(&mut self, interrupt: Interrupt, val: bool) {
2021-10-29 03:13:23 +00:00
let byte = self.read(INTERRUPT_FLAG_ADDRESS);
2021-10-29 23:27:21 +00:00
self.write(INTERRUPT_FLAG_ADDRESS, interrupt.set(byte, val));
2021-10-29 03:13:23 +00:00
}
2021-10-29 20:40:47 +00:00
2021-10-29 23:27:21 +00:00
pub fn get_interrupt(&mut self, interrupt: Interrupt) -> bool {
2021-10-29 20:40:47 +00:00
let byte = self.read(INTERRUPT_ENABLE_ADDRESS) & self.read(INTERRUPT_FLAG_ADDRESS);
2021-10-29 23:27:21 +00:00
interrupt.get(byte)
2021-10-29 20:40:47 +00:00
}
2021-10-13 17:56:00 +00:00
}