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; };