address handling
This commit is contained in:
parent
7448d18424
commit
828da3e01f
|
@ -1,4 +1,4 @@
|
|||
#![feature(exclusive_range_pattern, let_chains, bigint_helper_methods)]
|
||||
#![feature(exclusive_range_pattern, let_chains, bigint_helper_methods, step_trait)]
|
||||
|
||||
use crate::{processor::memory::Memory, util::pause};
|
||||
use connect::{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
pub use self::rom::Rom;
|
||||
use self::{
|
||||
addresses::{Address, AddressMarker, IoAddress},
|
||||
mmio::{
|
||||
apu::ApuSaveState,
|
||||
gpu::{Colour, GpuSaveState},
|
||||
|
@ -11,17 +12,16 @@ use self::{
|
|||
use crate::{
|
||||
connect::{AudioOutput, CameraWrapperRef, JoypadState, PocketCamera, Renderer, SerialTarget},
|
||||
processor::SplitRegister,
|
||||
verbose_println, Cpu,
|
||||
Cpu,
|
||||
};
|
||||
|
||||
mod interrupts;
|
||||
pub use interrupts::{Interrupt, Interrupts};
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub(crate) mod addresses;
|
||||
pub mod mmio;
|
||||
pub(crate) mod rom;
|
||||
|
||||
pub(crate) type Address = u16;
|
||||
|
||||
pub struct Memory<ColourFormat, R, C>
|
||||
where
|
||||
ColourFormat: From<Colour> + Clone,
|
||||
|
@ -124,73 +124,86 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, address: Address) -> u8 {
|
||||
pub(crate) fn get<T>(&self, address: T) -> u8
|
||||
where
|
||||
T: Into<Address>,
|
||||
{
|
||||
let address: Address = address.into();
|
||||
match address {
|
||||
0x0..0x8000 => {
|
||||
Address::Rom(address) => {
|
||||
// rom access
|
||||
// todo - switchable rom banks
|
||||
if let Some(bootrom) = &self.bootrom && (address as usize) < bootrom.len() {
|
||||
bootrom[address as usize]
|
||||
if let Some(bootrom) = &self.bootrom && (address.inner() as usize) < bootrom.len() {
|
||||
bootrom[address.inner() as usize]
|
||||
} else {
|
||||
self.rom.get(address)
|
||||
}
|
||||
}
|
||||
0x8000..0xA000 => self.gpu.vram.get(address),
|
||||
0xA000..0xC000 => {
|
||||
// cart ram
|
||||
self.rom.get_ram(address)
|
||||
}
|
||||
0xC000..0xE000 => self.ram[(address - 0xC000) as usize],
|
||||
0xE000..0xFE00 => self.ram[(address - 0xE000) as usize],
|
||||
0xFE00..0xFEA0 => self.gpu.oam.get(address),
|
||||
0xFEA0..0xFF00 => 0xFF,
|
||||
0xFF00..0xFF4C => self.get_io(address),
|
||||
0xFF4C..0xFF80 => 0xFF,
|
||||
0xFF80..0xFFFF => self.cpu_ram[(address - 0xFF80) as usize],
|
||||
0xFFFF => self.interrupts.get_enable_register(),
|
||||
Address::Vram(address) => self.gpu.vram.get(address),
|
||||
Address::CartRam(address) => self.rom.get_ram(address),
|
||||
Address::WorkRam(address) => self.ram[address.get_local() as usize],
|
||||
Address::BankedWorkRam(address) => self.ram[(address.get_local() + 0x1000) as usize],
|
||||
Address::MirroredRam(address) => self.ram[address.get_local() as usize],
|
||||
Address::Oam(address) => self.gpu.oam.get(address),
|
||||
Address::Prohibited(_) => 0xFF,
|
||||
Address::Io(address) => self.get_io(address),
|
||||
Address::Hram(address) => self.cpu_ram[address.get_local() as usize],
|
||||
Address::InterruptEnable(_) => self.interrupts.get_enable_register(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, address: Address, data: u8) {
|
||||
pub(crate) fn set<T>(&mut self, address: T, data: u8)
|
||||
where
|
||||
T: Into<Address>,
|
||||
{
|
||||
let address: Address = address.into();
|
||||
match address {
|
||||
0x0..0x8000 => {
|
||||
// change this with MBC code...
|
||||
Address::Rom(address) => {
|
||||
self.rom.set(address, data);
|
||||
if self.rom.can_rumble() {
|
||||
// rumble
|
||||
self.gpu.window.set_rumble(self.rom.is_rumbling())
|
||||
}
|
||||
}
|
||||
0x8000..0xA000 => self.gpu.vram.set(address, data),
|
||||
0xA000..0xC000 => self.rom.set_ram(address, data),
|
||||
0xC000..0xE000 => self.ram[(address - 0xC000) as usize] = data,
|
||||
0xE000..0xFE00 => self.ram[(address - 0xE000) as usize] = data,
|
||||
0xFE00..0xFEA0 => self.gpu.oam.set(address, data),
|
||||
0xFEA0..0xFF00 => {}
|
||||
0xFF00..0xFF4C => self.set_io(address, data),
|
||||
0xFF50 => self.bootrom = None,
|
||||
0xFF4C..0xFF50 | 0xFF51..0xFF80 => {}
|
||||
0xFF80..0xFFFF => self.cpu_ram[(address - 0xFF80) as usize] = data,
|
||||
0xFFFF => {
|
||||
verbose_println!("interrupts set to {:#b}", data);
|
||||
verbose_println!(" / {:#X}", data);
|
||||
self.interrupts.set_enable_register(data);
|
||||
Address::Vram(address) => self.gpu.vram.set(address, data),
|
||||
Address::CartRam(address) => self.rom.set_ram(address, data),
|
||||
Address::WorkRam(address) => self.ram[address.get_local() as usize] = data,
|
||||
Address::BankedWorkRam(address) => {
|
||||
self.ram[(address.get_local() + 0x1000) as usize] = data
|
||||
}
|
||||
Address::MirroredRam(address) => self.ram[address.get_local() as usize] = data,
|
||||
Address::Oam(address) => self.gpu.oam.set(address, data),
|
||||
Address::Prohibited(_) => {}
|
||||
Address::Io(address) => {
|
||||
if address.inner() == 0xFF50 {
|
||||
self.bootrom = None
|
||||
}
|
||||
self.set_io(address, data)
|
||||
}
|
||||
Address::Hram(address) => self.cpu_ram[address.get_local() as usize] = data,
|
||||
Address::InterruptEnable(_) => self.interrupts.set_enable_register(data),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_io(&self, address: Address) -> u8 {
|
||||
// range: 0xFF00 - 0xFF4B inclusive
|
||||
fn get_io(&self, address: IoAddress) -> u8 {
|
||||
match address {
|
||||
0xFF00 => self.joypad.as_register(),
|
||||
IoAddress::Joypad => self.joypad.as_register(),
|
||||
IoAddress::Serial(address) => match address.inner() {
|
||||
0xFF01 => self.serial.get_queued(),
|
||||
0xFF02 => self.serial.get_control(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
IoAddress::Timer(address) => match address.inner() {
|
||||
0xFF04 => self.timers.get_div(),
|
||||
0xFF05 => self.timers.get_tima(),
|
||||
0xFF06 => self.timers.get_tma(),
|
||||
0xFF07 => self.timers.get_timer_control(),
|
||||
0xFF0F => self.interrupts.get_flag_register(),
|
||||
0xFF10..0xFF40 => self.apu.get_register(address),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
IoAddress::InterruptFlag => self.interrupts.get_flag_register(),
|
||||
IoAddress::Audio(address) => self.apu.get_register(address),
|
||||
IoAddress::WaveRam(address) => self.apu.get_wave_ram_register(address),
|
||||
IoAddress::Video(address) => match address.inner() {
|
||||
0xFF40 => self.gpu.get_lcdc(),
|
||||
0xFF41 => self.gpu.get_lcd_status(),
|
||||
0xFF42 => self.gpu.get_scy(),
|
||||
|
@ -203,26 +216,31 @@ where
|
|||
0xFF49 => self.gpu.get_obj_palette_1(),
|
||||
0xFF4A => self.gpu.get_wy(),
|
||||
0xFF4B => self.gpu.get_wx(),
|
||||
0xFF03 | 0xFF08..0xFF0F => 0xFF,
|
||||
0x0..0xFF00 | 0xFF4C..=0xFFFF => panic!("passed wrong address to get_io"),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
IoAddress::Unused(_) => 0xFF,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_io(&mut self, address: Address, data: u8) {
|
||||
// range: 0xFF00 - 0xFF4B inclusive
|
||||
fn set_io(&mut self, address: IoAddress, data: u8) {
|
||||
match address {
|
||||
0xFF00 => {
|
||||
// joypad
|
||||
self.joypad.mmio_write(data);
|
||||
}
|
||||
IoAddress::Joypad => self.joypad.mmio_write(data),
|
||||
IoAddress::Serial(address) => match address.inner() {
|
||||
0xFF01 => self.serial.update_queued(data),
|
||||
0xFF02 => self.serial.update_control(data),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
IoAddress::Timer(address) => match address.inner() {
|
||||
0xFF04 => self.timers.update_div(),
|
||||
0xFF05 => self.timers.update_tima(data),
|
||||
0xFF06 => self.timers.update_tma(data),
|
||||
0xFF07 => self.timers.update_timer_control(data),
|
||||
0xFF0F => self.interrupts.set_flag_register(data),
|
||||
0xFF10..0xFF40 => self.apu.mmio_write(address, data),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
IoAddress::InterruptFlag => self.interrupts.set_flag_register(data),
|
||||
IoAddress::Audio(address) => self.apu.mmio_write(address, data),
|
||||
IoAddress::WaveRam(address) => self.apu.mmio_write_wave_ram(address, data),
|
||||
IoAddress::Video(address) => match address.inner() {
|
||||
0xFF40 => self.gpu.update_lcdc(data),
|
||||
0xFF41 => self.gpu.update_lcd_status(data),
|
||||
0xFF42 => self.gpu.update_scy(data),
|
||||
|
@ -245,11 +263,9 @@ where
|
|||
0xFF49 => self.gpu.update_obj_palette_1(data),
|
||||
0xFF4A => self.gpu.update_wy(data),
|
||||
0xFF4B => self.gpu.update_wx(data),
|
||||
0xFF03 | 0xFF08..0xFF0F | 0xFF44 => {
|
||||
// read-only addresses
|
||||
verbose_println!("BANNED write: {data:#X} to {address:#X}");
|
||||
}
|
||||
0x0..0xFF00 | 0xFF4C..=u16::MAX => panic!("passed wrong address to set_io"),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
IoAddress::Unused(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
167
lib/src/processor/memory/addresses.rs
Normal file
167
lib/src/processor/memory/addresses.rs
Normal file
|
@ -0,0 +1,167 @@
|
|||
use std::ops::{Add, Sub};
|
||||
|
||||
pub(crate) use self::types::*;
|
||||
|
||||
mod types;
|
||||
|
||||
pub(crate) type VramAddress = BoundedAddress<0x8000, 0xA000>;
|
||||
pub(crate) type CartRamAddress = BoundedAddress<0xA000, 0xC000>;
|
||||
pub(crate) type WorkRamAddress = BoundedAddress<0xC000, 0xD000>;
|
||||
pub(crate) type BankedWorkRamAddress = BoundedAddress<0xD000, 0xE000>;
|
||||
pub(crate) type MirroredRamAddress = BoundedAddress<0xE000, 0xFE00>;
|
||||
pub(crate) type OamAddress = BoundedAddress<0xFE00, 0xFEA0>;
|
||||
pub(crate) type ProhibitedAddress = BoundedAddress<0xFEA0, 0xFF00>;
|
||||
pub(crate) type HramAddress = BoundedAddress<0xFF80, 0xFFFF>;
|
||||
pub(crate) type InterruptEnable = ();
|
||||
|
||||
pub(crate) type Bank0Address = BoundedAddress<0x0, 0x4000>;
|
||||
pub(crate) type MappedBankAddress = BoundedAddress<0x4000, 0x8000>;
|
||||
|
||||
pub(crate) type SerialAddress = BoundedAddress<0xFF01, 0xFF03>;
|
||||
pub(crate) type TimerAddress = BoundedAddress<0xFF04, 0xFF08>;
|
||||
pub(crate) type AudioAddress = BoundedAddress<0xFF10, 0xFF27>;
|
||||
pub(crate) type WaveRamAddress = BoundedAddress<0xFF30, 0xFF40>;
|
||||
pub(crate) type VideoAddress = BoundedAddress<0xFF40, 0xFF4C>;
|
||||
|
||||
pub(crate) enum RomAddress {
|
||||
Bank0(Bank0Address),
|
||||
MappedBank(MappedBankAddress),
|
||||
}
|
||||
|
||||
pub(crate) enum IoAddress {
|
||||
Joypad,
|
||||
Serial(SerialAddress),
|
||||
Timer(TimerAddress),
|
||||
InterruptFlag,
|
||||
Audio(AudioAddress),
|
||||
WaveRam(WaveRamAddress),
|
||||
Video(VideoAddress),
|
||||
Unused(u16),
|
||||
}
|
||||
|
||||
pub(crate) enum Address {
|
||||
Rom(RomAddress),
|
||||
Vram(VramAddress),
|
||||
CartRam(CartRamAddress),
|
||||
WorkRam(WorkRamAddress),
|
||||
BankedWorkRam(BankedWorkRamAddress),
|
||||
MirroredRam(MirroredRamAddress),
|
||||
Oam(OamAddress),
|
||||
Prohibited(ProhibitedAddress),
|
||||
Io(IoAddress),
|
||||
Hram(HramAddress),
|
||||
InterruptEnable(InterruptEnable),
|
||||
}
|
||||
|
||||
impl TryInto<RomAddress> for u16 {
|
||||
type Error = AddressError;
|
||||
|
||||
fn try_into(self) -> Result<RomAddress, Self::Error> {
|
||||
match self {
|
||||
0x0..0x4000 => Ok(RomAddress::Bank0(self.try_into().unwrap())),
|
||||
0x4000..0x8000 => Ok(RomAddress::MappedBank(self.try_into().unwrap())),
|
||||
_ => Err(AddressError::OutOfBounds),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressMarker for RomAddress {
|
||||
fn inner(&self) -> u16 {
|
||||
match self {
|
||||
RomAddress::Bank0(v) => v.inner(),
|
||||
RomAddress::MappedBank(v) => v.inner(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for Address {
|
||||
fn from(value: u16) -> Self {
|
||||
match value {
|
||||
0x0..0x8000 => Address::Rom(value.try_into().unwrap()),
|
||||
0x8000..0xA000 => Address::Vram(value.try_into().unwrap()),
|
||||
0xA000..0xC000 => Address::CartRam(value.try_into().unwrap()),
|
||||
0xC000..0xD000 => Address::WorkRam(value.try_into().unwrap()),
|
||||
0xD000..0xE000 => Address::BankedWorkRam(value.try_into().unwrap()),
|
||||
0xE000..0xFE00 => Address::MirroredRam(value.try_into().unwrap()),
|
||||
0xFE00..0xFEA0 => Address::Oam(value.try_into().unwrap()),
|
||||
0xFEA0..0xFF00 => Address::Prohibited(value.try_into().unwrap()),
|
||||
0xFF00..0xFF80 => Address::Io(value.try_into().unwrap()),
|
||||
0xFF80..0xFFFF => Address::Hram(value.try_into().unwrap()),
|
||||
0xFFFF => Address::InterruptEnable(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<IoAddress> for u16 {
|
||||
type Error = AddressError;
|
||||
|
||||
fn try_into(self) -> Result<IoAddress, Self::Error> {
|
||||
match self {
|
||||
0xFF00 => Ok(IoAddress::Joypad),
|
||||
0xFF01..0xFF03 => Ok(IoAddress::Serial(self.try_into().unwrap())),
|
||||
0xFF04..0xFF08 => Ok(IoAddress::Timer(self.try_into().unwrap())),
|
||||
0xFF0F => Ok(IoAddress::InterruptFlag),
|
||||
0xFF10..0xFF27 => Ok(IoAddress::Audio(self.try_into().unwrap())),
|
||||
0xFF30..0xFF40 => Ok(IoAddress::WaveRam(self.try_into().unwrap())),
|
||||
0xFF40..0xFF4C => Ok(IoAddress::Video(self.try_into().unwrap())),
|
||||
0x0..0xFF00 => Err(AddressError::OutOfBounds),
|
||||
0xFFFF => Err(AddressError::OutOfBounds),
|
||||
_ => Ok(IoAddress::Unused(self)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressMarker for IoAddress {
|
||||
fn inner(&self) -> u16 {
|
||||
match self {
|
||||
IoAddress::Joypad => 0xFF00,
|
||||
IoAddress::Serial(v) => v.inner(),
|
||||
IoAddress::Timer(v) => v.inner(),
|
||||
IoAddress::InterruptFlag => 0xFF0F,
|
||||
IoAddress::Audio(v) => v.inner(),
|
||||
IoAddress::WaveRam(v) => v.inner(),
|
||||
IoAddress::Video(v) => v.inner(),
|
||||
IoAddress::Unused(v) => *v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressMarker for Address {
|
||||
fn inner(&self) -> u16 {
|
||||
match self {
|
||||
Address::Rom(v) => v.inner(),
|
||||
Address::Vram(v) => v.inner(),
|
||||
Address::CartRam(v) => v.inner(),
|
||||
Address::WorkRam(v) => v.inner(),
|
||||
Address::BankedWorkRam(v) => v.inner(),
|
||||
Address::MirroredRam(v) => v.inner(),
|
||||
Address::Oam(v) => v.inner(),
|
||||
Address::Prohibited(v) => v.inner(),
|
||||
Address::Io(v) => v.inner(),
|
||||
Address::Hram(v) => v.inner(),
|
||||
Address::InterruptEnable(_) => 0xFFFF,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Address> for u16 {
|
||||
fn from(value: Address) -> Self {
|
||||
value.inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Address {
|
||||
type Output = Address;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
self.inner().wrapping_add(rhs.inner()).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Address {
|
||||
type Output = Address;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
self.inner().wrapping_sub(rhs.inner()).into()
|
||||
}
|
||||
}
|
65
lib/src/processor/memory/addresses/types.rs
Normal file
65
lib/src/processor/memory/addresses/types.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
use std::ops::{Add, Sub};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum AddressError {
|
||||
OutOfBounds,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct BoundedAddress<const MIN: u16, const MAX: u16>(u16);
|
||||
|
||||
impl<const MIN: u16, const MAX: u16> Add<u16> for BoundedAddress<MIN, MAX> {
|
||||
type Output = Option<BoundedAddress<MIN, MAX>>;
|
||||
|
||||
fn add(self, rhs: u16) -> Self::Output {
|
||||
(self.0 + rhs).try_into().ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MIN: u16, const MAX: u16> Sub<u16> for BoundedAddress<MIN, MAX> {
|
||||
type Output = Option<BoundedAddress<MIN, MAX>>;
|
||||
|
||||
fn sub(self, rhs: u16) -> Self::Output {
|
||||
(self.0 - rhs).try_into().ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MIN: u16, const MAX: u16> TryInto<BoundedAddress<MIN, MAX>> for u16 {
|
||||
type Error = AddressError;
|
||||
|
||||
fn try_into(self) -> Result<BoundedAddress<MIN, MAX>, Self::Error> {
|
||||
if self >= MIN && self < MAX {
|
||||
Ok(BoundedAddress(self))
|
||||
} else {
|
||||
Err(AddressError::OutOfBounds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MIN: u16, const MAX: u16> BoundedAddress<MIN, MAX> {
|
||||
pub(crate) fn get_local(&self) -> u16 {
|
||||
self.0 - MIN
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MIN: u16, const MAX: u16> PartialEq for BoundedAddress<MIN, MAX> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MIN: u16, const MAX: u16> PartialOrd for BoundedAddress<MIN, MAX> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
self.0.partial_cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait AddressMarker {
|
||||
fn inner(&self) -> u16;
|
||||
}
|
||||
|
||||
impl<const MIN: u16, const MAX: u16> AddressMarker for BoundedAddress<MIN, MAX> {
|
||||
fn inner(&self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ use self::{
|
|||
};
|
||||
use crate::{
|
||||
connect::AudioOutput,
|
||||
processor::memory::Address,
|
||||
processor::memory::addresses::{AddressMarker, AudioAddress, WaveRamAddress},
|
||||
util::{get_bit, set_or_clear_bit},
|
||||
};
|
||||
use futures::executor;
|
||||
|
@ -185,11 +185,11 @@ impl Apu {
|
|||
self.output.send_rb.is_full()
|
||||
}
|
||||
|
||||
pub fn get_register(&self, addr: Address) -> u8 {
|
||||
pub(crate) fn get_register(&self, addr: AudioAddress) -> u8 {
|
||||
if self.apu_enable {
|
||||
self.make_register(addr)
|
||||
} else {
|
||||
match addr {
|
||||
match addr.inner() {
|
||||
0xFF26 | 0xFF11 | 0xFF16 | 0xFF1B | 0xFF20 | 0xFF30..0xFF40 => {
|
||||
self.make_register(addr)
|
||||
}
|
||||
|
@ -198,8 +198,12 @@ impl Apu {
|
|||
}
|
||||
}
|
||||
|
||||
fn make_register(&self, addr: Address) -> u8 {
|
||||
match addr {
|
||||
pub(crate) fn get_wave_ram_register(&self, addr: WaveRamAddress) -> u8 {
|
||||
self.channels.three.wave_ram.data[addr.get_local() as usize]
|
||||
}
|
||||
|
||||
fn make_register(&self, addr: AudioAddress) -> u8 {
|
||||
match addr.inner() {
|
||||
0xFF10 => self.channels.one.get_sweep_register(),
|
||||
0xFF11 => self.channels.one.get_length_timer_and_duty_cycle(),
|
||||
0xFF12 => self.channels.one.get_volume_and_envelope(),
|
||||
|
@ -250,15 +254,13 @@ impl Apu {
|
|||
// write-only registers
|
||||
0xFF13 | 0xFF18 | 0xFF1B | 0xFF1D | 0xFF20 => 0xFF,
|
||||
// not registers
|
||||
0xFF15 | 0xFF1F | 0xFF27..0xFF30 => 0xFF,
|
||||
// wave ram
|
||||
0xFF30..0xFF40 => self.channels.three.wave_ram.data[(addr - 0xFF30) as usize],
|
||||
0x0..0xFF10 | 0xFF40..=0xFFFF => panic!("non-apu addr in apu"),
|
||||
0xFF15 | 0xFF1F => 0xFF,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mmio_write(&mut self, addr: Address, data: u8) {
|
||||
match addr {
|
||||
pub(crate) fn mmio_write(&mut self, addr: AudioAddress, data: u8) {
|
||||
match addr.inner() {
|
||||
0xFF10 => self.channels.one.update_sweep(data),
|
||||
0xFF11 => self.channels.one.update_length_timer_and_duty_cycle(data),
|
||||
0xFF12 => self.channels.one.update_volume_and_envelope(data),
|
||||
|
@ -296,17 +298,19 @@ impl Apu {
|
|||
0xFF26 => {
|
||||
if !self.apu_enable {
|
||||
for i in 0xFF10..0xFF20 {
|
||||
self.mmio_write(i, 0x0);
|
||||
self.mmio_write(i.try_into().unwrap(), 0x0);
|
||||
}
|
||||
for i in 0xFF21..0xFF25 {
|
||||
self.mmio_write(i, 0x0);
|
||||
self.mmio_write(i.try_into().unwrap(), 0x0);
|
||||
}
|
||||
}
|
||||
self.apu_enable = (1 << 7) == (data & 0b10000000);
|
||||
}
|
||||
0xFF30..0xFF40 => self.channels.three.update_wave_ram(addr, data),
|
||||
0xFF15 | 0xFF1F | 0xFF27..0xFF30 => {}
|
||||
0x0..0xFF10 | 0xFF40..=0xFFFF => panic!("non-apu addr in apu"),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn mmio_write_wave_ram(&mut self, addr: WaveRamAddress, data: u8) {
|
||||
self.channels.three.update_wave_ram(addr, data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
processor::memory::Address,
|
||||
processor::memory::addresses::WaveRamAddress,
|
||||
util::{get_bit, set_or_clear_bit, Nibbles},
|
||||
};
|
||||
|
||||
|
@ -461,8 +461,8 @@ impl WaveChannel {
|
|||
set_or_clear_bit(0xFF, 6, self.length_enable)
|
||||
}
|
||||
|
||||
pub(super) fn update_wave_ram(&mut self, addr: Address, data: u8) {
|
||||
let real_addr = (addr - 0xFF30) as usize;
|
||||
pub(super) fn update_wave_ram(&mut self, addr: WaveRamAddress, data: u8) {
|
||||
let real_addr = addr.get_local() as usize;
|
||||
if real_addr >= self.wave_ram.data.len() {
|
||||
panic!("sent the wrong address to update_wave_ram");
|
||||
}
|
||||
|
|
|
@ -332,17 +332,17 @@ where
|
|||
let mut objs = vec![];
|
||||
let effective_scanline = scanline + 16;
|
||||
for i in (0xFE00..0xFE9F).step_by(4) {
|
||||
let y_pos = self.oam.get(i);
|
||||
let y_pos = self.oam.get(i.try_into().unwrap());
|
||||
if y_pos <= effective_scanline
|
||||
&& (y_pos + self.lcdc.obj_size.get_height()) > effective_scanline
|
||||
{
|
||||
// sprite is on line
|
||||
let x_pos = self.oam.get(i + 1);
|
||||
let mut tile_index = self.oam.get(i + 2);
|
||||
let x_pos = self.oam.get((i + 1).try_into().unwrap());
|
||||
let mut tile_index = self.oam.get((i + 2).try_into().unwrap());
|
||||
if self.lcdc.obj_size == ObjSize::S8x16 {
|
||||
tile_index = clear_bit(tile_index, 0);
|
||||
}
|
||||
let flags = self.oam.get(i + 3);
|
||||
let flags = self.oam.get((i + 3).try_into().unwrap());
|
||||
objs.push(Object {
|
||||
x: x_pos,
|
||||
y: y_pos,
|
||||
|
@ -380,11 +380,12 @@ where
|
|||
object_row = self.lcdc.obj_size.get_height() - (object_row + 1);
|
||||
}
|
||||
let tile_row = object_row % 8;
|
||||
let tile_addr = TiledataArea::D8000
|
||||
let tile_addr = (TiledataArea::D8000
|
||||
.get_addr(object.tile_index + if object_row >= 8 { 1 } else { 0 })
|
||||
+ (tile_row as u16 * 2);
|
||||
+ (tile_row as u16 * 2))
|
||||
.unwrap();
|
||||
let lsbs = self.vram.get(tile_addr);
|
||||
let msbs = self.vram.get(tile_addr + 1);
|
||||
let msbs = self.vram.get((tile_addr + 1).unwrap());
|
||||
for px_x in 0..8 {
|
||||
let x_addr = if object.flags.x_flip { px_x } else { 7 - px_x };
|
||||
let lsb = get_bit(lsbs, x_addr);
|
||||
|
@ -437,14 +438,15 @@ where
|
|||
let tilemap_column = (tile_line_x / 8) as u16;
|
||||
|
||||
let tile_px_x = tile_line_x % 8;
|
||||
let tile_addr = self
|
||||
let tile_addr = (self
|
||||
.lcdc
|
||||
.tile_area
|
||||
.get_addr(self.vram.get(tilemap.get_addr(row_addr + (tilemap_column))))
|
||||
+ tiledata_offset as u16;
|
||||
+ tiledata_offset as u16)
|
||||
.unwrap();
|
||||
|
||||
let lsbs = self.vram.get(tile_addr);
|
||||
let msbs = self.vram.get(tile_addr + 1);
|
||||
let msbs = self.vram.get((tile_addr + 1).unwrap());
|
||||
let lsb = get_bit(lsbs, 7 - tile_px_x);
|
||||
let msb = get_bit(msbs, 7 - tile_px_x);
|
||||
let (colour, is_zero) = self.bg_palette.map_bits(lsb, msb);
|
||||
|
|
|
@ -61,9 +61,9 @@ where
|
|||
for tile_x in 0..16 {
|
||||
let tile_num = (tile_y * 16) + tile_x;
|
||||
let data_begin = area.get_addr(tile_num);
|
||||
for px_y in 0..8 {
|
||||
let lsbs = memory.get((px_y * 2) + data_begin);
|
||||
let msbs = memory.get((px_y * 2) + data_begin + 1);
|
||||
for px_y in 0..8_u16 {
|
||||
let lsbs = memory.get((data_begin + (px_y * 2)).unwrap());
|
||||
let msbs = memory.get((data_begin + (1 + (px_y * 2))).unwrap());
|
||||
for px_x in 0..8 {
|
||||
let real_px_y = (display_y * 8) + px_y as usize;
|
||||
let real_px_x = (tile_x as usize * 8) + px_x as usize;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
processor::memory::Address,
|
||||
processor::memory::addresses::{OamAddress, VramAddress},
|
||||
util::{as_signed, get_bit},
|
||||
};
|
||||
|
||||
|
@ -20,10 +20,10 @@ pub(super) enum TilemapArea {
|
|||
}
|
||||
|
||||
impl TilemapArea {
|
||||
pub(super) fn get_addr(&self, addr: u16) -> u16 {
|
||||
pub(super) fn get_addr(&self, addr: u16) -> VramAddress {
|
||||
match self {
|
||||
TilemapArea::T9800 => 0x9800 + addr,
|
||||
TilemapArea::T9C00 => 0x9C00 + addr,
|
||||
TilemapArea::T9800 => (0x9800 + addr).try_into().unwrap(),
|
||||
TilemapArea::T9C00 => (0x9C00 + addr).try_into().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,10 +35,13 @@ pub(super) enum TiledataArea {
|
|||
}
|
||||
|
||||
impl TiledataArea {
|
||||
pub(super) fn get_addr(&self, addr: u8) -> u16 {
|
||||
pub(super) fn get_addr(&self, addr: u8) -> VramAddress {
|
||||
match self {
|
||||
TiledataArea::D8000 => 0x8000 + ((addr as u16) * 16),
|
||||
TiledataArea::D9000 => 0x9000_u16.wrapping_add_signed((as_signed(addr) as i16) * 16),
|
||||
TiledataArea::D8000 => (0x8000 + ((addr as u16) * 16)).try_into().unwrap(),
|
||||
TiledataArea::D9000 => 0x9000_u16
|
||||
.wrapping_add_signed((as_signed(addr) as i16) * 16)
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -224,12 +227,12 @@ pub struct Vram {
|
|||
}
|
||||
|
||||
impl Vram {
|
||||
pub fn get(&self, address: Address) -> u8 {
|
||||
self.data[(address - 0x8000) as usize]
|
||||
pub(crate) fn get(&self, address: VramAddress) -> u8 {
|
||||
self.data[address.get_local() as usize]
|
||||
}
|
||||
|
||||
pub fn set(&mut self, address: Address, data: u8) {
|
||||
self.data[(address - 0x8000) as usize] = data;
|
||||
pub(crate) fn set(&mut self, address: VramAddress, data: u8) {
|
||||
self.data[address.get_local() as usize] = data;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,12 +250,12 @@ pub struct Oam {
|
|||
}
|
||||
|
||||
impl Oam {
|
||||
pub fn get(&self, address: Address) -> u8 {
|
||||
self.data[(address - 0xFE00) as usize]
|
||||
pub(crate) fn get(&self, address: OamAddress) -> u8 {
|
||||
self.data[address.get_local() as usize]
|
||||
}
|
||||
|
||||
pub fn set(&mut self, address: Address, data: u8) {
|
||||
self.data[(address - 0xFE00) as usize] = data;
|
||||
pub(crate) fn set(&mut self, address: OamAddress, data: u8) {
|
||||
self.data[address.get_local() as usize] = data;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
connect::{CameraWrapperRef, PocketCamera as PocketCameraTrait},
|
||||
processor::memory::Address,
|
||||
};
|
||||
use crate::connect::{CameraWrapperRef, PocketCamera as PocketCameraTrait};
|
||||
use std::{
|
||||
fs::{File, OpenOptions},
|
||||
io::{Read, Seek, SeekFrom, Write},
|
||||
|
@ -17,6 +14,8 @@ use self::mbcs::{
|
|||
PocketCamera, PocketCameraSaveState,
|
||||
};
|
||||
|
||||
use super::addresses::{CartRamAddress, RomAddress};
|
||||
|
||||
mod mbcs;
|
||||
|
||||
struct MaybeBufferedSram {
|
||||
|
@ -249,19 +248,19 @@ where
|
|||
&self.title
|
||||
}
|
||||
|
||||
pub(super) fn get(&self, address: Address) -> u8 {
|
||||
pub(super) fn get(&self, address: RomAddress) -> u8 {
|
||||
self.mbc.get(address)
|
||||
}
|
||||
|
||||
pub(super) fn get_ram(&self, address: Address) -> u8 {
|
||||
pub(super) fn get_ram(&self, address: CartRamAddress) -> u8 {
|
||||
self.mbc.get_ram(address)
|
||||
}
|
||||
|
||||
pub(super) fn set(&mut self, address: Address, data: u8) {
|
||||
pub(super) fn set(&mut self, address: RomAddress, data: u8) {
|
||||
self.mbc.set(address, data);
|
||||
}
|
||||
|
||||
pub(super) fn set_ram(&mut self, address: Address, data: u8) {
|
||||
pub(super) fn set_ram(&mut self, address: CartRamAddress, data: u8) {
|
||||
self.mbc.set_ram(address, data);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::processor::memory::Address;
|
||||
use crate::processor::memory::addresses::{CartRamAddress, RomAddress};
|
||||
|
||||
mod mbc1;
|
||||
mod mbc2;
|
||||
|
@ -21,11 +21,11 @@ const RAM_BANK_SIZE: usize = 8 * KB;
|
|||
|
||||
pub(super) trait Mbc: Send {
|
||||
// addresses 0x0000 - 0x7FFF
|
||||
fn get(&self, address: Address) -> u8;
|
||||
fn get(&self, address: RomAddress) -> u8;
|
||||
// addresses 0xA000 - 0xBFFF
|
||||
fn get_ram(&self, address: Address) -> u8;
|
||||
fn set(&mut self, address: Address, data: u8);
|
||||
fn set_ram(&mut self, address: Address, data: u8);
|
||||
fn get_ram(&self, address: CartRamAddress) -> u8;
|
||||
fn set(&mut self, address: RomAddress, data: u8);
|
||||
fn set_ram(&mut self, address: CartRamAddress, data: u8);
|
||||
fn mbc_type(&self) -> String;
|
||||
fn get_save_state(&self) -> MbcSaveState;
|
||||
fn is_rumbling(&self) -> bool {
|
||||
|
|
|
@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||
use crate::processor::memory::{
|
||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||
rom::{MaybeBufferedSram, MbcSaveState, SramSaveState},
|
||||
Address,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
|
@ -53,39 +53,32 @@ impl Mbc1 {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_rom_addr(&self, address: Address) -> usize {
|
||||
fn get_rom_addr(&self, address: RomAddress) -> usize {
|
||||
(match address {
|
||||
0x0..0x4000 => match self.bank_mode {
|
||||
BankingMode::Simple => address as usize,
|
||||
RomAddress::Bank0(address) => match self.bank_mode {
|
||||
BankingMode::Simple => address.inner() as usize,
|
||||
BankingMode::Advanced => {
|
||||
(address as usize) + (self.upper_banks as usize * 512 * KB)
|
||||
(address.inner() as usize) + (self.upper_banks as usize * 512 * KB)
|
||||
}
|
||||
},
|
||||
0x4000..0x8000 => {
|
||||
(address - 0x4000) as usize
|
||||
RomAddress::MappedBank(address) => {
|
||||
(address.get_local() as usize)
|
||||
+ (ROM_BANK_SIZE * self.rom_bank as usize)
|
||||
+ (self.upper_banks as usize * 512 * KB)
|
||||
}
|
||||
|
||||
0xA000..0xC000 => panic!("passed ram address to rom address function"),
|
||||
_ => panic!("address {address} incompatible with MBC"),
|
||||
} % self.rom_len)
|
||||
}
|
||||
|
||||
fn get_ram_addr(&self, address: Address) -> usize {
|
||||
match address {
|
||||
0x0..0x8000 => panic!("passed rom address to ram address function"),
|
||||
0xA000..0xC000 => match self.bank_mode {
|
||||
fn get_ram_addr(&self, address: CartRamAddress) -> usize {
|
||||
match self.bank_mode {
|
||||
BankingMode::Simple => {
|
||||
(address - 0xA000) as usize + (RAM_BANK_SIZE * self.ram_bank as usize)
|
||||
(address.get_local() as usize) + (RAM_BANK_SIZE * self.ram_bank as usize)
|
||||
}
|
||||
BankingMode::Advanced => {
|
||||
(address - 0xA000) as usize
|
||||
(address.get_local() as usize)
|
||||
+ (RAM_BANK_SIZE * self.ram_bank as usize)
|
||||
+ (self.upper_banks as usize * 16 * KB)
|
||||
}
|
||||
},
|
||||
_ => panic!("address {address} incompatible with MBC"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,11 +97,11 @@ impl Mbc1 {
|
|||
}
|
||||
|
||||
impl Mbc for Mbc1 {
|
||||
fn get(&self, address: Address) -> u8 {
|
||||
fn get(&self, address: RomAddress) -> u8 {
|
||||
self.data[self.get_rom_addr(address)]
|
||||
}
|
||||
|
||||
fn get_ram(&self, address: Address) -> u8 {
|
||||
fn get_ram(&self, address: CartRamAddress) -> u8 {
|
||||
if self.ram_enabled && let Some(ram) = &self.ram {
|
||||
let addr = self.get_ram_addr(address) % ram.len();
|
||||
return ram.get(addr);
|
||||
|
@ -116,7 +109,7 @@ impl Mbc for Mbc1 {
|
|||
0xFF
|
||||
}
|
||||
|
||||
fn set_ram(&mut self, address: Address, data: u8) {
|
||||
fn set_ram(&mut self, address: CartRamAddress, data: u8) {
|
||||
let mut addr = self.get_ram_addr(address);
|
||||
if self.ram_enabled && let Some(ram) = &mut self.ram {
|
||||
addr %= ram.len();
|
||||
|
@ -124,8 +117,8 @@ impl Mbc for Mbc1 {
|
|||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, address: Address, data: u8) {
|
||||
match address {
|
||||
fn set(&mut self, address: RomAddress, data: u8) {
|
||||
match address.inner() {
|
||||
0x0..0x2000 => {
|
||||
// enable/disable ram
|
||||
self.ram_enabled = (data & 0x0F) == 0xA;
|
||||
|
|
|
@ -3,8 +3,8 @@ use std::path::PathBuf;
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::processor::memory::{
|
||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||
rom::{MaybeBufferedSram, MbcSaveState, SramSaveState},
|
||||
Address,
|
||||
};
|
||||
|
||||
use super::{rom_banks, Mbc, ROM_BANK_SIZE};
|
||||
|
@ -51,28 +51,27 @@ impl Mbc2 {
|
|||
}
|
||||
|
||||
impl Mbc for Mbc2 {
|
||||
fn get(&self, address: Address) -> u8 {
|
||||
fn get(&self, address: RomAddress) -> u8 {
|
||||
match address {
|
||||
0x0..0x4000 => self.data[address as usize],
|
||||
0x4000..0x8000 => {
|
||||
self.data[((address as usize - 0x4000) + (0x4000 * self.rom_bank as usize))
|
||||
RomAddress::Bank0(address) => self.data[address.inner() as usize],
|
||||
RomAddress::MappedBank(address) => {
|
||||
self.data[((address.get_local() as usize) + (0x4000 * self.rom_bank as usize))
|
||||
% self.rom_len]
|
||||
}
|
||||
_ => panic!("passed wrong address to mbc"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ram(&self, address: Address) -> u8 {
|
||||
fn get_ram(&self, address: CartRamAddress) -> u8 {
|
||||
if self.ram_enabled {
|
||||
0xF0 | (0x0F & self.ram.get((address - 0xA000) as usize % 512))
|
||||
0xF0 | (0x0F & self.ram.get((address.get_local() as usize) % 512))
|
||||
} else {
|
||||
0xFF
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, address: Address, data: u8) {
|
||||
if address < 0x4000 {
|
||||
if address & (1 << 8) == (1 << 8) {
|
||||
fn set(&mut self, address: RomAddress, data: u8) {
|
||||
if let RomAddress::Bank0(_) = address {
|
||||
if address.inner() & (1 << 8) == (1 << 8) {
|
||||
// bit 8 is set - rom bank
|
||||
self.rom_bank = data & 0xF;
|
||||
if self.rom_bank == 0 {
|
||||
|
@ -85,9 +84,9 @@ impl Mbc for Mbc2 {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_ram(&mut self, address: Address, data: u8) {
|
||||
fn set_ram(&mut self, address: CartRamAddress, data: u8) {
|
||||
if self.ram_enabled {
|
||||
self.ram.set((address - 0xA000) as usize % 512, data);
|
||||
self.ram.set((address.get_local() as usize) % 512, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ use serde::{Deserialize, Serialize};
|
|||
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||
use crate::{
|
||||
processor::memory::{
|
||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||
rom::{MaybeBufferedSram, MbcSaveState, SramSaveState},
|
||||
Address,
|
||||
},
|
||||
util::set_or_clear_bit,
|
||||
};
|
||||
|
@ -127,19 +127,18 @@ impl Mbc3 {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_rom_addr(&self, address: Address) -> usize {
|
||||
fn get_rom_addr(&self, address: RomAddress) -> usize {
|
||||
(match address {
|
||||
0x0..0x4000 => address as usize,
|
||||
0x4000..0x8000 => {
|
||||
let internal_addr = address as usize - 0x4000;
|
||||
RomAddress::Bank0(address) => address.inner() as usize,
|
||||
RomAddress::MappedBank(address) => {
|
||||
let internal_addr = address.get_local() as usize;
|
||||
internal_addr + (ROM_BANK_SIZE * self.rom_bank as usize)
|
||||
}
|
||||
_ => panic!("address {address} incompatible with MBC"),
|
||||
} % self.rom_size)
|
||||
}
|
||||
|
||||
fn get_ram_addr(&self, address: Address, ram_bank: usize) -> usize {
|
||||
((address as usize - 0xA000) + (RAM_BANK_SIZE * ram_bank)) % self.ram_size
|
||||
fn get_ram_addr(&self, address: CartRamAddress, ram_bank: usize) -> usize {
|
||||
((address.get_local() as usize) + (RAM_BANK_SIZE * ram_bank)) % self.ram_size
|
||||
}
|
||||
|
||||
pub fn from_save_state(state: Mbc3SaveState, data: Vec<u8>) -> Self {
|
||||
|
@ -158,11 +157,11 @@ impl Mbc3 {
|
|||
}
|
||||
|
||||
impl Mbc for Mbc3 {
|
||||
fn get(&self, address: Address) -> u8 {
|
||||
fn get(&self, address: RomAddress) -> u8 {
|
||||
self.data[self.get_rom_addr(address)]
|
||||
}
|
||||
|
||||
fn get_ram(&self, address: Address) -> u8 {
|
||||
fn get_ram(&self, address: CartRamAddress) -> u8 {
|
||||
if self.ram_enabled {
|
||||
match &self.ram_bank {
|
||||
RamBank::Ram(ram_bank) => {
|
||||
|
@ -180,8 +179,8 @@ impl Mbc for Mbc3 {
|
|||
0xFF
|
||||
}
|
||||
|
||||
fn set(&mut self, address: Address, data: u8) {
|
||||
match address {
|
||||
fn set(&mut self, address: RomAddress, data: u8) {
|
||||
match address.inner() {
|
||||
0x0..0x2000 => {
|
||||
if data & 0xF == 0xA {
|
||||
self.ram_enabled = true;
|
||||
|
@ -218,12 +217,11 @@ impl Mbc for Mbc3 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => panic!("unsupported addr"),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_ram(&mut self, address: Address, data: u8) {
|
||||
fn set_ram(&mut self, address: CartRamAddress, data: u8) {
|
||||
if self.ram_enabled {
|
||||
match &self.ram_bank {
|
||||
RamBank::Ram(ram_bank) => {
|
||||
|
|
|
@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::{
|
||||
processor::memory::{
|
||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||
rom::{MaybeBufferedSram, MbcSaveState, SramSaveState},
|
||||
Address,
|
||||
},
|
||||
util::get_bit,
|
||||
};
|
||||
|
@ -58,19 +58,18 @@ impl Mbc5 {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_rom_addr(&self, address: Address) -> usize {
|
||||
fn get_rom_addr(&self, address: RomAddress) -> usize {
|
||||
(match address {
|
||||
0x0..0x4000 => address as usize,
|
||||
0x4000..0x8000 => {
|
||||
let internal_addr = address as usize - 0x4000;
|
||||
RomAddress::Bank0(address) => address.inner() as usize,
|
||||
RomAddress::MappedBank(address) => {
|
||||
let internal_addr = address.get_local() as usize;
|
||||
internal_addr + (ROM_BANK_SIZE * self.rom_bank as usize)
|
||||
}
|
||||
_ => panic!("address {address} incompatible with MBC"),
|
||||
} % self.rom_size)
|
||||
}
|
||||
|
||||
fn get_ram_addr(&self, address: Address) -> usize {
|
||||
((address as usize - 0xA000) + (RAM_BANK_SIZE * self.ram_bank as usize)) % self.ram_size
|
||||
fn get_ram_addr(&self, address: CartRamAddress) -> usize {
|
||||
((address.get_local() as usize) + (RAM_BANK_SIZE * self.ram_bank as usize)) % self.ram_size
|
||||
}
|
||||
|
||||
pub fn from_save_state(state: Mbc5SaveState, data: Vec<u8>) -> Self {
|
||||
|
@ -89,11 +88,11 @@ impl Mbc5 {
|
|||
}
|
||||
|
||||
impl Mbc for Mbc5 {
|
||||
fn get(&self, address: Address) -> u8 {
|
||||
fn get(&self, address: RomAddress) -> u8 {
|
||||
self.data[self.get_rom_addr(address)]
|
||||
}
|
||||
|
||||
fn get_ram(&self, address: Address) -> u8 {
|
||||
fn get_ram(&self, address: CartRamAddress) -> u8 {
|
||||
if self.ram_enabled && let Some(ram) = &self.ram {
|
||||
ram.get(self.get_ram_addr(address))
|
||||
} else {
|
||||
|
@ -101,8 +100,8 @@ impl Mbc for Mbc5 {
|
|||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, address: Address, data: u8) {
|
||||
match address {
|
||||
fn set(&mut self, address: RomAddress, data: u8) {
|
||||
match address.inner() {
|
||||
0x0..0x2000 => {
|
||||
if (data & 0xF) == 0xA {
|
||||
self.ram_enabled = true
|
||||
|
@ -121,11 +120,11 @@ impl Mbc for Mbc5 {
|
|||
}
|
||||
}
|
||||
0x6000..0x8000 => {}
|
||||
_ => panic!("address {address} incompatible with MBC"),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_ram(&mut self, address: Address, data: u8) {
|
||||
fn set_ram(&mut self, address: CartRamAddress, data: u8) {
|
||||
let real_addr = self.get_ram_addr(address);
|
||||
if self.ram_enabled && let Some(ram) = &mut self.ram {
|
||||
ram.set(real_addr, data);
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use super::Mbc;
|
||||
use crate::processor::memory::{rom::MbcSaveState, Address};
|
||||
use crate::processor::memory::{
|
||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||
rom::MbcSaveState,
|
||||
};
|
||||
|
||||
pub struct None {
|
||||
data: Vec<u8>,
|
||||
|
@ -12,17 +15,17 @@ impl None {
|
|||
}
|
||||
|
||||
impl Mbc for None {
|
||||
fn get(&self, address: Address) -> u8 {
|
||||
self.data[address as usize]
|
||||
fn get(&self, address: RomAddress) -> u8 {
|
||||
self.data[address.inner() as usize]
|
||||
}
|
||||
|
||||
fn get_ram(&self, _address: Address) -> u8 {
|
||||
fn get_ram(&self, _address: CartRamAddress) -> u8 {
|
||||
0xFF
|
||||
}
|
||||
|
||||
fn set_ram(&mut self, _address: Address, _data: u8) {}
|
||||
fn set_ram(&mut self, _address: CartRamAddress, _data: u8) {}
|
||||
|
||||
fn set(&mut self, _address: Address, _data: u8) {}
|
||||
fn set(&mut self, _address: RomAddress, _data: u8) {}
|
||||
|
||||
fn mbc_type(&self) -> String {
|
||||
String::from("None")
|
||||
|
|
|
@ -2,8 +2,8 @@ use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
|||
use crate::{
|
||||
connect::{CameraWrapperRef, PocketCamera as PocketCameraTrait},
|
||||
processor::memory::{
|
||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||
rom::{MaybeBufferedSram, MbcSaveState},
|
||||
Address,
|
||||
},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -60,19 +60,18 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn get_rom_addr(&self, address: Address) -> usize {
|
||||
fn get_rom_addr(&self, address: RomAddress) -> usize {
|
||||
(match address {
|
||||
0x0..0x4000 => address as usize,
|
||||
0x4000..0x8000 => {
|
||||
let internal_addr = address as usize - 0x4000;
|
||||
RomAddress::Bank0(address) => address.inner() as usize,
|
||||
RomAddress::MappedBank(address) => {
|
||||
let internal_addr = address.get_local() as usize;
|
||||
internal_addr + (ROM_BANK_SIZE * self.rom_bank as usize)
|
||||
}
|
||||
_ => panic!("address {address} incompatible with MBC"),
|
||||
} % self.rom_size)
|
||||
}
|
||||
|
||||
fn get_ram_addr(&self, address: Address, bank: u8) -> usize {
|
||||
((address as usize - 0xA000) + (RAM_BANK_SIZE * bank as usize)) % self.ram_size
|
||||
fn get_ram_addr(&self, address: CartRamAddress, bank: u8) -> usize {
|
||||
((address.get_local() as usize) + (RAM_BANK_SIZE * bank as usize)) % self.ram_size
|
||||
}
|
||||
|
||||
pub(crate) fn from_save_state(
|
||||
|
@ -83,8 +82,8 @@ where
|
|||
todo!();
|
||||
}
|
||||
|
||||
fn get_cam_reg(&self, address: Address) -> u8 {
|
||||
match address {
|
||||
fn get_cam_reg(&self, address: CartRamAddress) -> u8 {
|
||||
match address.inner() {
|
||||
0xA000 => {
|
||||
(if self.camera.lock().unwrap().is_capturing() {
|
||||
0x1
|
||||
|
@ -92,13 +91,13 @@ where
|
|||
0x0
|
||||
}) | self.extra_bits_a000
|
||||
}
|
||||
0xA001..=0xA035 => self.camera_ram[(address - 0xA001) as usize],
|
||||
0xA001..=0xA035 => self.camera_ram[(address.inner() - 0xA001) as usize],
|
||||
_ => 0x00,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_cam_reg(&mut self, address: Address, data: u8) {
|
||||
match address {
|
||||
fn set_cam_reg(&mut self, address: CartRamAddress, data: u8) {
|
||||
match address.inner() {
|
||||
0xA000 => {
|
||||
if data & 0x1 == 0x1 {
|
||||
self.camera.lock().unwrap().begin_capture();
|
||||
|
@ -106,7 +105,7 @@ where
|
|||
self.extra_bits_a000 = data & 0b110;
|
||||
}
|
||||
0xA001..=0xA035 => {
|
||||
self.camera_ram[(address - 0xA001) as usize] = data;
|
||||
self.camera_ram[(address.inner() - 0xA001) as usize] = data;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -127,11 +126,11 @@ impl<C> Mbc for PocketCamera<C>
|
|||
where
|
||||
C: PocketCameraTrait + Send,
|
||||
{
|
||||
fn get(&self, address: Address) -> u8 {
|
||||
fn get(&self, address: RomAddress) -> u8 {
|
||||
self.data[self.get_rom_addr(address)]
|
||||
}
|
||||
|
||||
fn get_ram(&self, address: Address) -> u8 {
|
||||
fn get_ram(&self, address: CartRamAddress) -> u8 {
|
||||
match self.ram_bank {
|
||||
RamBank::Ram(bank) => {
|
||||
if let Some(ram) = &self.ram {
|
||||
|
@ -144,9 +143,9 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, address: Address, data: u8) {
|
||||
fn set(&mut self, address: RomAddress, data: u8) {
|
||||
self.check_for_new_image();
|
||||
match address {
|
||||
match address.inner() {
|
||||
0x0..0x2000 => {
|
||||
if (data & 0xF) == 0xA {
|
||||
self.ram_enabled = true
|
||||
|
@ -167,11 +166,11 @@ where
|
|||
}
|
||||
}
|
||||
0x6000..0x8000 => {}
|
||||
_ => panic!("address {address} incompatible with MBC"),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_ram(&mut self, address: Address, data: u8) {
|
||||
fn set_ram(&mut self, address: CartRamAddress, data: u8) {
|
||||
self.check_for_new_image();
|
||||
match self.ram_bank {
|
||||
RamBank::Ram(bank) => {
|
||||
|
|
Loading…
Reference in a new issue