diff --git a/devices/floppy/superdrive.cpp b/devices/floppy/superdrive.cpp
new file mode 100644
index 0000000..a5e6108
--- /dev/null
+++ b/devices/floppy/superdrive.cpp
@@ -0,0 +1,70 @@
+/*
+DingusPPC - The Experimental PowerPC Macintosh emulator
+Copyright (C) 2018-21 divingkatae and maximum
+ (theweirdo) spatium
+
+(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+/** @file Macintosh Superdrive emulation. */
+
+#include "superdrive.h"
+#include
+
+#include
+
+using namespace MacSuperdrive;
+
+MacSuperDrive::MacSuperDrive()
+{
+ this->media_kind = MediaKind::high_density;
+}
+
+void MacSuperDrive::command(uint8_t addr, uint8_t value)
+{
+ LOG_F(9, "Superdrive: command addr=0x%X, value=%d", addr, value);
+
+ switch(addr) {
+ case CommandAddr::Motor_On_Off:
+ if (value) {
+ LOG_F(INFO, "Superdrive: turn spindle motor off");
+ } else {
+ LOG_F(INFO, "Superdrive: turn spindle motor on");
+ }
+ break;
+ default:
+ LOG_F(WARNING, "Superdrive: unimplemented command, addr=0x%X", addr);
+ }
+}
+
+uint8_t MacSuperDrive::status(uint8_t addr)
+{
+ LOG_F(9, "Superdrive: status request, addr = 0x%X", addr);
+
+ switch(addr) {
+ case StatusAddr::MFM_Support:
+ return 1; // Superdrive does support MFM encoding scheme
+ case StatusAddr::Double_Sided:
+ return 1; // yes, Superdrive is double sided
+ case StatusAddr::Drive_Exists:
+ return 0; // tell the world I'm here
+ case StatusAddr::Media_Kind:
+ return this->media_kind;
+ default:
+ LOG_F(WARNING, "Superdrive: unimplemented status request, addr=0x%X", addr);
+ return 0;
+ }
+}
diff --git a/devices/floppy/superdrive.h b/devices/floppy/superdrive.h
new file mode 100644
index 0000000..a30cf7b
--- /dev/null
+++ b/devices/floppy/superdrive.h
@@ -0,0 +1,64 @@
+/*
+DingusPPC - The Experimental PowerPC Macintosh emulator
+Copyright (C) 2018-21 divingkatae and maximum
+ (theweirdo) spatium
+
+(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+/** @file Macintosh Superdrive definitions. */
+
+#ifndef MAC_SUPERDRIVE_H
+#define MAC_SUPERDRIVE_H
+
+#include
+
+namespace MacSuperdrive {
+
+/** Apple Drive status request addresses. */
+enum StatusAddr : uint8_t {
+ MFM_Support = 5,
+ Double_Sided = 6,
+ Drive_Exists = 7,
+ Media_Kind = 0xF
+};
+
+/** Apple Drive command addresses. */
+enum CommandAddr : uint8_t {
+ Motor_On_Off = 2,
+};
+
+/** Type of media currently in the drive. */
+enum MediaKind : uint8_t {
+ high_density = 0, // 1 or 2 MB disk
+ low_density = 1
+};
+
+class MacSuperDrive {
+public:
+ MacSuperDrive();
+ ~MacSuperDrive() = default;
+
+ void command(uint8_t addr, uint8_t value);
+ uint8_t status(uint8_t addr);
+
+private:
+ uint8_t media_kind;
+};
+
+}; // namespace MacSuperdrive
+
+#endif // MAC_SUPERDRIVE_H
diff --git a/devices/floppy/swim3.cpp b/devices/floppy/swim3.cpp
new file mode 100644
index 0000000..b4b9cec
--- /dev/null
+++ b/devices/floppy/swim3.cpp
@@ -0,0 +1,104 @@
+/*
+DingusPPC - The Experimental PowerPC Macintosh emulator
+Copyright (C) 2018-21 divingkatae and maximum
+ (theweirdo) spatium
+
+(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+/** @file Sander-Wozniak Machine 3 (SWIM3) emulation. */
+
+#include "superdrive.h"
+#include "swim3.h"
+#include
+
+#include
+#include
+
+using namespace Swim3;
+
+Swim3Ctrl::Swim3Ctrl()
+{
+ this->setup_reg = 0;
+ this->mode_reg = 0;
+ this->int_reg = 0;
+ this->int_mask = 0;
+ this->xfer_cnt = 0;
+ this->first_sec = 0xFF;
+
+ // Attach virtual Superdrive to the internal drive connector
+ // TODO: make SWIM3/drive wiring user selectable
+ this->int_drive = std::unique_ptr
+ (new MacSuperdrive::MacSuperDrive());
+}
+
+uint8_t Swim3Ctrl::read(uint8_t reg_offset)
+{
+ uint8_t status_addr;
+
+ switch(reg_offset) {
+ case Swim3Reg::Phase:
+ return this->phase_lines;
+ case Swim3Reg::Setup:
+ return this->setup_reg;
+ case Swim3Reg::Handshake_Mode1:
+ if (this->mode_reg & 2) { // internal drive?
+ status_addr = ((this->mode_reg & 0x20) >> 2) | (this->phase_lines & 7);
+ return ((this->int_drive->status(status_addr) & 1) << 2);
+ } else {
+ return 4;
+ }
+ default:
+ LOG_F(INFO, "SWIM3: reading from 0x%X register", reg_offset);
+ }
+ return 0;
+}
+
+void Swim3Ctrl::write(uint8_t reg_offset, uint8_t value)
+{
+ switch(reg_offset) {
+ case Swim3Reg::Param_Data:
+ this->pram = value;
+ break;
+ case Swim3Reg::Phase:
+ this->phase_lines = value & 0xF;
+ if (value & 8) {
+ if (this->mode_reg & 2) { // internal drive?
+ this->int_drive->command(
+ ((this->mode_reg & 0x20) >> 3) | (this->phase_lines & 3),
+ (value >> 2) & 1
+ );
+ }
+ }
+ break;
+ case Swim3Reg::Setup:
+ this->setup_reg = value;
+ break;
+ case Swim3Reg::Status_Mode0:
+ // ones in value clear the corresponding bits in the mode register
+ this->mode_reg &= ~value;
+ break;
+ case Swim3Reg::Handshake_Mode1:
+ // ones in value set the corresponding bits in the mode register
+ this->mode_reg |= value;
+ break;
+ case Swim3Reg::Interrupt_Mask:
+ this->int_mask = value;
+ break;
+ default:
+ LOG_F(INFO, "SWIM3: writing 0x%X to register 0x%X", value, reg_offset);
+ }
+}
diff --git a/devices/floppy/swim3.h b/devices/floppy/swim3.h
new file mode 100644
index 0000000..1a4d54c
--- /dev/null
+++ b/devices/floppy/swim3.h
@@ -0,0 +1,78 @@
+/*
+DingusPPC - The Experimental PowerPC Macintosh emulator
+Copyright (C) 2018-21 divingkatae and maximum
+ (theweirdo) spatium
+
+(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+/** @file Sander-Wozniak Machine 3 (SWIM3) definitions. */
+
+#ifndef SWIM3_H
+#define SWIM3_H
+
+#include "superdrive.h"
+
+#include
+#include
+
+/** SWIM3 registers offsets. */
+namespace Swim3 {
+
+enum Swim3Reg : uint8_t {
+ Data = 0,
+ Timer = 1,
+ Error = 2,
+ Param_Data = 3,
+ Phase = 4,
+ Setup = 5,
+ Status_Mode0 = 6, // read: Status, write: zeroes to the mode register
+ Handshake_Mode1 = 7, // read: Handshake, write: ones to the mode register
+ Interrupt = 8,
+ Step = 9,
+ Current_Track = 10,
+ Current_Sector = 11,
+ Gap_Format = 12,
+ First_Sector = 13,
+ Sectors_To_Xfer = 14,
+ Interrupt_Mask = 15
+};
+
+class Swim3Ctrl {
+public:
+ Swim3Ctrl();
+ ~Swim3Ctrl() = default;
+
+ // SWIM3 registers access
+ uint8_t read(uint8_t reg_offset);
+ void write(uint8_t reg_offset, uint8_t value);
+
+private:
+ std::unique_ptr int_drive;
+
+ uint8_t setup_reg;
+ uint8_t mode_reg;
+ uint8_t phase_lines;
+ uint8_t int_reg;
+ uint8_t int_mask;
+ uint8_t pram; // parameter RAM: two nibbles = {late_time, early_time}
+ uint8_t first_sec;
+ uint8_t xfer_cnt;
+};
+
+}; // namespace Swim3
+
+#endif // SWIM3_H
diff --git a/devices/ioctrl/amic.cpp b/devices/ioctrl/amic.cpp
index 8ee25a7..158a7c3 100644
--- a/devices/ioctrl/amic.cpp
+++ b/devices/ioctrl/amic.cpp
@@ -28,6 +28,7 @@ along with this program. If not, see .
#include
#include
#include
+#include
#include
#include
#include
@@ -66,6 +67,9 @@ AMIC::AMIC()
// initialize on-board video
this->disp_id = std::unique_ptr (new DisplayID());
this->def_vid = std::unique_ptr (new PdmOnboardVideo());
+
+ // intialize floppy disk HW
+ this->swim3 = std::unique_ptr (new Swim3::Swim3Ctrl());
}
bool AMIC::supports_type(HWCompType type) {
@@ -113,6 +117,9 @@ uint32_t AMIC::read(uint32_t reg_start, uint32_t offset, int size)
case AMICReg::Snd_Out_DMA:
return this->snd_out_dma->read_stat();
}
+ case 0x16: // SWIM3 registers
+ case 0x17:
+ return this->swim3->read((offset >> 9) & 0xF);
}
switch(offset) {
@@ -196,6 +203,10 @@ void AMIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size)
this->snd_out_dma->write_dma_out_ctrl(value);
return;
}
+ case 0x16: // SWIM3 registers
+ case 0x17:
+ this->swim3->write((offset >> 9) & 0xF, value);
+ return;
}
switch(offset) {
diff --git a/devices/ioctrl/amic.h b/devices/ioctrl/amic.h
index b4cf1d2..c8bd2f7 100644
--- a/devices/ioctrl/amic.h
+++ b/devices/ioctrl/amic.h
@@ -28,6 +28,7 @@ along with this program. If not, see .
#include
#include
#include
+#include
#include
#include
#include
@@ -166,6 +167,8 @@ private:
std::unique_ptr disp_id;
std::unique_ptr def_vid;
uint8_t mon_id;
+
+ std::unique_ptr swim3;
};
#endif // AMIC_H
diff --git a/devices/ioctrl/heathrow.cpp b/devices/ioctrl/heathrow.cpp
index 5d17ae4..0234c8c 100644
--- a/devices/ioctrl/heathrow.cpp
+++ b/devices/ioctrl/heathrow.cpp
@@ -22,6 +22,7 @@ along with this program. If not, see .
#include
#include
#include
+#include
#include
#include
#include
@@ -56,8 +57,9 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow") {
std::bind(&AwacsScreamer::dma_end, this->screamer.get())
);
- this->mesh = std::unique_ptr (new MESHController(HeathrowMESHID));
- this->escc = std::unique_ptr (new EsccController());
+ this->mesh = std::unique_ptr (new MESHController(HeathrowMESHID));
+ this->escc = std::unique_ptr (new EsccController());
+ this->swim3 = std::unique_ptr (new Swim3::Swim3Ctrl());
}
uint32_t HeathrowIC::pci_cfg_read(uint32_t reg_offs, uint32_t size) {
@@ -136,6 +138,8 @@ uint32_t HeathrowIC::read(uint32_t reg_start, uint32_t offset, int size) {
case 0x14:
res = this->screamer->snd_ctrl_read(offset - 0x14000, size);
break;
+ case 0x15: // SWIM3
+ return this->swim3->read(offset & 0xF);
case 0x16:
case 0x17:
res = this->viacuda->read((offset - 0x16000) >> 9);
@@ -175,6 +179,9 @@ void HeathrowIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int
case 0x14:
this->screamer->snd_ctrl_write(offset - 0x14000, value, size);
break;
+ case 0x15:
+ this->swim3->write(offset & 0xF, value);
+ break;
case 0x16:
case 0x17:
this->viacuda->write((offset - 0x16000) >> 9, value);
diff --git a/devices/ioctrl/macio.h b/devices/ioctrl/macio.h
index 2777637..67385fb 100644
--- a/devices/ioctrl/macio.h
+++ b/devices/ioctrl/macio.h
@@ -59,6 +59,7 @@ along with this program. If not, see .
#include
#include
#include
+#include
#include
#include
#include
@@ -154,11 +155,12 @@ private:
uint32_t aux_ctrl = 0; // aux features control register
/* device cells */
- std::unique_ptr viacuda; // VIA cell with Cuda MCU attached to it
- std::unique_ptr nvram; // NVRAM cell
- std::unique_ptr screamer; // Screamer audio codec instance
- std::unique_ptr mesh; // MESH SCSI cell instance
- std::unique_ptr escc; // ESCC serial controller
+ std::unique_ptr viacuda; // VIA cell with Cuda MCU attached to it
+ std::unique_ptr nvram; // NVRAM cell
+ std::unique_ptr screamer; // Screamer audio codec instance
+ std::unique_ptr mesh; // MESH SCSI cell instance
+ std::unique_ptr escc; // ESCC serial controller
+ std::unique_ptr swim3; // floppy disk controller
std::unique_ptr snd_out_dma;
};