1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00

Adds putative support for PlusToo-style BIN files.

Albeit a bit of a guess, since it's not intended to be an emulator file format.
This commit is contained in:
Thomas Harte 2019-06-04 21:41:09 -04:00
parent 058fe3e986
commit b8a1553368
7 changed files with 150 additions and 31 deletions

View File

@ -290,6 +290,7 @@ Analyser::Static::TargetList Analyser::Static::MSX::GetTargets(const Media &medi
target->region = target->media.tapes.empty() ? Target::Region::USA : Target::Region::Europe;
// Blindly accept disks for now.
// TODO: how to spot an MSX disk?
target->media.disks = media.disks;
target->has_disk_drive = !media.disks.empty();

View File

@ -43,6 +43,7 @@
#include "../../Storage/Disk/DiskImage/Formats/MSXDSK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/NIB.hpp"
#include "../../Storage/Disk/DiskImage/Formats/OricMFMDSK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/PlusTooBIN.hpp"
#include "../../Storage/Disk/DiskImage/Formats/SSD.hpp"
#include "../../Storage/Disk/DiskImage/Formats/WOZ.hpp"
@ -91,7 +92,8 @@ static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform::
Format("81", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // 81
Format("a26", result.cartridges, Cartridge::BinaryDump, TargetPlatform::Atari2600) // A26
Format("adf", result.disks, Disk::DiskImageHolder<Storage::Disk::AcornADF>, TargetPlatform::Acorn) // ADF
Format("bin", result.cartridges, Cartridge::BinaryDump, TargetPlatform::AllCartridge) // BIN
Format("bin", result.cartridges, Cartridge::BinaryDump, TargetPlatform::AllCartridge) // BIN (cartridge dump)
Format("bin", result.disks, Disk::DiskImageHolder<Storage::Disk::PlusTooBIN>, TargetPlatform::Macintosh) // BIN (PlusToo disk image)
Format("cas", result.tapes, Tape::CAS, TargetPlatform::MSX) // CAS
Format("cdt", result.tapes, Tape::TZX, TargetPlatform::AmstradCPC) // CDT
Format("col", result.cartridges, Cartridge::BinaryDump, TargetPlatform::ColecoVision) // COL

View File

@ -25,11 +25,7 @@ namespace {
}
IWM::IWM(int clock_rate) :
clock_rate_(clock_rate),
drives_{
{static_cast<unsigned int>(clock_rate), 300, 2},
{static_cast<unsigned int>(clock_rate), 300, 2}
} {}
clock_rate_(clock_rate) {}
// MARK: - Bus accessors
@ -64,7 +60,7 @@ uint8_t IWM::read(int address) {
case ENABLE: /* Read data register. */
printf("Reading data register\n");
return 0xff;
return 0x00;
case Q6: case Q6|ENABLE: {
/*
@ -93,7 +89,7 @@ uint8_t IWM::read(int address) {
case SEL: // Disk in place.
printf("disk in place)\n");
sense = drives_[active_drive_].has_disk() ? 0x00 : 0x80;
sense = drives_[active_drive_] && drives_[active_drive_]->has_disk() ? 0x00 : 0x80;
break;
case CA0: // Disk head stepping.
@ -106,12 +102,12 @@ uint8_t IWM::read(int address) {
case CA1: // Disk motor running.
printf("disk motor running)\n");
sense = drives_[active_drive_].get_motor_on() ? 0x00 : 0x80;
sense = drives_[active_drive_] && drives_[active_drive_]->get_motor_on() ? 0x00 : 0x80;
break;
case CA1|SEL: // Head at track 0.
printf("head at track 0)\n");
sense = drives_[active_drive_].get_is_track_zero() ? 0x00 : 0x80;
sense = drives_[active_drive_] && drives_[active_drive_]->get_is_track_zero() ? 0x00 : 0x80;
break;
case CA1|CA0|SEL: // Tachometer (?)
@ -132,12 +128,13 @@ uint8_t IWM::read(int address) {
case CA2|CA1|CA0|SEL: // Drive installed.
printf("drive installed)\n");
sense = drives_[active_drive_] ? 0x00 : 0x80;
break;
}
return
(mode_&0x1f) |
(drives_[active_drive_].get_motor_on() ? 0x20 : 0x00) |
(drive_motor_on_ ? 0x20 : 0x00) |
sense;
} break;
@ -214,13 +211,15 @@ void IWM::access(int address) {
case 4:
if(address & 1) {
drives_[active_drive_].set_motor_on(true);
drive_motor_on_ = true;
if(drives_[active_drive_]) drives_[active_drive_]->set_motor_on(true);
} else {
// If the 1-second delay is enabled, set up a timer for that.
if(!(mode_ & 4)) {
cycles_until_motor_off_ = Cycles(clock_rate_);
} else {
drives_[active_drive_].set_motor_on(false);
drive_motor_on_ = false;
if(drives_[active_drive_]) drives_[active_drive_]->set_motor_on(false);
}
}
break;
@ -228,9 +227,9 @@ void IWM::access(int address) {
case 5: {
const int new_drive = address & 1;
if(new_drive != active_drive_) {
drives_[new_drive].set_motor_on(drives_[active_drive_].get_motor_on());
drives_[active_drive_].set_motor_on(false);
if(drives_[active_drive_]) drives_[active_drive_]->set_motor_on(false);
active_drive_ = new_drive;
if(drives_[active_drive_]) drives_[active_drive_]->set_motor_on(drive_motor_on_);
}
} break;
}
@ -247,10 +246,22 @@ void IWM::set_select(bool enabled) {
// MARK: - Active logic
void IWM::run_for(const Cycles cycles) {
// Check for a timeout of the motor-off timer.
if(cycles_until_motor_off_ > Cycles(0)) {
cycles_until_motor_off_ -= cycles;
if(cycles_until_motor_off_ <= Cycles(0)) {
drives_[active_drive_].set_motor_on(false);
drive_motor_on_ = false;
if(drives_[active_drive_])
drives_[active_drive_]->set_motor_on(false);
}
}
// Activity otherwise depends on mode and motor state.
switch(state_ & (Q6 | Q7 | ENABLE)) {
}
}
void IWM::set_drive(int slot, Storage::Disk::Drive *drive) {
drives_[slot] = drive;
}

View File

@ -38,6 +38,9 @@ class IWM {
/// Advances the controller by @c cycles.
void run_for(const Cycles cycles);
/// Connects a drive to the IWM.
void set_drive(int slot, Storage::Disk::Drive *drive);
private:
const int clock_rate_;
@ -48,7 +51,8 @@ class IWM {
int state_ = 0;
int active_drive_ = 0;
Storage::Disk::Drive drives_[2];
Storage::Disk::Drive *drives_[2] = {nullptr, nullptr};
bool drive_motor_on_ = false;
Cycles cycles_until_motor_off_;

View File

@ -110,6 +110,8 @@
4B08A2751EE35D56008B7065 /* Z80InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */; };
4B08A2781EE39306008B7065 /* TestMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B08A2771EE39306008B7065 /* TestMachine.mm */; };
4B08A56920D72BEF0016CE5A /* Activity.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B08A56720D72BEF0016CE5A /* Activity.xib */; };
4B0C956E22A7109A0015A8F6 /* PlusTooBIN.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0C956C22A7109A0015A8F6 /* PlusTooBIN.cpp */; };
4B0C957122A74E880015A8F6 /* SonyDrive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0C956F22A74E880015A8F6 /* SonyDrive.cpp */; };
4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0CCC421C62D0B3001CAC5F /* CRT.cpp */; };
4B0E04EA1FC9E5DA00F43484 /* CAS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0E04E81FC9E5DA00F43484 /* CAS.cpp */; };
4B0E04EB1FC9E78800F43484 /* CAS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0E04E81FC9E5DA00F43484 /* CAS.cpp */; };
@ -726,6 +728,10 @@
4B08A2771EE39306008B7065 /* TestMachine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestMachine.mm; sourceTree = "<group>"; };
4B08A2791EE3957B008B7065 /* TestMachine+ForSubclassEyesOnly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TestMachine+ForSubclassEyesOnly.h"; sourceTree = "<group>"; };
4B08A56820D72BEF0016CE5A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/Activity.xib"; sourceTree = SOURCE_ROOT; };
4B0C956C22A7109A0015A8F6 /* PlusTooBIN.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PlusTooBIN.cpp; sourceTree = "<group>"; };
4B0C956D22A7109A0015A8F6 /* PlusTooBIN.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PlusTooBIN.hpp; sourceTree = "<group>"; };
4B0C956F22A74E880015A8F6 /* SonyDrive.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SonyDrive.cpp; sourceTree = "<group>"; };
4B0C957022A74E880015A8F6 /* SonyDrive.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SonyDrive.hpp; sourceTree = "<group>"; };
4B0CCC421C62D0B3001CAC5F /* CRT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CRT.cpp; sourceTree = "<group>"; };
4B0CCC431C62D0B3001CAC5F /* CRT.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRT.hpp; sourceTree = "<group>"; };
4B0E04E81FC9E5DA00F43484 /* CAS.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CAS.cpp; sourceTree = "<group>"; };
@ -1945,34 +1951,36 @@
isa = PBXGroup;
children = (
4B45188D1F75FD1B00926311 /* AcornADF.cpp */,
4B45188E1F75FD1B00926311 /* AcornADF.hpp */,
4B0333AD2094081A0050B93D /* AppleDSK.cpp */,
4B0333AE2094081A0050B93D /* AppleDSK.hpp */,
4B45188F1F75FD1B00926311 /* CPCDSK.cpp */,
4B4518901F75FD1B00926311 /* CPCDSK.hpp */,
4B4518911F75FD1B00926311 /* D64.cpp */,
4B4518921F75FD1B00926311 /* D64.hpp */,
4BB4BFAE22A42F290069048D /* DiskCopy42.cpp */,
4BB4BFAF22A42F290069048D /* DiskCopy42.hpp */,
4BAF2B4C2004580C00480230 /* DMK.cpp */,
4BAF2B4D2004580C00480230 /* DMK.hpp */,
4B4518931F75FD1B00926311 /* G64.cpp */,
4B4518941F75FD1B00926311 /* G64.hpp */,
4B4518951F75FD1B00926311 /* HFE.cpp */,
4B4518961F75FD1B00926311 /* HFE.hpp */,
4B58601C1F806AB200AEE2E3 /* MFMSectorDump.cpp */,
4B58601D1F806AB200AEE2E3 /* MFMSectorDump.hpp */,
4BEBFB4B2002C4BF000708CC /* MSXDSK.cpp */,
4BEBFB4C2002C4BF000708CC /* MSXDSK.hpp */,
4B0F94FC208C1A1600FE41D9 /* NIB.cpp */,
4B0F94FD208C1A1600FE41D9 /* NIB.hpp */,
4B4518971F75FD1B00926311 /* OricMFMDSK.cpp */,
4B4518981F75FD1B00926311 /* OricMFMDSK.hpp */,
4B0C956C22A7109A0015A8F6 /* PlusTooBIN.cpp */,
4B4518991F75FD1B00926311 /* SSD.cpp */,
4B45189A1F75FD1B00926311 /* SSD.hpp */,
4BFDD7891F7F2DB4008579B9 /* Utility */,
4B6ED2EE208E2F8A0047B343 /* WOZ.cpp */,
4B45188E1F75FD1B00926311 /* AcornADF.hpp */,
4B0333AE2094081A0050B93D /* AppleDSK.hpp */,
4B4518901F75FD1B00926311 /* CPCDSK.hpp */,
4B4518921F75FD1B00926311 /* D64.hpp */,
4BB4BFAF22A42F290069048D /* DiskCopy42.hpp */,
4BAF2B4D2004580C00480230 /* DMK.hpp */,
4B4518941F75FD1B00926311 /* G64.hpp */,
4B4518961F75FD1B00926311 /* HFE.hpp */,
4B58601D1F806AB200AEE2E3 /* MFMSectorDump.hpp */,
4BEBFB4C2002C4BF000708CC /* MSXDSK.hpp */,
4B0F94FD208C1A1600FE41D9 /* NIB.hpp */,
4B4518981F75FD1B00926311 /* OricMFMDSK.hpp */,
4B0C956D22A7109A0015A8F6 /* PlusTooBIN.hpp */,
4B45189A1F75FD1B00926311 /* SSD.hpp */,
4B6ED2EF208E2F8A0047B343 /* WOZ.hpp */,
4BFDD7891F7F2DB4008579B9 /* Utility */,
);
path = Formats;
sourceTree = "<group>";
@ -3104,6 +3112,8 @@
4BCE0059227CFFCA000CA200 /* Macintosh.hpp */,
4BD0692B22828A2D00D2A54F /* RealTimeClock.hpp */,
4BCE005F227D39AB000CA200 /* Video.hpp */,
4B0C956F22A74E880015A8F6 /* SonyDrive.cpp */,
4B0C957022A74E880015A8F6 /* SonyDrive.hpp */,
);
path = Macintosh;
sourceTree = "<group>";
@ -4073,6 +4083,7 @@
4B30512D1D989E2200B4FED8 /* Drive.cpp in Sources */,
4BCE005D227D30CC000CA200 /* MemoryPacker.cpp in Sources */,
4BCE0051227CE8CA000CA200 /* Video.cpp in Sources */,
4B0C956E22A7109A0015A8F6 /* PlusTooBIN.cpp in Sources */,
4B894536201967B4007DE474 /* Z80.cpp in Sources */,
4BCA6CC81D9DD9F000C2D7B2 /* CommodoreROM.cpp in Sources */,
4BEA52661DF3472B007E74F2 /* TIASound.cpp in Sources */,
@ -4097,6 +4108,7 @@
4B8334861F5DA3780097E338 /* 6502Storage.cpp in Sources */,
4B8FE2271DA1DE2D0090D3CE /* NSBundle+DataResource.m in Sources */,
4B2A53A01D117D36003C6002 /* CSMachine.mm in Sources */,
4B0C957122A74E880015A8F6 /* SonyDrive.cpp in Sources */,
4BC91B831D1F160E00884B76 /* CommodoreTAP.cpp in Sources */,
4B55DD8320DF06680043F2E5 /* MachinePicker.swift in Sources */,
4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */,

