camera builds!
This commit is contained in:
parent
533cb42152
commit
bceb8b0ea4
|
@ -36,4 +36,12 @@ impl PocketCamera for Webcam {
|
||||||
}
|
}
|
||||||
buffer
|
buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn begin_capture(&mut self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_capturing(&self) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,10 @@ impl AudioOutput {
|
||||||
pub trait PocketCamera {
|
pub trait PocketCamera {
|
||||||
// resolution - 128x128
|
// resolution - 128x128
|
||||||
fn capture_greyscale(&mut self) -> [u8; 128 * 128];
|
fn capture_greyscale(&mut self) -> [u8; 128 * 128];
|
||||||
|
|
||||||
|
fn begin_capture(&mut self);
|
||||||
|
|
||||||
|
fn is_capturing(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NoCamera;
|
pub struct NoCamera;
|
||||||
|
@ -76,6 +80,12 @@ impl PocketCamera for NoCamera {
|
||||||
fn capture_greyscale(&mut self) -> [u8; 128 * 128] {
|
fn capture_greyscale(&mut self) -> [u8; 128 * 128] {
|
||||||
[0; 128 * 128]
|
[0; 128 * 128]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn begin_capture(&mut self) {}
|
||||||
|
|
||||||
|
fn is_capturing(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
@ -83,7 +93,7 @@ pub struct EmulatorOptions<ColourFormat, R, C>
|
||||||
where
|
where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
C: PocketCamera,
|
C: PocketCamera + Send + 'static,
|
||||||
{
|
{
|
||||||
pub(crate) window: R,
|
pub(crate) window: R,
|
||||||
pub(crate) tile_window: Option<R>,
|
pub(crate) tile_window: Option<R>,
|
||||||
|
@ -124,7 +134,7 @@ impl<ColourFormat, R, C> EmulatorOptions<ColourFormat, R, C>
|
||||||
where
|
where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
C: PocketCamera,
|
C: PocketCamera + Send + 'static,
|
||||||
{
|
{
|
||||||
pub fn new_with_camera(window: R, rom: RomFile, output: AudioOutput, camera: C) -> Self {
|
pub fn new_with_camera(window: R, rom: RomFile, output: AudioOutput, camera: C) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
use crate::{processor::memory::Memory, util::pause};
|
use crate::{processor::memory::Memory, util::pause};
|
||||||
use connect::{
|
use connect::{
|
||||||
AudioOutput, EmulatorMessage, EmulatorOptions, PocketCamera, Renderer, RomFile, SerialTarget,
|
AudioOutput, EmulatorMessage, EmulatorOptions, NoCamera, PocketCamera, Renderer, RomFile,
|
||||||
|
SerialTarget,
|
||||||
};
|
};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use processor::{
|
use processor::{
|
||||||
|
@ -37,10 +38,10 @@ pub struct EmulatorCore<ColourFormat, R, C>
|
||||||
where
|
where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
C: PocketCamera,
|
C: PocketCamera + Send + 'static,
|
||||||
{
|
{
|
||||||
receiver: Receiver<EmulatorMessage>,
|
receiver: Receiver<EmulatorMessage>,
|
||||||
cpu: Cpu<ColourFormat, R>,
|
cpu: Cpu<ColourFormat, R, C>,
|
||||||
spooky: PhantomData<C>,
|
spooky: PhantomData<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ impl<ColourFormat, R, C> EmulatorCore<ColourFormat, R, C>
|
||||||
where
|
where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
C: PocketCamera,
|
C: PocketCamera + Send + 'static,
|
||||||
{
|
{
|
||||||
pub fn init(
|
pub fn init(
|
||||||
receiver: Receiver<EmulatorMessage>,
|
receiver: Receiver<EmulatorMessage>,
|
||||||
|
@ -71,14 +72,14 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
match fs::read(path) {
|
match fs::read(path) {
|
||||||
Ok(data) => Rom::load(data, maybe_save),
|
Ok(data) => Rom::load(data, maybe_save, options.camera),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error reading ROM: {e}");
|
println!("Error reading ROM: {e}");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RomFile::Raw(data) => Rom::load(data, None),
|
RomFile::Raw(data) => Rom::load(data, None, options.camera),
|
||||||
};
|
};
|
||||||
|
|
||||||
options.window.prepare(WIDTH, HEIGHT);
|
options.window.prepare(WIDTH, HEIGHT);
|
||||||
|
@ -114,7 +115,7 @@ where
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(receiver: Receiver<EmulatorMessage>, cpu: Cpu<ColourFormat, R>) -> Self {
|
fn new(receiver: Receiver<EmulatorMessage>, cpu: Cpu<ColourFormat, R, C>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
receiver,
|
receiver,
|
||||||
cpu,
|
cpu,
|
||||||
|
@ -178,7 +179,13 @@ where
|
||||||
{
|
{
|
||||||
CpuSaveState::create(&self.cpu)
|
CpuSaveState::create(&self.cpu)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<ColourFormat, R> EmulatorCore<ColourFormat, R, NoCamera>
|
||||||
|
where
|
||||||
|
ColourFormat: From<Colour> + Clone,
|
||||||
|
R: Renderer<ColourFormat>,
|
||||||
|
{
|
||||||
pub fn from_save_state(
|
pub fn from_save_state(
|
||||||
state: CpuSaveState<ColourFormat, R>,
|
state: CpuSaveState<ColourFormat, R>,
|
||||||
rom: RomFile,
|
rom: RomFile,
|
||||||
|
@ -199,7 +206,7 @@ where
|
||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
receiver,
|
receiver,
|
||||||
cpu: Cpu::from_save_state(state, data, window, output, serial_target),
|
cpu: Cpu::from_save_state(state, data, window, output, serial_target, NoCamera),
|
||||||
spooky: PhantomData,
|
spooky: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
connect::Renderer,
|
connect::{PocketCamera, Renderer},
|
||||||
processor::{memory::mmio::gpu::Colour, Cpu, Direction, Flags, Reg8, SplitRegister},
|
processor::{memory::mmio::gpu::Colour, Cpu, Direction, Flags, Reg8, SplitRegister},
|
||||||
util::{clear_bit, get_bit, set_bit},
|
util::{clear_bit, get_bit, set_bit},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<ColourFormat, R> Cpu<ColourFormat, R>
|
impl<ColourFormat, R, C> Cpu<ColourFormat, R, C>
|
||||||
where
|
where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
|
C: PocketCamera + Send + 'static,
|
||||||
{
|
{
|
||||||
pub(crate) fn and(&mut self, first: u8, second: u8) -> u8 {
|
pub(crate) fn and(&mut self, first: u8, second: u8) -> u8 {
|
||||||
let result = first & second;
|
let result = first & second;
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
connect::Renderer,
|
connect::{PocketCamera, Renderer},
|
||||||
processor::{memory::mmio::gpu::Colour, Cpu, Direction, Flags, SplitRegister},
|
processor::{memory::mmio::gpu::Colour, Cpu, Direction, Flags, SplitRegister},
|
||||||
util::{as_signed, get_bit, get_rotation_carry, rotate, Nibbles},
|
util::{as_signed, get_bit, get_rotation_carry, rotate, Nibbles},
|
||||||
};
|
};
|
||||||
use std::ops::{BitAnd, BitOr};
|
use std::ops::{BitAnd, BitOr};
|
||||||
|
|
||||||
impl<ColourFormat, R> Cpu<ColourFormat, R>
|
impl<ColourFormat, R, C> Cpu<ColourFormat, R, C>
|
||||||
where
|
where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
|
C: PocketCamera + Send + 'static,
|
||||||
{
|
{
|
||||||
pub(crate) fn pop_word(&mut self) -> u16 {
|
pub(crate) fn pop_word(&mut self) -> u16 {
|
||||||
let mut word: u16 = 0x0;
|
let mut word: u16 = 0x0;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use self::{
|
||||||
rom::RomSaveState,
|
rom::RomSaveState,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
connect::{AudioOutput, JoypadState, Renderer, SerialTarget},
|
connect::{AudioOutput, JoypadState, PocketCamera, Renderer, SerialTarget},
|
||||||
processor::SplitRegister,
|
processor::SplitRegister,
|
||||||
verbose_println, Cpu,
|
verbose_println, Cpu,
|
||||||
};
|
};
|
||||||
|
@ -22,13 +22,14 @@ pub(crate) mod rom;
|
||||||
|
|
||||||
pub(crate) type Address = u16;
|
pub(crate) type Address = u16;
|
||||||
|
|
||||||
pub struct Memory<ColourFormat, R>
|
pub struct Memory<ColourFormat, R, C>
|
||||||
where
|
where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
|
C: PocketCamera + Send + 'static,
|
||||||
{
|
{
|
||||||
bootrom: Option<Vec<u8>>,
|
bootrom: Option<Vec<u8>>,
|
||||||
rom: Rom,
|
rom: Rom<C>,
|
||||||
ram: [u8; 8192],
|
ram: [u8; 8192],
|
||||||
cpu_ram: [u8; 128],
|
cpu_ram: [u8; 128],
|
||||||
pub(super) interrupts: Interrupts,
|
pub(super) interrupts: Interrupts,
|
||||||
|
@ -69,8 +70,9 @@ impl<ColourFormat, R> MemorySaveState<ColourFormat, R>
|
||||||
where
|
where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
|
// C: PocketCamera + Send + 'static,
|
||||||
{
|
{
|
||||||
pub fn create(memory: &Memory<ColourFormat, R>) -> Self {
|
pub fn create<C: PocketCamera + Send + 'static>(memory: &Memory<ColourFormat, R, C>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
rom: RomSaveState::create(&memory.rom),
|
rom: RomSaveState::create(&memory.rom),
|
||||||
ram: memory.ram,
|
ram: memory.ram,
|
||||||
|
@ -88,14 +90,15 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ColourFormat, R> Memory<ColourFormat, R>
|
impl<ColourFormat, R, C> Memory<ColourFormat, R, C>
|
||||||
where
|
where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
|
C: PocketCamera + Send + 'static,
|
||||||
{
|
{
|
||||||
pub fn init(
|
pub fn init(
|
||||||
bootrom: Option<Vec<u8>>,
|
bootrom: Option<Vec<u8>>,
|
||||||
rom: Rom,
|
rom: Rom<C>,
|
||||||
window: R,
|
window: R,
|
||||||
output: AudioOutput,
|
output: AudioOutput,
|
||||||
serial_target: SerialTarget,
|
serial_target: SerialTarget,
|
||||||
|
@ -295,10 +298,11 @@ where
|
||||||
window: R,
|
window: R,
|
||||||
output: AudioOutput,
|
output: AudioOutput,
|
||||||
serial_target: SerialTarget,
|
serial_target: SerialTarget,
|
||||||
|
camera: C,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bootrom: None,
|
bootrom: None,
|
||||||
rom: Rom::from_save_state(state.rom, data),
|
rom: Rom::from_save_state(state.rom, data, camera),
|
||||||
ram: state.ram,
|
ram: state.ram,
|
||||||
cpu_ram: state.cpu_ram,
|
cpu_ram: state.cpu_ram,
|
||||||
interrupts: state.interrupts,
|
interrupts: state.interrupts,
|
||||||
|
@ -314,10 +318,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ColourFormat, R> Cpu<ColourFormat, R>
|
impl<ColourFormat, R, C> Cpu<ColourFormat, R, C>
|
||||||
where
|
where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
|
C: PocketCamera + Send + 'static,
|
||||||
{
|
{
|
||||||
pub fn increment_timers(&mut self, machine_cycles: u8) {
|
pub fn increment_timers(&mut self, machine_cycles: u8) {
|
||||||
let steps = (machine_cycles as usize) * 4;
|
let steps = (machine_cycles as usize) * 4;
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::processor::memory::Address;
|
use crate::{connect::PocketCamera as PocketCameraTrait, processor::memory::Address};
|
||||||
use std::{
|
use std::{
|
||||||
fs::{File, OpenOptions},
|
fs::{File, OpenOptions},
|
||||||
io::{Read, Seek, SeekFrom, Write},
|
io::{Read, Seek, SeekFrom, Write},
|
||||||
|
marker::PhantomData,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
str::from_utf8_unchecked,
|
str::from_utf8_unchecked,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::mbcs::{
|
use self::mbcs::{
|
||||||
Mbc, Mbc1, Mbc1SaveState, Mbc2, Mbc2SaveState, Mbc3, Mbc3SaveState, Mbc5, Mbc5SaveState, None,
|
Mbc, Mbc1, Mbc1SaveState, Mbc2, Mbc2SaveState, Mbc3, Mbc3SaveState, Mbc5, Mbc5SaveState, None,
|
||||||
|
PocketCamera, PocketCameraSaveState,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod mbcs;
|
mod mbcs;
|
||||||
|
@ -120,9 +122,13 @@ impl Drop for MaybeBufferedSram {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Rom {
|
pub struct Rom<C>
|
||||||
|
where
|
||||||
|
C: PocketCameraTrait,
|
||||||
|
{
|
||||||
title: String,
|
title: String,
|
||||||
mbc: Box<dyn Mbc>,
|
mbc: Box<dyn Mbc>,
|
||||||
|
spooky: PhantomData<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
@ -132,7 +138,7 @@ pub struct RomSaveState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RomSaveState {
|
impl RomSaveState {
|
||||||
pub fn create(rom: &Rom) -> Self {
|
pub fn create<C: PocketCameraTrait>(rom: &Rom<C>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: rom.title.clone(),
|
title: rom.title.clone(),
|
||||||
mbc: rom.mbc.get_save_state(),
|
mbc: rom.mbc.get_save_state(),
|
||||||
|
@ -146,23 +152,34 @@ enum MbcSaveState {
|
||||||
Mbc2(Mbc2SaveState),
|
Mbc2(Mbc2SaveState),
|
||||||
Mbc3(Mbc3SaveState),
|
Mbc3(Mbc3SaveState),
|
||||||
Mbc5(Mbc5SaveState),
|
Mbc5(Mbc5SaveState),
|
||||||
|
PocketCamera(PocketCameraSaveState),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MbcSaveState {
|
impl MbcSaveState {
|
||||||
fn get_mbc(self, data: Vec<u8>) -> Box<dyn Mbc> {
|
fn get_mbc<C: PocketCameraTrait + Send + 'static>(
|
||||||
|
self,
|
||||||
|
data: Vec<u8>,
|
||||||
|
camera: C,
|
||||||
|
) -> Box<dyn Mbc> {
|
||||||
match self {
|
match self {
|
||||||
MbcSaveState::Mbc1(state) => Box::new(Mbc1::from_save_state(state, data)),
|
MbcSaveState::Mbc1(state) => Box::new(Mbc1::from_save_state(state, data)),
|
||||||
MbcSaveState::Mbc2(state) => Box::new(Mbc2::from_save_state(state, data)),
|
MbcSaveState::Mbc2(state) => Box::new(Mbc2::from_save_state(state, data)),
|
||||||
MbcSaveState::Mbc3(state) => Box::new(Mbc3::from_save_state(state, data)),
|
MbcSaveState::Mbc3(state) => Box::new(Mbc3::from_save_state(state, data)),
|
||||||
MbcSaveState::Mbc5(state) => Box::new(Mbc5::from_save_state(state, data)),
|
MbcSaveState::Mbc5(state) => Box::new(Mbc5::from_save_state(state, data)),
|
||||||
MbcSaveState::None => Box::new(None::init(data)),
|
MbcSaveState::None => Box::new(None::init(data)),
|
||||||
|
MbcSaveState::PocketCamera(state) => {
|
||||||
|
Box::new(PocketCamera::from_save_state(state, data, camera))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rom {
|
impl<C> Rom<C>
|
||||||
pub fn load(data: Vec<u8>, save_path: Option<PathBuf>) -> Self {
|
where
|
||||||
|
C: PocketCameraTrait + Send + 'static,
|
||||||
|
{
|
||||||
|
pub fn load(data: Vec<u8>, save_path: Option<PathBuf>, camera: C) -> Self {
|
||||||
let mut title_length = 0x143;
|
let mut title_length = 0x143;
|
||||||
for (i, val) in data.iter().enumerate().take(0x143).skip(0x134) {
|
for (i, val) in data.iter().enumerate().take(0x143).skip(0x134) {
|
||||||
title_length = i;
|
title_length = i;
|
||||||
|
@ -195,15 +212,23 @@ impl Rom {
|
||||||
0x1C => Box::new(Mbc5::init(data, rom_size, 0, true, None)),
|
0x1C => Box::new(Mbc5::init(data, rom_size, 0, true, None)),
|
||||||
0x1D => Box::new(Mbc5::init(data, rom_size, ram_size, true, None)),
|
0x1D => Box::new(Mbc5::init(data, rom_size, ram_size, true, None)),
|
||||||
0x1E => Box::new(Mbc5::init(data, rom_size, ram_size, true, save_path)),
|
0x1E => Box::new(Mbc5::init(data, rom_size, ram_size, true, save_path)),
|
||||||
|
0xFC => Box::new(PocketCamera::init(
|
||||||
|
data, rom_size, ram_size, save_path, camera,
|
||||||
|
)),
|
||||||
_ => panic!("unimplemented mbc: {:#X}", data[0x147]),
|
_ => panic!("unimplemented mbc: {:#X}", data[0x147]),
|
||||||
};
|
};
|
||||||
Self { title, mbc }
|
Self {
|
||||||
|
title,
|
||||||
|
mbc,
|
||||||
|
spooky: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_save_state(state: RomSaveState, data: Vec<u8>) -> Self {
|
pub fn from_save_state(state: RomSaveState, data: Vec<u8>, camera: C) -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: state.title,
|
title: state.title,
|
||||||
mbc: state.mbc.get_mbc(data),
|
mbc: state.mbc.get_mbc(data, camera),
|
||||||
|
spooky: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,13 @@ mod mbc2;
|
||||||
mod mbc3;
|
mod mbc3;
|
||||||
mod mbc5;
|
mod mbc5;
|
||||||
mod none;
|
mod none;
|
||||||
|
mod pocketcamera;
|
||||||
pub use mbc1::{Mbc1, Mbc1SaveState};
|
pub use mbc1::{Mbc1, Mbc1SaveState};
|
||||||
pub use mbc2::{Mbc2, Mbc2SaveState};
|
pub use mbc2::{Mbc2, Mbc2SaveState};
|
||||||
pub use mbc3::{Mbc3, Mbc3SaveState};
|
pub use mbc3::{Mbc3, Mbc3SaveState};
|
||||||
pub use mbc5::{Mbc5, Mbc5SaveState};
|
pub use mbc5::{Mbc5, Mbc5SaveState};
|
||||||
pub use none::None;
|
pub use none::None;
|
||||||
|
pub use pocketcamera::{PocketCamera, PocketCameraSaveState};
|
||||||
|
|
||||||
use super::MbcSaveState;
|
use super::MbcSaveState;
|
||||||
|
|
||||||
|
|
181
lib/src/processor/memory/rom/mbcs/pocketcamera.rs
Normal file
181
lib/src/processor/memory/rom/mbcs/pocketcamera.rs
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||||
|
use crate::{
|
||||||
|
connect::PocketCamera as PocketCameraTrait,
|
||||||
|
processor::memory::{
|
||||||
|
rom::{MaybeBufferedSram, MbcSaveState},
|
||||||
|
Address,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
enum RamBank {
|
||||||
|
Ram(u8),
|
||||||
|
Camera,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PocketCamera<C>
|
||||||
|
where
|
||||||
|
C: PocketCameraTrait,
|
||||||
|
{
|
||||||
|
data: Vec<u8>,
|
||||||
|
rom_bank: u8,
|
||||||
|
rom_size: usize,
|
||||||
|
ram: Option<MaybeBufferedSram>,
|
||||||
|
ram_bank: RamBank,
|
||||||
|
ram_size: usize,
|
||||||
|
ram_enabled: bool,
|
||||||
|
camera: C,
|
||||||
|
extra_bits_a000: u8,
|
||||||
|
camera_ram: [u8; 52],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct PocketCameraSaveState;
|
||||||
|
|
||||||
|
impl<C> PocketCamera<C>
|
||||||
|
where
|
||||||
|
C: PocketCameraTrait,
|
||||||
|
{
|
||||||
|
pub fn init(
|
||||||
|
data: Vec<u8>,
|
||||||
|
rom_size: u8,
|
||||||
|
ram_size: u8,
|
||||||
|
save_file: Option<PathBuf>,
|
||||||
|
camera: C,
|
||||||
|
) -> Self {
|
||||||
|
let ram = ram_size_kb(ram_size).map(|s| MaybeBufferedSram::new(save_file, s * KB));
|
||||||
|
Self {
|
||||||
|
data,
|
||||||
|
rom_bank: 1,
|
||||||
|
rom_size: rom_banks(rom_size) * ROM_BANK_SIZE,
|
||||||
|
ram,
|
||||||
|
ram_bank: RamBank::Ram(0),
|
||||||
|
ram_size: ram_size_kb(ram_size).map_or(1, |s| s * KB),
|
||||||
|
ram_enabled: false,
|
||||||
|
camera,
|
||||||
|
extra_bits_a000: 0,
|
||||||
|
camera_ram: [0; 52],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_rom_addr(&self, address: Address) -> usize {
|
||||||
|
(match address {
|
||||||
|
0x0..0x4000 => address as usize,
|
||||||
|
0x4000..0x8000 => {
|
||||||
|
let internal_addr = address as usize - 0x4000;
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_save_state(_state: PocketCameraSaveState, _data: Vec<u8>, _camera: C) -> Self {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cam_reg(&self, address: Address) -> u8 {
|
||||||
|
match address {
|
||||||
|
0xA000 => (if self.camera.is_capturing() { 0x1 } else { 0x0 }) | self.extra_bits_a000,
|
||||||
|
_ => 0x00,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_cam_reg(&mut self, address: Address, data: u8) {
|
||||||
|
match address {
|
||||||
|
0xA000 => {
|
||||||
|
if data & 0x1 == 0x1 {
|
||||||
|
self.camera.begin_capture();
|
||||||
|
}
|
||||||
|
self.extra_bits_a000 = data & 0b110;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> Mbc for PocketCamera<C>
|
||||||
|
where
|
||||||
|
C: PocketCameraTrait + Send,
|
||||||
|
{
|
||||||
|
fn get(&self, address: Address) -> u8 {
|
||||||
|
self.data[self.get_rom_addr(address)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ram(&self, address: Address) -> u8 {
|
||||||
|
match self.ram_bank {
|
||||||
|
RamBank::Ram(bank) => {
|
||||||
|
if let Some(ram) = &self.ram {
|
||||||
|
ram.get(self.get_ram_addr(address, bank))
|
||||||
|
} else {
|
||||||
|
0xFF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RamBank::Camera => self.get_cam_reg(address),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&mut self, address: Address, data: u8) {
|
||||||
|
match address {
|
||||||
|
0x0..0x2000 => {
|
||||||
|
if (data & 0xF) == 0xA {
|
||||||
|
self.ram_enabled = true
|
||||||
|
} else {
|
||||||
|
self.ram_enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0x2000..0x4000 => {
|
||||||
|
if data < 0x40 {
|
||||||
|
self.rom_bank = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0x4000..0x6000 => {
|
||||||
|
self.ram_bank = if data & 0xF0 != 0 {
|
||||||
|
RamBank::Camera
|
||||||
|
} else {
|
||||||
|
RamBank::Ram(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0x6000..0x8000 => {}
|
||||||
|
_ => panic!("address {address} incompatible with MBC"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_ram(&mut self, address: Address, data: u8) {
|
||||||
|
match self.ram_bank {
|
||||||
|
RamBank::Ram(bank) => {
|
||||||
|
let real_addr = self.get_ram_addr(address, bank);
|
||||||
|
if self.ram_enabled && let Some(ram) = &mut self.ram {
|
||||||
|
ram.set(real_addr, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RamBank::Camera => self.set_cam_reg(address, data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mbc_type(&self) -> String {
|
||||||
|
if let Some(ram) = &self.ram {
|
||||||
|
format!(
|
||||||
|
"{}KB Pocket Camera with {}KB RAM",
|
||||||
|
self.rom_size / KB,
|
||||||
|
ram.len() / KB,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!("{}KB Pocket Camera", self.rom_size / KB)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) {
|
||||||
|
if let Some(ref mut ram) = self.ram {
|
||||||
|
ram.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_save_state(&self) -> MbcSaveState {
|
||||||
|
MbcSaveState::PocketCamera(PocketCameraSaveState)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use self::memory::{mmio::gpu::Colour, Interrupt, Memory, MemorySaveState};
|
use self::memory::{mmio::gpu::Colour, Interrupt, Memory, MemorySaveState};
|
||||||
use crate::{
|
use crate::{
|
||||||
connect::{AudioOutput, Renderer, SerialTarget},
|
connect::{AudioOutput, PocketCamera, Renderer, SerialTarget},
|
||||||
verbose_println,
|
verbose_println,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,12 +23,13 @@ pub(crate) enum Direction {
|
||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Cpu<ColourFormat, R>
|
pub struct Cpu<ColourFormat, R, C>
|
||||||
where
|
where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
|
C: PocketCamera + Send + 'static,
|
||||||
{
|
{
|
||||||
pub memory: Memory<ColourFormat, R>,
|
pub memory: Memory<ColourFormat, R, C>,
|
||||||
pub reg: Registers,
|
pub reg: Registers,
|
||||||
pub last_instruction: u8,
|
pub last_instruction: u8,
|
||||||
last_instruction_addr: u16,
|
last_instruction_addr: u16,
|
||||||
|
@ -55,7 +56,7 @@ where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
{
|
{
|
||||||
pub fn create(cpu: &Cpu<ColourFormat, R>) -> Self {
|
pub fn create<C: PocketCamera + Send + 'static>(cpu: &Cpu<ColourFormat, R, C>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
memory: MemorySaveState::create(&cpu.memory),
|
memory: MemorySaveState::create(&cpu.memory),
|
||||||
reg: cpu.reg,
|
reg: cpu.reg,
|
||||||
|
@ -67,12 +68,13 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ColourFormat, R> Cpu<ColourFormat, R>
|
impl<ColourFormat, R, C> Cpu<ColourFormat, R, C>
|
||||||
where
|
where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
|
C: PocketCamera + Send + 'static,
|
||||||
{
|
{
|
||||||
pub fn new(mut memory: Memory<ColourFormat, R>, run_bootrom: bool) -> Self {
|
pub fn new(mut memory: Memory<ColourFormat, R, C>, run_bootrom: bool) -> Self {
|
||||||
if !run_bootrom {
|
if !run_bootrom {
|
||||||
memory.cpu_ram_init();
|
memory.cpu_ram_init();
|
||||||
}
|
}
|
||||||
|
@ -176,9 +178,17 @@ where
|
||||||
window: R,
|
window: R,
|
||||||
output: AudioOutput,
|
output: AudioOutput,
|
||||||
serial_target: SerialTarget,
|
serial_target: SerialTarget,
|
||||||
|
camera: C,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
memory: Memory::from_save_state(state.memory, data, window, output, serial_target),
|
memory: Memory::from_save_state(
|
||||||
|
state.memory,
|
||||||
|
data,
|
||||||
|
window,
|
||||||
|
output,
|
||||||
|
serial_target,
|
||||||
|
camera,
|
||||||
|
),
|
||||||
reg: state.reg,
|
reg: state.reg,
|
||||||
last_instruction: state.last_instruction,
|
last_instruction: state.last_instruction,
|
||||||
last_instruction_addr: state.last_instruction_addr,
|
last_instruction_addr: state.last_instruction_addr,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
connect::Renderer,
|
connect::{PocketCamera, Renderer},
|
||||||
processor::{
|
processor::{
|
||||||
instructions::instructions::{res, set},
|
instructions::instructions::{res, set},
|
||||||
Cpu, Flags, Reg8, SplitRegister,
|
Cpu, Flags, Reg8, SplitRegister,
|
||||||
|
@ -9,10 +9,11 @@ use crate::{
|
||||||
|
|
||||||
use super::memory::mmio::gpu::Colour;
|
use super::memory::mmio::gpu::Colour;
|
||||||
|
|
||||||
impl<ColourFormat, R> Cpu<ColourFormat, R>
|
impl<ColourFormat, R, C> Cpu<ColourFormat, R, C>
|
||||||
where
|
where
|
||||||
ColourFormat: From<Colour> + Clone,
|
ColourFormat: From<Colour> + Clone,
|
||||||
R: Renderer<ColourFormat>,
|
R: Renderer<ColourFormat>,
|
||||||
|
C: PocketCamera + Send + 'static,
|
||||||
{
|
{
|
||||||
pub fn run_opcode(&mut self, opcode: u8) -> u8 {
|
pub fn run_opcode(&mut self, opcode: u8) -> u8 {
|
||||||
match opcode {
|
match opcode {
|
||||||
|
|
Loading…
Reference in a new issue