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:
commit
ec39c4a5f0
@ -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;
|
||||
|
25
Analyser/Static/PCCompatible/StaticAnalyser.cpp
Normal file
25
Analyser/Static/PCCompatible/StaticAnalyser.cpp
Normal 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;
|
||||
}
|
22
Analyser/Static/PCCompatible/StaticAnalyser.hpp
Normal file
22
Analyser/Static/PCCompatible/StaticAnalyser.hpp
Normal 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 */
|
33
Analyser/Static/PCCompatible/Target.hpp
Normal file
33
Analyser/Static/PCCompatible/Target.hpp
Normal 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 */
|
@ -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);
|
||||
|
@ -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_;
|
||||
|
@ -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 */,
|
||||
|
@ -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>
|
||||
|
@ -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 \
|
||||
\
|
||||
|
@ -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')
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user