View File

@ -0,0 +1,49 @@
//
// PlusTooBIN.cpp
// Clock Signal
//
// Created by Thomas Harte on 04/06/2019.
// Copyright © 2019 Thomas Harte. All rights reserved.
//
#include "PlusTooBIN.hpp"
#include "../../Track/PCMTrack.hpp"
#include "../../Encodings/AppleGCR/Encoder.hpp"
using namespace Storage::Disk;
namespace {
const long sector_size = 1024;
}
PlusTooBIN::PlusTooBIN(const std::string &file_name) :
file_(file_name) {
// BIN isn't really meant to be an emulator file format, it's primarily
// a convenience for the PlusToo Macintosh clone. So validation is
// fairly light.
if(file_.stats().st_size != 1638400)
throw Error::InvalidFormat;
}
HeadPosition PlusTooBIN::get_maximum_head_position() {
return HeadPosition(80);
}
int PlusTooBIN::get_head_count() {
return 2;
}
std::shared_ptr<Track> PlusTooBIN::get_track_at_position(Track::Address address) {
if(address.position >= get_maximum_head_position()) return nullptr;
if(address.head >= get_head_count()) return nullptr;
const auto start_position = Encodings::AppleGCR::Macintosh::sectors_in_track(address.position.as_int());
const long file_offset = long(start_position.start * 2 + address.head * start_position.start) * sector_size;
file_.seek(file_offset, SEEK_SET);
const auto track_contents = file_.read(std::size_t(sector_size * start_position.length));
const std::size_t number_of_bits = std::size_t(sector_size * start_position.length * 8);
return std::shared_ptr<PCMTrack>(new PCMTrack(PCMSegment(number_of_bits, track_contents)));
}

View File

@ -0,0 +1,40 @@
//
// PlusTooBIN.hpp
// Clock Signal
//
// Created by Thomas Harte on 04/06/2019.
// Copyright © 2019 Thomas Harte. All rights reserved.
//
#ifndef PlusTooBIN_hpp
#define PlusTooBIN_hpp
#include "../DiskImage.hpp"
#include "../../../FileHolder.hpp"
#include <string>
namespace Storage {
namespace Disk {
/*!
Provides a @c DiskImage capturing the raw bitstream contained in a PlusToo-style BIN file.
*/
class PlusTooBIN: public DiskImage {
public:
PlusTooBIN(const std::string &file_name);
// Implemented to satisfy @c DiskImage.
HeadPosition get_maximum_head_position() override;
int get_head_count() override;
std::shared_ptr<Track> get_track_at_position(Track::Address address) override;
private:
Storage::FileHolder file_;
};
}
}
#endif /* PlusTooBIN_hpp */