Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions core/src/emulator/comm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub enum EmulatorCommand {
/// Toggle automatic writeback for a floppy drive.
/// Parameters: drive id, enabled
SetFloppyWriteback(usize, bool),
SlimInsert(usize, PathBuf, bool),
SlimEject(usize),
ScsiAttachHdd(usize, PathBuf),
ScsiBranchHdd(usize, PathBuf),
ScsiAttachCdrom(usize),
Expand Down Expand Up @@ -134,6 +136,8 @@ pub struct EmulatorStatus {
pub fdd: [FddStatus; 3],
pub model: MacModel,
pub has_pmmu: bool,
pub has_slim: bool,
pub slim: [Option<SlimSlotStatus>; 2],
pub speed: EmulatorSpeed,
pub effective_speed: f64,
pub scsi: [Option<ScsiTargetStatus>; 7],
Expand Down Expand Up @@ -178,6 +182,13 @@ pub struct FddStatus {
pub writeback_enabled: bool,
}

#[derive(Debug, Clone)]
pub struct SlimSlotStatus {
pub image: PathBuf,
pub size: usize,
pub write_protect: bool,
}

/// A friendly message ready for display to a user
#[derive(Debug)]
pub enum UserMessageType {
Expand Down
82 changes: 79 additions & 3 deletions core/src/emulator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::mac::compact::bus::{CompactMacBus, RAM_DIRTY_PAGESIZE};
use crate::mac::macii::bus::{DEFAULT_BUS_SPEED, MacIIBus};
use crate::mac::portable::bus::MacPortableBus;
use crate::mac::scc::Scc;
use crate::mac::scsi::disk_image::FileDiskImage;
use crate::mac::scsi::target::ScsiTargetEvent;
use crate::mac::serial_bridge::{SccBridge, SerialBridgeStatus};
use crate::mac::swim::drive::DriveType;
Expand All @@ -51,7 +52,7 @@ use crate::mac::scsi::disk_image::DiskImage;
use crate::mac::swim::Swim;
use comm::{
Breakpoint, EmulatorCommand, EmulatorCommandSender, EmulatorEvent, EmulatorEventReceiver,
EmulatorStatus, FddStatus, InputRecording, ScsiTargetStatus,
EmulatorStatus, FddStatus, InputRecording, ScsiTargetStatus, SlimSlotStatus,
};

/// Mouse emulation mode
Expand Down Expand Up @@ -237,6 +238,44 @@ dispatch! {
}
}

impl EmulatorConfig {
/// Returns true if a SLIM card adapter is installed
fn has_slim(&self) -> bool {
match self {
Self::Portable(cpu) => cpu.bus.slim_installed(),
_ => false,
}
}

/// Returns the status of the SLIM card slots
fn slim_status(&self) -> [Option<SlimSlotStatus>; 2] {
match self {
Self::Portable(cpu) => cpu.bus.slim_status(),
_ => Default::default(),
}
}

/// Inserts a SLIM card image into a slot
fn slim_insert(&mut self, slot: usize, filename: &Path, write_protect: bool) -> Result<()> {
match self {
Self::Portable(cpu) => {
cpu.bus.slim_eject(slot)?;
let image = FileDiskImage::open(filename, !write_protect)?;
cpu.bus.slim_insert(slot, Box::new(image), write_protect)
}
_ => bail!("SLIM cards not supported on this model"),
}
}

/// Ejects the SLIM card from a slot
fn slim_eject(&mut self, slot: usize) -> Result<()> {
match self {
Self::Portable(cpu) => cpu.bus.slim_eject(slot),
_ => bail!("SLIM cards not supported on this model"),
}
}
}

/// An interface that allows sub-components to access emulator state (such as the speed setting)
pub trait EmuContext {
fn speed(&self) -> EmulatorSpeed;
Expand Down Expand Up @@ -276,6 +315,7 @@ impl Emulator {
None,
None,
false,
false,
None,
)
}
Expand All @@ -290,6 +330,7 @@ impl Emulator {
ram_size: Option<usize>,
override_fdd_type: Option<DriveType>,
pmmu_enabled: bool,
slim_adapter: bool,
shared_dir: Option<PathBuf>,
) -> Result<(Self, Arc<Mutex<Option<DisplayBuffer>>>)> {
// Set up channels
Expand Down Expand Up @@ -331,6 +372,11 @@ impl Emulator {
}
MacModel::Portable | MacModel::Portable15MB => {
assert!(!pmmu_enabled, "PMMU not available on compact models");
assert!(
!slim_adapter
|| ram_size.unwrap_or_else(|| model.ram_size_default()) <= 5 * 1024 * 1024,
"RAM size cannot be greater than 5MB when SLIM adapter is enabled!"
);

// Find extension ROM if present
let extension_rom = extra_roms.iter().find_map(|p| match p {
Expand All @@ -339,8 +385,15 @@ impl Emulator {
});

// Initialize bus and CPU
let bus =
MacPortableBus::new(model, rom, extension_rom, renderer, mouse_mode, ram_size);
let bus = MacPortableBus::new(
model,
rom,
extension_rom,
renderer,
mouse_mode,
ram_size,
slim_adapter,
);
let cpu = Box::new(CpuM68000::new(bus));
assert_eq!(cpu.get_type(), model.cpu_type());

Expand Down Expand Up @@ -641,6 +694,8 @@ impl Emulator {
}),
model: self.model,
has_pmmu: self.config.cpu_has_pmmu(),
has_slim: self.config.has_slim(),
slim: self.config.slim_status(),
scsi: core::array::from_fn(|i| {
self.config
.scsi()
Expand Down Expand Up @@ -1037,6 +1092,27 @@ impl Tickable for Emulator {
}
self.status_update()?;
}
EmulatorCommand::SlimInsert(slot, filename, write_protect) => {
match self.config.slim_insert(slot, &filename, write_protect) {
Ok(()) => {
info!(
"SLIM slot {}: card inserted, image '{}' loaded",
slot + 1,
filename.display()
);
}
Err(e) => {
self.user_error(&format!("SLIM slot {}: {:#}", slot + 1, e));
}
}
self.status_update()?;
}
EmulatorCommand::SlimEject(slot) => {
if let Err(e) = self.config.slim_eject(slot) {
self.user_error(&format!("SLIM slot {}: {:#}", slot + 1, e));
}
self.status_update()?;
}
EmulatorCommand::ScsiAttachHdd(id, filename) => {
match self.load_hdd_image(&filename, id) {
Ok(_) => {
Expand Down
4 changes: 4 additions & 0 deletions core/src/mac/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ impl MacModel {
}
}

pub const fn has_slim(self) -> bool {
matches!(self, Self::Portable)
}

/// Default RAM size
pub const fn ram_size_default(self) -> usize {
match self {
Expand Down
57 changes: 52 additions & 5 deletions core/src/mac/portable/bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use super::via::Via;
use super::video::Video;
use crate::bus::{Address, Bus, BusMember, BusResult, InspectableBus, IrqSource};
use crate::debuggable::Debuggable;
use crate::emulator::comm::EmulatorSpeed;
use crate::emulator::comm::{EmulatorSpeed, SlimSlotStatus};
use crate::emulator::{EmuContext, MouseMode};
use crate::keymap::KeyEvent;
use crate::mac::MacModel;
Expand All @@ -17,6 +17,7 @@ use crate::mac::macii::bus::DEFAULT_BUS_SPEED;
use crate::mac::rtc::Rtc;
use crate::mac::scc::Scc;
use crate::mac::scsi::controller::ScsiController;
use crate::mac::scsi::disk_image::DiskImage;
use crate::mac::swim::Swim;
use crate::renderer::{
AUDIO_BUFFER_SAMPLES, AUDIO_CHANNELS, AudioProvider, Renderer, null_audio_sink,
Expand Down Expand Up @@ -108,6 +109,7 @@ where
renderer: TRenderer,
mouse_mode: MouseMode,
ram_size: Option<usize>,
slim_adapter: bool,
) -> Self {
let ram_size = ram_size.unwrap_or_else(|| model.ram_size_default());

Expand Down Expand Up @@ -161,7 +163,7 @@ where
progkey_pressed: LatchingEvent::default(),
mouse_mode,
pmgr: Pmgr::new(),
normandy: Normandy::new(),
normandy: Normandy::new(slim_adapter),
};

// Disable memory test
Expand All @@ -177,8 +179,10 @@ where
}

/// Reinstalls things that can't be serialized and does some updates upon deserialization
pub fn after_deserialize(&mut self, _renderer: TRenderer) {
pub fn after_deserialize(&mut self, renderer: TRenderer) {
self.video.after_deserialize(renderer).unwrap();
self.asc.after_deserialize();
self.normandy.after_deserialize();

// Mark all RAM pages as dirty after deserialization to update memory display
self.ram_dirty
Expand All @@ -189,6 +193,31 @@ where
self.model
}

/// Returns true if the SLIM card adapter is installed
pub fn slim_installed(&self) -> bool {
self.normandy.slim_installed()
}

/// Returns the status of the SLIM card slots
pub fn slim_status(&self) -> [Option<SlimSlotStatus>; 2] {
self.normandy.slim_status()
}

/// Inserts a SLIM card image into a slot
pub fn slim_insert(
&mut self,
slot: usize,
image: Box<dyn DiskImage>,
write_protect: bool,
) -> Result<()> {
self.normandy.slim_insert(slot, image, write_protect)
}

/// Ejects the SLIM card from a slot
pub fn slim_eject(&mut self, slot: usize) -> Result<()> {
self.normandy.slim_eject(slot)
}

pub fn get_effective_speed(&self) -> f64 {
self.pmgr.rtc.effective_speed()
}
Expand Down Expand Up @@ -238,7 +267,15 @@ where
fn write_normal(&mut self, addr: Address, val: Byte) -> Option<()> {
match addr {
// RAM
0x0000_0000..=0x008F_FFFF => self.normal_ram_write(addr, val),
0x0000_0000..=0x004F_FFFF => self.normal_ram_write(addr, val),
// SLIM cards, or RAM
0x0050_0000..=0x008F_FFFF => {
if self.normandy.slim_installed() {
self.normandy.write(addr, val)
} else {
self.normal_ram_write(addr, val)
}
}
// ROM, or Remapped RAM for 15MB RAM Mod
0x0090_0000..=0x009F_FFFF => {
if self.model == MacModel::Portable15MB {
Expand Down Expand Up @@ -311,7 +348,16 @@ where

fn read_normal(&mut self, addr: Address) -> Option<Byte> {
match addr {
0x0000_0000..=0x008F_FFFF => self.normal_ram_read(addr),
// RAM
0x0000_0000..=0x004F_FFFF => self.normal_ram_read(addr),
// SLIM cards, or RAM
0x0050_0000..=0x008F_FFFF => {
if self.normandy.slim_installed() {
self.normandy.read(addr).or(Some(Self::OPENBUS))
} else {
self.normal_ram_read(addr)
}
}
// ROM, or Remapped RAM for 15MB RAM Mod
0x0090_0000..=0x009F_FFFF => {
if self.model == MacModel::Portable15MB {
Expand Down Expand Up @@ -589,6 +635,7 @@ where
self.via.b_in.set_pmack(self.pmgr.pmack);
self.via.a_in.0 = self.pmgr.a_in;
self.via.ifr.set_pmgr(self.pmgr.interrupt);
self.normandy.tick(ticks, ())?;

Ok(())
}
Expand Down
Loading
Loading