1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-23 03:32:32 +00:00

Merge pull request #1225 from TomHarte/PCDiskImages

Add enough for FAT12 IMA images to get to the PC.
This commit is contained in:
Thomas Harte 2023-11-29 16:11:33 -05:00 committed by GitHub
commit ec39c4a5f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 190 additions and 5 deletions

View File

@ -40,6 +40,8 @@ Analyser::Static::TargetList Analyser::Static::Enterprise::GetTargets(const Medi
target->basic_version = Target::BASICVersion::Any;
// Inspect any supplied disks.
//
// TODO: how best can these be discerned from MS-DOS and MSX disks?
if(!media.disks.empty()) {
// DOS will be needed.
target->dos = Target::DOS::EXDOS;

View File

@ -0,0 +1,25 @@
//
// StaticAnalyser.cpp
// Clock Signal
//
// Created by Thomas Harte on 03/10/2019.
// Copyright © 2019 Thomas Harte. All rights reserved.
//
#include "StaticAnalyser.hpp"
#include "Target.hpp"
Analyser::Static::TargetList Analyser::Static::PCCompatible::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
// This analyser can comprehend disks only.
if(media.disks.empty()) return {};
// No analysis is applied yet.
Analyser::Static::TargetList targets;
using Target = Analyser::Static::PCCompatible::Target;
auto *const target = new Target();
target->media = media;
targets.push_back(std::unique_ptr<Analyser::Static::Target>(target));
return targets;
}

View File

@ -0,0 +1,22 @@
//
// StaticAnalyser.hpp
// Clock Signal
//
// Created by Thomas Harte on 29/11/2019.
// Copyright © 2023 Thomas Harte. All rights reserved.
//
#ifndef Analyser_Static_PCCompatible_StaticAnalyser_hpp
#define Analyser_Static_PCCompatible_StaticAnalyser_hpp
#include "../StaticAnalyser.hpp"
#include "../../../Storage/TargetPlatforms.hpp"
#include <string>
namespace Analyser::Static::PCCompatible {
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
}
#endif /* Analyser_Static_PCCompatible_StaticAnalyser_hpp */

View File

@ -0,0 +1,33 @@
//
// Target.hpp
// Clock Signal
//
// Created by Thomas Harte on 29/11/2023.
// Copyright © 2023 Thomas Harte. All rights reserved.
//
#ifndef Analyser_Static_PCCompatible_Target_h
#define Analyser_Static_PCCompatible_Target_h
#include "../../../Reflection/Struct.hpp"
#include "../StaticAnalyser.hpp"
namespace Analyser::Static::PCCompatible {
struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Target> {
ReflectableEnum(VideoAdaptor,
MDA,
CGA);
VideoAdaptor adaptor = VideoAdaptor::MDA;
Target() : Analyser::Static::Target(Machine::PCCompatible) {
if(needs_declare()) {
DeclareField(adaptor);
AnnounceEnum(VideoAdaptor);
}
}
};
}
#endif /* Analyser_Static_PCCompatible_Target_h */

View File

@ -28,6 +28,7 @@
#include "Macintosh/StaticAnalyser.hpp"
#include "MSX/StaticAnalyser.hpp"
#include "Oric/StaticAnalyser.hpp"
#include "PCCompatible/StaticAnalyser.hpp"
#include "Sega/StaticAnalyser.hpp"
#include "ZX8081/StaticAnalyser.hpp"
#include "ZXSpectrum/StaticAnalyser.hpp"
@ -177,6 +178,7 @@ static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform::
Disk::DiskImageHolder<Storage::Disk::HFE>,
TargetPlatform::Acorn | TargetPlatform::AmstradCPC | TargetPlatform::Commodore | TargetPlatform::Oric | TargetPlatform::ZXSpectrum)
// HFE (TODO: switch to AllDisk once the MSX stops being so greedy)
Format("ima", result.disks, Disk::DiskImageHolder<Storage::Disk::FAT12>, TargetPlatform::PCCompatible) // IMG (Enterprise/MS-DOS style)
Format("img", result.disks, Disk::DiskImageHolder<Storage::Disk::MacintoshIMG>, TargetPlatform::Macintosh) // IMG (DiskCopy 4.2)
Format("image", result.disks, Disk::DiskImageHolder<Storage::Disk::MacintoshIMG>, TargetPlatform::Macintosh) // IMG (DiskCopy 4.2)
Format("img", result.disks, Disk::DiskImageHolder<Storage::Disk::FAT12>, TargetPlatform::Enterprise) // IMG (Enterprise/MS-DOS style)
@ -289,6 +291,7 @@ TargetList Analyser::Static::GetTargets(const std::string &file_name) {
Append(Macintosh);
Append(MSX);
Append(Oric);
Append(PCCompatible);
Append(Sega);
Append(ZX8081);
Append(ZXSpectrum);

View File

@ -30,8 +30,13 @@
#include "../../Outputs/CRT/CRT.hpp"
#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
#include "../../Storage/Disk/Track/TrackSerialiser.hpp"
#include "../../Storage/Disk/Encodings/MFM/Constants.hpp"
#include "../../Storage/Disk/Encodings/MFM/SegmentParser.hpp"
#include "../AudioProducer.hpp"
#include "../KeyboardMachine.hpp"
#include "../MediaTarget.hpp"
#include "../ScanProducer.hpp"
#include "../TimedMachine.hpp"
@ -101,10 +106,15 @@ class FloppyController {
printf("TODO: implement FDC command %d\n", uint8_t(decoder_.command()));
break;
case Command::ReadData:
printf("FDC: Read %d:%d at %d/%d\n", decoder_.target().drive, decoder_.target().head, decoder_.geometry().cylinder, decoder_.geometry().head);
break;
case Command::Seek:
printf("FDC: Seek %d:%d to %d\n", decoder_.target().drive, decoder_.target().head, decoder_.seek_target());
drives_[decoder_.target().drive].track = decoder_.seek_target();
drives_[decoder_.target().drive].side = decoder_.target().head;
drives_[decoder_.target().drive].cache_track();
drives_[decoder_.target().drive].raised_interrupt = true;
drives_[decoder_.target().drive].status = decoder_.drive_head() | uint8_t(Intel::i8272::Status0::SeekEnded);
@ -113,6 +123,8 @@ class FloppyController {
case Command::Recalibrate:
printf("FDC: Recalibrate\n");
drives_[decoder_.target().drive].track = 0;
drives_[decoder_.target().drive].cache_track();
drives_[decoder_.target().drive].raised_interrupt = true;
drives_[decoder_.target().drive].status = decoder_.target().drive | uint8_t(Intel::i8272::Status0::SeekEnded);
pic_.apply_edge<6>(true);
@ -192,6 +204,10 @@ class FloppyController {
}
}
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive) {
drives_[drive].disk = disk;
}
private:
void reset() {
printf("FDC reset\n");
@ -230,6 +246,32 @@ class FloppyController {
bool side = false;
bool motor = false;
bool exists = true;
std::shared_ptr<Storage::Disk::Disk> disk;
Storage::Encodings::MFM::SectorMap cached_track;
void cache_track() {
if(!disk) {
return;
}
cached_track.clear();
auto raw_track = disk->get_track_at_position(
Storage::Disk::Track::Address(
side,
Storage::Disk::HeadPosition(track)
)
);
if(!raw_track) {
return;
}
const bool is_double_density = true; // TODO: use MFM flag here.
auto serialisation = Storage::Disk::track_serialisation(
*raw_track,
is_double_density ? Storage::Encodings::MFM::MFMBitLength : Storage::Encodings::MFM::FMBitLength
);
cached_track = Storage::Encodings::MFM::sectors_from_segment(std::move(serialisation), is_double_density);
}
} drives_[4];
std::string drive_name(int c) const {
@ -1088,8 +1130,9 @@ class ConcreteMachine:
public Machine,
public MachineTypes::TimedMachine,
public MachineTypes::AudioProducer,
public MachineTypes::ScanProducer,
public MachineTypes::MappedKeyboardMachine,
public MachineTypes::MediaTarget,
public MachineTypes::ScanProducer,
public Activity::Source
{
public:
@ -1126,6 +1169,9 @@ class ConcreteMachine:
// Give the MDA something to read from.
const auto &font_contents = roms.find(font)->second;
mda_.set_source(context.memory.at(0xb'0000), font_contents);
// ... and insert media.
insert_media(target.media);
}
~ConcreteMachine() {
@ -1238,6 +1284,17 @@ class ConcreteMachine:
}
}
// MARK: - MediaTarget
bool insert_media(const Analyser::Static::Media &media) override {
int c = 0;
for(auto &disk : media.disks) {
fdc_.set_disk(disk, c);
c++;
if(c == 4) break;
}
return true;
}
// MARK: - MappedKeyboardMachine.
MappedKeyboardMachine::KeyboardMapper *get_keyboard_mapper() override {
return &keyboard_mapper_;

View File

@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
423820112B17CBC800964EFE /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 423820102B17CBC800964EFE /* StaticAnalyser.cpp */; };
423820122B17CBC800964EFE /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 423820102B17CBC800964EFE /* StaticAnalyser.cpp */; };
423BDC4A2AB24699008E37B6 /* 8088Tests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 423BDC492AB24699008E37B6 /* 8088Tests.mm */; };
42437B332AC70833006DFED1 /* HDV.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B6FD0342923061300EC4760 /* HDV.cpp */; };
425739382B051EA800B7D1E4 /* PCCompatible.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 425739372B051EA800B7D1E4 /* PCCompatible.cpp */; };
@ -1128,6 +1130,9 @@
/* Begin PBXFileReference section */
4238200B2B1295AD00964EFE /* Status.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Status.hpp; sourceTree = "<group>"; };
4238200C2B15998800964EFE /* Results.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Results.hpp; sourceTree = "<group>"; };
4238200E2B17CBC800964EFE /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaticAnalyser.hpp; sourceTree = "<group>"; };
4238200F2B17CBC800964EFE /* Target.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = "<group>"; };
423820102B17CBC800964EFE /* StaticAnalyser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaticAnalyser.cpp; sourceTree = "<group>"; };
423BDC492AB24699008E37B6 /* 8088Tests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = 8088Tests.mm; sourceTree = "<group>"; };
42437B342ACF02A9006DFED1 /* Flags.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Flags.hpp; sourceTree = "<group>"; };
42437B352ACF0AA2006DFED1 /* Perform.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Perform.hpp; sourceTree = "<group>"; };
@ -2346,6 +2351,16 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
4238200D2B17CBC800964EFE /* PCCompatible */ = {
isa = PBXGroup;
children = (
4238200E2B17CBC800964EFE /* StaticAnalyser.hpp */,
4238200F2B17CBC800964EFE /* Target.hpp */,
423820102B17CBC800964EFE /* StaticAnalyser.cpp */,
);
path = PCCompatible;
sourceTree = "<group>";
};
42437B372ACF2798006DFED1 /* Implementation */ = {
isa = PBXGroup;
children = (
@ -3581,6 +3596,7 @@
4BB4BFB622A4372E0069048D /* Macintosh */,
4B89450F201967B4007DE474 /* MSX */,
4B8944F6201967B4007DE474 /* Oric */,
4238200D2B17CBC800964EFE /* PCCompatible */,
4B7F1894215486A100388727 /* Sega */,
4B894504201967B4007DE474 /* ZX8081 */,
4B0F1BAF2602645900B85C66 /* ZXSpectrum */,
@ -5724,6 +5740,7 @@
4B0ACC2D23775819008902D0 /* IntelligentKeyboard.cpp in Sources */,
4B894539201967B4007DE474 /* Tape.cpp in Sources */,
4B92E26B234AE35100CD6D1B /* MFP68901.cpp in Sources */,
423820122B17CBC800964EFE /* StaticAnalyser.cpp in Sources */,
4B7F1898215486A200388727 /* StaticAnalyser.cpp in Sources */,
4B15A9FD208249BB005E6C8D /* StaticAnalyser.cpp in Sources */,
4B055AD31FAE9B0B0060FFFF /* Microdisc.cpp in Sources */,
@ -5994,6 +6011,7 @@
4B0ACC2A23775819008902D0 /* Video.cpp in Sources */,
4B54C0BF1F8D8F450050900F /* Keyboard.cpp in Sources */,
4B3FE75E1F3CF68B00448EE4 /* CPM.cpp in Sources */,
423820112B17CBC800964EFE /* StaticAnalyser.cpp in Sources */,
4BC6236D26F4235400F83DFE /* Copper.cpp in Sources */,
4B2BFDB21DAEF5FF001A68B8 /* Video.cpp in Sources */,
4BEDA3BF25B25563000C2DBD /* Decoder.cpp in Sources */,

View File

@ -672,6 +672,26 @@
<key>NSDocumentClass</key>
<string>$(PRODUCT_MODULE_NAME).MachineDocument</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>ima</string>
</array>
<key>CFBundleTypeName</key>
<string>Raw DOS disk image</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>????</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSTypeIsPackage</key>
<false/>
<key>NSDocumentClass</key>
<string>$(PRODUCT_MODULE_NAME).MachineDocument</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>

View File

@ -52,6 +52,7 @@ SOURCES += \
$$SRC/Analyser/Static/Macintosh/*.cpp \
$$SRC/Analyser/Static/MSX/*.cpp \
$$SRC/Analyser/Static/Oric/*.cpp \
$$SRC/Analyser/Static/PCCompatible/*.cpp \
$$SRC/Analyser/Static/Sega/*.cpp \
$$SRC/Analyser/Static/ZX8081/*.cpp \
$$SRC/Analyser/Static/ZXSpectrum/*.cpp \
@ -174,6 +175,7 @@ HEADERS += \
$$SRC/Analyser/Static/Macintosh/*.hpp \
$$SRC/Analyser/Static/MSX/*.hpp \
$$SRC/Analyser/Static/Oric/*.hpp \
$$SRC/Analyser/Static/PCCompatible/*.hpp \
$$SRC/Analyser/Static/Sega/*.hpp \
$$SRC/Analyser/Static/ZX8081/*.hpp \
\

View File

@ -36,6 +36,7 @@ SOURCES += glob.glob('../../Analyser/Static/Enterprise/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/Macintosh/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/MSX/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/Oric/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/PCCompatible/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/Sega/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/ZX8081/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/ZXSpectrum/*.cpp')

View File

@ -44,7 +44,6 @@ void MFMSectorDump::set_tracks(const std::map<Track::Address, std::shared_ptr<Tr
// in one loop, then write in another.
for(const auto &track : tracks) {
// Assumption here: sector IDs will run from 0.
decode_sectors(*track.second, parsed_track, first_sector_, first_sector_ + uint8_t(sectors_per_track_-1), sector_size_, is_double_density_);
const long file_offset = get_file_offset_for_position(track.first);

View File

@ -22,7 +22,6 @@ namespace Storage::Disk {
class MFMSectorDump: public DiskImage {
public:
MFMSectorDump(const std::string &file_name);
void set_geometry(int sectors_per_track, uint8_t sector_size, uint8_t first_sector, bool is_double_density);
bool get_is_read_only() final;
void set_tracks(const std::map<Track::Address, std::shared_ptr<Track>> &tracks) final;
@ -30,6 +29,7 @@ class MFMSectorDump: public DiskImage {
protected:
Storage::FileHolder file_;
void set_geometry(int sectors_per_track, uint8_t sector_size, uint8_t first_sector, bool is_double_density);
private:
virtual long get_file_offset_for_position(Track::Address address) = 0;

View File

@ -15,12 +15,14 @@
namespace Storage::Encodings::MFM {
using SectorMap = std::map<std::size_t, Sector>;
/*!
Scans @c segment for all included sectors, returning a set that maps from location within
the segment (counted in bits from the beginning and pointing to the location the disk
had reached upon detection of the ID mark) to sector.
*/
std::map<std::size_t, Sector> sectors_from_segment(const Disk::PCMSegment &&segment, bool is_double_density);
SectorMap sectors_from_segment(const Disk::PCMSegment &&segment, bool is_double_density);
}

View File

@ -38,11 +38,12 @@ enum Type: IntType {
ZX80 = 1 << 19,
ZX81 = 1 << 20,
ZXSpectrum = 1 << 21,
PCCompatible = 1 << 22,
Acorn = AcornAtom | AcornElectron | BBCMaster | BBCModelA | BBCModelB,
ZX8081 = ZX80 | ZX81,
AllCartridge = Atari2600 | AcornElectron | Coleco | MSX,
AllDisk = Acorn | AmstradCPC | Commodore | Oric | MSX | ZXSpectrum | Macintosh | AtariST | DiskII | Amiga,
AllDisk = Acorn | AmstradCPC | Commodore | Oric | MSX | ZXSpectrum | Macintosh | AtariST | DiskII | Amiga | PCCompatible,
AllTape = Acorn | AmstradCPC | Commodore | Oric | ZX8081 | MSX | ZXSpectrum,
};