2021-10-29 03:13:23 +00:00
|
|
|
use crate::utils::{
|
|
|
|
get_bit,
|
|
|
|
set_bit,
|
|
|
|
BitIndex,
|
|
|
|
join_bytes
|
|
|
|
};
|
2021-10-14 00:38:37 +00:00
|
|
|
use crate::rom::ROM;
|
2021-10-29 03:13:23 +00:00
|
|
|
use crate::ppu::{PPU, LCDStatus, LCDStatusModeFlag};
|
|
|
|
use crate::cpu::{InterruptFlag};
|
2021-10-14 00:38:37 +00:00
|
|
|
|
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-14 00:38:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 03:13:23 +00:00
|
|
|
pub const INTERRUPT_FLAG_ADDRESS: u16 = 0xFF0F;
|
2021-10-22 20:32:12 +00:00
|
|
|
|
2021-10-14 00:38:37 +00:00
|
|
|
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-29 00:38:30 +00:00
|
|
|
let game_rom = match ROM::load_file("ignore/tetris.gb".to_string()) {
|
|
|
|
// let game_rom = match ROM::load_file("roms/cpu_instrs.gb".to_string()) {
|
2021-10-28 17:58:03 +00:00
|
|
|
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/01-special.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()) {
|
2021-10-14 00:38:37 +00:00
|
|
|
Ok(rom) => rom,
|
2021-10-28 17:58:03 +00:00
|
|
|
// _ => ROM::from_bytes(&[0; 0xFFFF])
|
|
|
|
_ => panic!("Could not read ROM"),
|
2021-10-14 00:38:37 +00:00
|
|
|
};
|
|
|
|
Self {
|
2021-10-19 18:59:53 +00:00
|
|
|
data: [0x00; 0x10000],
|
2021-10-14 00:38:37 +00:00
|
|
|
game_rom,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn read(&self, address: u16) -> u8 {
|
2021-10-22 20:32:12 +00:00
|
|
|
if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) {
|
|
|
|
return self.game_rom.read(address);
|
2021-10-29 03:13:23 +00:00
|
|
|
} else if VIDEO_RAM.in_range(address) {
|
|
|
|
if PPU::get_lcd_status(self, LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD)) {
|
|
|
|
return 0xFF
|
|
|
|
}
|
2021-10-22 20:32:12 +00:00
|
|
|
} else if IO_REGISTERS.in_range(address) {
|
2021-10-29 00:38:30 +00:00
|
|
|
return self.data[address as usize];
|
2021-10-14 00:38:37 +00:00
|
|
|
}
|
2021-10-22 20:32:12 +00:00
|
|
|
self.data[address as usize]
|
2021-10-14 00:38:37 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2021-10-14 00:38:37 +00:00
|
|
|
pub fn write(&mut self, address: u16, data: u8) {
|
2021-10-20 17:29:55 +00:00
|
|
|
if address == 0xFF01 {
|
2021-10-20 19:33:11 +00:00
|
|
|
print!("{}", data as char);
|
2021-10-20 17:29:55 +00:00
|
|
|
}
|
2021-10-22 20:32:12 +00:00
|
|
|
|
|
|
|
if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) {
|
|
|
|
println!("WRITING TO ROM");
|
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
} 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-29 03:13:23 +00:00
|
|
|
} else if VIDEO_RAM.in_range(address) {
|
|
|
|
//if !PPU::get_lcd_status(self, LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD)) {
|
|
|
|
self.data[address as usize] = data;
|
|
|
|
// }
|
|
|
|
} 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
|
|
|
|
|
|
|
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_flag(&mut self, flag: InterruptFlag, val: bool) {
|
|
|
|
let byte = self.read(INTERRUPT_FLAG_ADDRESS);
|
|
|
|
self.write(INTERRUPT_FLAG_ADDRESS, match flag {
|
|
|
|
InterruptFlag::VBlank => set_bit(byte, val, BitIndex::I0),
|
|
|
|
InterruptFlag::LCDSTAT => set_bit(byte, val, BitIndex::I1),
|
|
|
|
InterruptFlag::Timer => set_bit(byte, val, BitIndex::I2),
|
|
|
|
InterruptFlag::Serial => set_bit(byte, val, BitIndex::I3),
|
|
|
|
InterruptFlag::Joypad => set_bit(byte, val, BitIndex::I4),
|
|
|
|
});
|
|
|
|
}
|
2021-10-13 17:56:00 +00:00
|
|
|
}
|