mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-24 12:30:17 +00:00
Merge pull request #331 from TomHarte/MSXFloppy
Adds floppy emulation for the MSX
This commit is contained in:
commit
b36c917810
@ -23,10 +23,16 @@ void WD1770::set_register(int address, uint8_t value) {
|
||||
switch(address&3) {
|
||||
case 0: {
|
||||
if((value&0xf0) == 0xd0) {
|
||||
printf("!!!TODO: force interrupt!!!\n");
|
||||
update_status([] (Status &status) {
|
||||
status.type = Status::One;
|
||||
});
|
||||
if(value == 0xd0) {
|
||||
// Force interrupt **immediately**.
|
||||
printf("Force interrupt immediately\n");
|
||||
posit_event(static_cast<int>(Event1770::ForceInterrupt));
|
||||
} else {
|
||||
printf("!!!TODO: force interrupt!!!\n");
|
||||
update_status([] (Status &status) {
|
||||
status.type = Status::One;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
command_ = value;
|
||||
posit_event(static_cast<int>(Event1770::Command));
|
||||
@ -169,13 +175,23 @@ void WD1770::posit_event(int new_event_type) {
|
||||
}
|
||||
}
|
||||
|
||||
if(!(interesting_event_mask_ & static_cast<int>(new_event_type))) return;
|
||||
interesting_event_mask_ &= ~new_event_type;
|
||||
if(new_event_type == static_cast<int>(Event1770::ForceInterrupt)) {
|
||||
interesting_event_mask_ = 0;
|
||||
resume_point_ = 0;
|
||||
update_status([] (Status &status) {
|
||||
status.type = Status::One;
|
||||
status.data_request = false;
|
||||
});
|
||||
} else {
|
||||
if(!(interesting_event_mask_ & static_cast<int>(new_event_type))) return;
|
||||
interesting_event_mask_ &= ~new_event_type;
|
||||
}
|
||||
|
||||
Status new_status;
|
||||
BEGIN_SECTION()
|
||||
|
||||
// Wait for a new command, branch to the appropriate handler.
|
||||
case 0:
|
||||
wait_for_command:
|
||||
printf("Idle...\n");
|
||||
set_data_mode(DataMode::Scanning);
|
||||
@ -460,7 +476,7 @@ void WD1770::posit_event(int new_event_type) {
|
||||
sector_++;
|
||||
goto test_type2_write_protection;
|
||||
}
|
||||
printf("Read sector %d\n", sector_);
|
||||
printf("Finished reading sector %d\n", sector_);
|
||||
goto wait_for_command;
|
||||
}
|
||||
goto type2_check_crc;
|
||||
|
@ -116,7 +116,8 @@ class WD1770: public Storage::Disk::MFMController {
|
||||
Command = (1 << 3), // Indicates receipt of a new command.
|
||||
HeadLoad = (1 << 4), // Indicates the head has been loaded (1973 only).
|
||||
Timer = (1 << 5), // Indicates that the delay_time_-powered timer has timed out.
|
||||
IndexHoleTarget = (1 << 6) // Indicates that index_hole_count_ has reached index_hole_count_target_.
|
||||
IndexHoleTarget = (1 << 6), // Indicates that index_hole_count_ has reached index_hole_count_target_.
|
||||
ForceInterrupt = (1 << 7) // Indicates a forced interrupt.
|
||||
};
|
||||
void posit_event(int type);
|
||||
int interesting_event_mask_;
|
||||
|
71
Machines/MSX/DiskROM.cpp
Normal file
71
Machines/MSX/DiskROM.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
//
|
||||
// DiskROM.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 07/01/2018.
|
||||
// Copyright © 2018 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "DiskROM.hpp"
|
||||
|
||||
using namespace MSX;
|
||||
|
||||
DiskROM::DiskROM(const std::vector<uint8_t> &rom) :
|
||||
WD1770(P1793),
|
||||
rom_(rom) {
|
||||
set_is_double_density(true);
|
||||
}
|
||||
|
||||
void DiskROM::write(uint16_t address, uint8_t value) {
|
||||
switch(address) {
|
||||
case 0x7ff8: case 0x7ff9: case 0x7ffa: case 0x7ffb:
|
||||
set_register(address, value);
|
||||
break;
|
||||
case 0x7ffc:
|
||||
selected_head_ = value & 1;
|
||||
if(drives_[0]) drives_[0]->set_head(selected_head_);
|
||||
if(drives_[1]) drives_[1]->set_head(selected_head_);
|
||||
break;
|
||||
case 0x7ffd: {
|
||||
selected_drive_ = value & 1;
|
||||
set_drive(drives_[selected_drive_]);
|
||||
|
||||
bool drive_motor = !!(value & 0x80);
|
||||
if(drives_[0]) drives_[0]->set_motor_on(drive_motor);
|
||||
if(drives_[1]) drives_[1]->set_motor_on(drive_motor);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t DiskROM::read(uint16_t address) {
|
||||
if(address >= 0x7ff8 && address < 0x7ffc) {
|
||||
return get_register(address);
|
||||
}
|
||||
if(address == 0x7fff) {
|
||||
return (get_data_request_line() ? 0x00 : 0x80) | (get_interrupt_request_line() ? 0x00 : 0x40);
|
||||
}
|
||||
return rom_[address & 0x3fff];
|
||||
}
|
||||
|
||||
void DiskROM::run_for(HalfCycles half_cycles) {
|
||||
// Input clock is going to be 7159090/2 Mhz, but the drive controller
|
||||
// needs an 8Mhz clock, so scale up. 8000000/7159090 simplifies to
|
||||
// 800000/715909.
|
||||
controller_cycles_ += 800000 * half_cycles.as_int();
|
||||
WD::WD1770::run_for(Cycles(static_cast<int>(controller_cycles_ / 715909)));
|
||||
controller_cycles_ %= 715909;
|
||||
}
|
||||
|
||||
void DiskROM::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive) {
|
||||
if(!drives_[drive]) {
|
||||
drives_[drive].reset(new Storage::Disk::Drive(8000000, 300, 2));
|
||||
drives_[drive]->set_head(selected_head_);
|
||||
if(drive == selected_drive_) set_drive(drives_[drive]);
|
||||
}
|
||||
drives_[drive]->set_disk(disk);
|
||||
}
|
||||
|
||||
void DiskROM::set_head_load_request(bool head_load) {
|
||||
// Magic!
|
||||
set_head_loaded(head_load);
|
||||
}
|
44
Machines/MSX/DiskROM.hpp
Normal file
44
Machines/MSX/DiskROM.hpp
Normal file
@ -0,0 +1,44 @@
|
||||
//
|
||||
// DiskROM.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 07/01/2018.
|
||||
// Copyright © 2018 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef DiskROM_hpp
|
||||
#define DiskROM_hpp
|
||||
|
||||
#include "ROMSlotHandler.hpp"
|
||||
|
||||
#include "../../Components/1770/1770.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace MSX {
|
||||
|
||||
class DiskROM: public ROMSlotHandler, public WD::WD1770 {
|
||||
public:
|
||||
DiskROM(const std::vector<uint8_t> &rom);
|
||||
|
||||
void write(uint16_t address, uint8_t value) override;
|
||||
uint8_t read(uint16_t address) override;
|
||||
void run_for(HalfCycles half_cycles) override;
|
||||
|
||||
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, int drive);
|
||||
|
||||
private:
|
||||
const std::vector<uint8_t> &rom_;
|
||||
|
||||
long int controller_cycles_ = 0;
|
||||
int selected_drive_ = 0;
|
||||
int selected_head_ = 0;
|
||||
std::shared_ptr<Storage::Disk::Drive> drives_[4];
|
||||
|
||||
void set_head_load_request(bool head_load) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* DiskROM_hpp */
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "MSX.hpp"
|
||||
|
||||
#include "DiskROM.hpp"
|
||||
#include "Keyboard.hpp"
|
||||
#include "ROMSlotHandler.hpp"
|
||||
|
||||
@ -156,19 +157,28 @@ class ConcreteMachine:
|
||||
}
|
||||
|
||||
void configure_as_target(const StaticAnalyser::Target &target) override {
|
||||
// Add a disk cartridge if any disks were supplied.
|
||||
if(!target.media.disks.empty()) {
|
||||
map(2, 0, 0x4000, 0x2000);
|
||||
unmap(2, 0x6000, 0x2000);
|
||||
memory_slots_[2].set_handler(new DiskROM(memory_slots_[2].source));
|
||||
}
|
||||
|
||||
// Insert the media.
|
||||
insert_media(target.media);
|
||||
|
||||
// Type whatever has been requested.
|
||||
if(target.loading_command.length()) {
|
||||
type_string(target.loading_command);
|
||||
}
|
||||
|
||||
// Attach the hardware necessary for a game cartridge, if any.
|
||||
switch(target.msx.cartridge_type) {
|
||||
default: break;
|
||||
case StaticAnalyser::MSXCartridgeType::Konami:
|
||||
memory_slots_[1].set_handler(new Cartridge::KonamiROMSlotHandler(*this, 1));
|
||||
break;
|
||||
case StaticAnalyser::MSXCartridgeType::KonamiWithSCC:
|
||||
// TODO: enable an SCC.
|
||||
memory_slots_[1].set_handler(new Cartridge::KonamiWithSCCROMSlotHandler(*this, 1, scc_));
|
||||
break;
|
||||
case StaticAnalyser::MSXCartridgeType::ASCII8kb:
|
||||
@ -191,6 +201,16 @@ class ConcreteMachine:
|
||||
tape_player_.set_tape(media.tapes.front());
|
||||
}
|
||||
|
||||
if(!media.disks.empty()) {
|
||||
DiskROM *disk_rom = dynamic_cast<DiskROM *>(memory_slots_[2].handler.get());
|
||||
int drive = 0;
|
||||
for(auto &disk : media.disks) {
|
||||
disk_rom->set_disk(disk, drive);
|
||||
drive++;
|
||||
if(drive == 2) break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -439,14 +459,18 @@ class ConcreteMachine:
|
||||
auto roms = roms_with_names(
|
||||
"MSX",
|
||||
{
|
||||
"msx.rom"
|
||||
"msx.rom",
|
||||
"disk.rom"
|
||||
});
|
||||
|
||||
if(!roms[0]) return false;
|
||||
if(!roms[0] || !roms[1]) return false;
|
||||
|
||||
memory_slots_[0].source = std::move(*roms[0]);
|
||||
memory_slots_[0].source.resize(32768);
|
||||
|
||||
memory_slots_[2].source = std::move(*roms[1]);
|
||||
memory_slots_[2].source.resize(16384);
|
||||
|
||||
for(size_t c = 0; c < 8; ++c) {
|
||||
for(size_t slot = 0; slot < 3; ++slot) {
|
||||
memory_slots_[slot].read_pointers[c] = unpopulated_;
|
||||
|
@ -591,6 +591,10 @@
|
||||
4BEA525E1DF33323007E74F2 /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEA525D1DF33323007E74F2 /* Tape.cpp */; };
|
||||
4BEA52631DF339D7007E74F2 /* SoundGenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEA52611DF339D7007E74F2 /* SoundGenerator.cpp */; };
|
||||
4BEA52661DF3472B007E74F2 /* TIASound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEA52641DF3472B007E74F2 /* TIASound.cpp */; };
|
||||
4BEBFB4D2002C4BF000708CC /* MSXDSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEBFB4B2002C4BF000708CC /* MSXDSK.cpp */; };
|
||||
4BEBFB4E2002C4BF000708CC /* MSXDSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEBFB4B2002C4BF000708CC /* MSXDSK.cpp */; };
|
||||
4BEBFB512002DB30000708CC /* DiskROM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEBFB4F2002DB30000708CC /* DiskROM.cpp */; };
|
||||
4BEBFB522002DB30000708CC /* DiskROM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEBFB4F2002DB30000708CC /* DiskROM.cpp */; };
|
||||
4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEE0A6A1D72496600532C7B /* Cartridge.cpp */; };
|
||||
4BEE0A701D72496600532C7B /* PRG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEE0A6D1D72496600532C7B /* PRG.cpp */; };
|
||||
4BEF6AAA1D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */; };
|
||||
@ -1308,6 +1312,10 @@
|
||||
4BEAC08C1E7E0DF800EE56B2 /* Unpaged.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Unpaged.hpp; sourceTree = "<group>"; };
|
||||
4BEAC08D1E7E0E1A00EE56B2 /* Bus.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Bus.hpp; sourceTree = "<group>"; };
|
||||
4BEAC08E1E7E110500EE56B2 /* Pitfall2.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Pitfall2.hpp; sourceTree = "<group>"; };
|
||||
4BEBFB4B2002C4BF000708CC /* MSXDSK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MSXDSK.cpp; sourceTree = "<group>"; };
|
||||
4BEBFB4C2002C4BF000708CC /* MSXDSK.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MSXDSK.hpp; sourceTree = "<group>"; };
|
||||
4BEBFB4F2002DB30000708CC /* DiskROM.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DiskROM.cpp; path = MSX/DiskROM.cpp; sourceTree = "<group>"; };
|
||||
4BEBFB502002DB30000708CC /* DiskROM.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DiskROM.hpp; path = MSX/DiskROM.hpp; sourceTree = "<group>"; };
|
||||
4BEE0A6A1D72496600532C7B /* Cartridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cartridge.cpp; sourceTree = "<group>"; };
|
||||
4BEE0A6B1D72496600532C7B /* Cartridge.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cartridge.hpp; sourceTree = "<group>"; };
|
||||
4BEE0A6D1D72496600532C7B /* PRG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PRG.cpp; sourceTree = "<group>"; };
|
||||
@ -1776,20 +1784,22 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B45188D1F75FD1B00926311 /* AcornADF.cpp */,
|
||||
4B45188E1F75FD1B00926311 /* AcornADF.hpp */,
|
||||
4B45188F1F75FD1B00926311 /* CPCDSK.cpp */,
|
||||
4B4518901F75FD1B00926311 /* CPCDSK.hpp */,
|
||||
4B4518911F75FD1B00926311 /* D64.cpp */,
|
||||
4B4518921F75FD1B00926311 /* D64.hpp */,
|
||||
4B4518931F75FD1B00926311 /* G64.cpp */,
|
||||
4B4518941F75FD1B00926311 /* G64.hpp */,
|
||||
4B4518951F75FD1B00926311 /* HFE.cpp */,
|
||||
4B4518961F75FD1B00926311 /* HFE.hpp */,
|
||||
4B58601C1F806AB200AEE2E3 /* MFMSectorDump.cpp */,
|
||||
4B58601D1F806AB200AEE2E3 /* MFMSectorDump.hpp */,
|
||||
4BEBFB4B2002C4BF000708CC /* MSXDSK.cpp */,
|
||||
4B4518971F75FD1B00926311 /* OricMFMDSK.cpp */,
|
||||
4B4518981F75FD1B00926311 /* OricMFMDSK.hpp */,
|
||||
4B4518991F75FD1B00926311 /* SSD.cpp */,
|
||||
4B45188E1F75FD1B00926311 /* AcornADF.hpp */,
|
||||
4B4518901F75FD1B00926311 /* CPCDSK.hpp */,
|
||||
4B4518921F75FD1B00926311 /* D64.hpp */,
|
||||
4B4518941F75FD1B00926311 /* G64.hpp */,
|
||||
4B4518961F75FD1B00926311 /* HFE.hpp */,
|
||||
4B58601D1F806AB200AEE2E3 /* MFMSectorDump.hpp */,
|
||||
4BEBFB4C2002C4BF000708CC /* MSXDSK.hpp */,
|
||||
4B4518981F75FD1B00926311 /* OricMFMDSK.hpp */,
|
||||
4B45189A1F75FD1B00926311 /* SSD.hpp */,
|
||||
4BFDD7891F7F2DB4008579B9 /* Utility */,
|
||||
);
|
||||
@ -2013,8 +2023,10 @@
|
||||
4B79A4FC1FC8FF9800EEDAD5 /* MSX */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4BEBFB4F2002DB30000708CC /* DiskROM.cpp */,
|
||||
4B12C0EB1FCFA98D005BFD93 /* Keyboard.cpp */,
|
||||
4B79A4FF1FC913C900EEDAD5 /* MSX.cpp */,
|
||||
4BEBFB502002DB30000708CC /* DiskROM.hpp */,
|
||||
4B12C0EC1FCFA98D005BFD93 /* Keyboard.hpp */,
|
||||
4B79A5001FC913C900EEDAD5 /* MSX.hpp */,
|
||||
4B70EF6A1FFDCDF400A3494E /* ROMSlotHandler.hpp */,
|
||||
@ -3349,6 +3361,7 @@
|
||||
4B055AED1FAE9BA20060FFFF /* Z80Storage.cpp in Sources */,
|
||||
4B055AD11FAE9B030060FFFF /* Video.cpp in Sources */,
|
||||
4B055AA21FAE85DA0060FFFF /* SSD.cpp in Sources */,
|
||||
4BEBFB4E2002C4BF000708CC /* MSXDSK.cpp in Sources */,
|
||||
4B055ADD1FAE9B460060FFFF /* i8272.cpp in Sources */,
|
||||
4B055AC51FAE9AEE0060FFFF /* Atari2600.cpp in Sources */,
|
||||
4B055A9C1FAE85DA0060FFFF /* CPCDSK.cpp in Sources */,
|
||||
@ -3369,6 +3382,7 @@
|
||||
4B055A7F1FAE852F0060FFFF /* StaticAnalyser.cpp in Sources */,
|
||||
4B055ADB1FAE9B460060FFFF /* 6560.cpp in Sources */,
|
||||
4B055AA01FAE85DA0060FFFF /* MFMSectorDump.cpp in Sources */,
|
||||
4BEBFB522002DB30000708CC /* DiskROM.cpp in Sources */,
|
||||
4B055AA11FAE85DA0060FFFF /* OricMFMDSK.cpp in Sources */,
|
||||
4B055A951FAE85BB0060FFFF /* BitReverse.cpp in Sources */,
|
||||
4B055A891FAE85580060FFFF /* StaticAnalyser.cpp in Sources */,
|
||||
@ -3483,6 +3497,7 @@
|
||||
4BF829661D8F732B001BAE39 /* Disk.cpp in Sources */,
|
||||
4B448E811F1C45A00009ABD6 /* TZX.cpp in Sources */,
|
||||
4B1BA08A1FD4967800CB4ADA /* CSMSX.mm in Sources */,
|
||||
4BEBFB512002DB30000708CC /* DiskROM.cpp in Sources */,
|
||||
4BEA52631DF339D7007E74F2 /* SoundGenerator.cpp in Sources */,
|
||||
4BC5E4921D7ED365008CF980 /* StaticAnalyser.cpp in Sources */,
|
||||
4BC830D11D6E7C690000A26F /* Tape.cpp in Sources */,
|
||||
@ -3542,6 +3557,7 @@
|
||||
4BCA6CC81D9DD9F000C2D7B2 /* CommodoreROM.cpp in Sources */,
|
||||
4BA22B071D8817CE0008C640 /* Disk.cpp in Sources */,
|
||||
4BEA52661DF3472B007E74F2 /* TIASound.cpp in Sources */,
|
||||
4BEBFB4D2002C4BF000708CC /* MSXDSK.cpp in Sources */,
|
||||
4BBFBB6C1EE8401E00C01E7A /* ZX8081.cpp in Sources */,
|
||||
4B83348A1F5DB94B0097E338 /* IRQDelegatePortHandler.cpp in Sources */,
|
||||
4B7136891F78725F008B8ED9 /* Shifter.cpp in Sources */,
|
||||
|
@ -3,5 +3,6 @@ ROMs for the MSX go here; the copyright status of these is uncertain so they hav
|
||||
Expected files:
|
||||
|
||||
msx.rom
|
||||
disk.rom
|
||||
|
||||
These names match those offered for download at http://fms.komkon.org/fMSX/ (albeit in lowercase), and the emulator has been tested against those images.
|
@ -213,6 +213,9 @@ void StaticAnalyser::MSX::AddTargets(const Media &media, std::list<Target> &dest
|
||||
}
|
||||
}
|
||||
|
||||
// Blindly accept disks for now.
|
||||
target.media.disks = media.disks;
|
||||
|
||||
if(!target.media.empty()) {
|
||||
target.machine = Target::MSX;
|
||||
target.probability = 1.0;
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "../Storage/Disk/DiskImage/Formats/D64.hpp"
|
||||
#include "../Storage/Disk/DiskImage/Formats/G64.hpp"
|
||||
#include "../Storage/Disk/DiskImage/Formats/HFE.hpp"
|
||||
#include "../Storage/Disk/DiskImage/Formats/MSXDSK.hpp"
|
||||
#include "../Storage/Disk/DiskImage/Formats/OricMFMDSK.hpp"
|
||||
#include "../Storage/Disk/DiskImage/Formats/SSD.hpp"
|
||||
|
||||
@ -91,6 +92,7 @@ static Media GetMediaAndPlatforms(const char *file_name, TargetPlatform::IntType
|
||||
Format("d64", result.disks, Disk::DiskImageHolder<Storage::Disk::D64>, TargetPlatform::Commodore) // D64
|
||||
Format("dsd", result.disks, Disk::DiskImageHolder<Storage::Disk::SSD>, TargetPlatform::Acorn) // DSD
|
||||
Format("dsk", result.disks, Disk::DiskImageHolder<Storage::Disk::CPCDSK>, TargetPlatform::AmstradCPC) // DSK (Amstrad CPC)
|
||||
Format("dsk", result.disks, Disk::DiskImageHolder<Storage::Disk::MSXDSK>, TargetPlatform::MSX) // DSK (MSX)
|
||||
Format("dsk", result.disks, Disk::DiskImageHolder<Storage::Disk::OricMFMDSK>, TargetPlatform::Oric) // DSK (Oric)
|
||||
Format("g64", result.disks, Disk::DiskImageHolder<Storage::Disk::G64>, TargetPlatform::Commodore) // G64
|
||||
Format("hfe", result.disks, Disk::DiskImageHolder<Storage::Disk::HFE>, TargetPlatform::AmstradCPC) // HFE (TODO: plus other target platforms)
|
||||
|
@ -33,7 +33,7 @@ AcornADF::AcornADF(const char *file_name) : MFMSectorDump(file_name) {
|
||||
file_.read(bytes, 4);
|
||||
if(bytes[0] != 'H' || bytes[1] != 'u' || bytes[2] != 'g' || bytes[3] != 'o') throw ErrorNotAcornADF;
|
||||
|
||||
set_geometry(sectors_per_track, sector_size, true);
|
||||
set_geometry(sectors_per_track, sector_size, 0, true);
|
||||
}
|
||||
|
||||
int AcornADF::get_head_position_count() {
|
||||
|
@ -14,10 +14,11 @@ using namespace Storage::Disk;
|
||||
|
||||
MFMSectorDump::MFMSectorDump(const char *file_name) : file_(file_name) {}
|
||||
|
||||
void MFMSectorDump::set_geometry(int sectors_per_track, uint8_t sector_size, bool is_double_density) {
|
||||
void MFMSectorDump::set_geometry(int sectors_per_track, uint8_t sector_size, uint8_t first_sector, bool is_double_density) {
|
||||
sectors_per_track_ = sectors_per_track;
|
||||
sector_size_ = sector_size;
|
||||
is_double_density_ = is_double_density;
|
||||
first_sector_ = first_sector;
|
||||
}
|
||||
|
||||
std::shared_ptr<Track> MFMSectorDump::get_track_at_position(Track::Address address) {
|
||||
@ -32,7 +33,7 @@ std::shared_ptr<Track> MFMSectorDump::get_track_at_position(Track::Address addre
|
||||
file_.read(sectors, sizeof(sectors));
|
||||
}
|
||||
|
||||
return track_for_sectors(sectors, static_cast<uint8_t>(address.position), static_cast<uint8_t>(address.head), 0, sector_size_, is_double_density_);
|
||||
return track_for_sectors(sectors, static_cast<uint8_t>(address.position), static_cast<uint8_t>(address.head), first_sector_, sector_size_, is_double_density_);
|
||||
}
|
||||
|
||||
void MFMSectorDump::set_tracks(const std::map<Track::Address, std::shared_ptr<Track>> &tracks) {
|
||||
@ -43,7 +44,7 @@ void MFMSectorDump::set_tracks(const std::map<Track::Address, std::shared_ptr<Tr
|
||||
|
||||
for(auto &track : tracks) {
|
||||
// Assumption here: sector IDs will run from 0.
|
||||
decode_sectors(*track.second, parsed_track, 0, static_cast<uint8_t>(sectors_per_track_-1), sector_size_, is_double_density_);
|
||||
decode_sectors(*track.second, parsed_track, first_sector_, first_sector_ + static_cast<uint8_t>(sectors_per_track_-1), sector_size_, is_double_density_);
|
||||
long file_offset = get_file_offset_for_position(track.first);
|
||||
|
||||
std::lock_guard<std::mutex> lock_guard(file_.get_file_access_mutex());
|
||||
|
@ -21,7 +21,7 @@ namespace Disk {
|
||||
class MFMSectorDump: public DiskImage {
|
||||
public:
|
||||
MFMSectorDump(const char *file_name);
|
||||
void set_geometry(int sectors_per_track, uint8_t sector_size, bool is_double_density);
|
||||
void set_geometry(int sectors_per_track, uint8_t sector_size, uint8_t first_sector, bool is_double_density);
|
||||
|
||||
bool get_is_read_only() override;
|
||||
void set_tracks(const std::map<Track::Address, std::shared_ptr<Track>> &tracks) override;
|
||||
@ -36,6 +36,7 @@ class MFMSectorDump: public DiskImage {
|
||||
int sectors_per_track_ = 0;
|
||||
uint8_t sector_size_ = 0;
|
||||
bool is_double_density_ = true;
|
||||
uint8_t first_sector_ = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
59
Storage/Disk/DiskImage/Formats/MSXDSK.cpp
Normal file
59
Storage/Disk/DiskImage/Formats/MSXDSK.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// MSXDSK.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 07/01/2018.
|
||||
// Copyright © 2018 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "MSXDSK.hpp"
|
||||
|
||||
#include "Utility/ImplicitSectors.hpp"
|
||||
|
||||
namespace {
|
||||
static const int sectors_per_track = 9;
|
||||
static const int sector_size = 2;
|
||||
}
|
||||
|
||||
using namespace Storage::Disk;
|
||||
|
||||
MSXDSK::MSXDSK(const char *file_name) :
|
||||
MFMSectorDump(file_name) {
|
||||
// The only sanity check here is whether a sensible
|
||||
// geometry can be guessed.
|
||||
off_t file_size = file_.stats().st_size;
|
||||
const off_t track_size = 512*9;
|
||||
|
||||
// Throw if there would seemingly be an incomplete track.
|
||||
if(file_size % track_size) throw ErrorNotMSXDSK;
|
||||
|
||||
track_count_ = static_cast<int>(file_size / track_size);
|
||||
head_count_ = 1;
|
||||
|
||||
// Throw if too large or too small or too large for single sided and
|
||||
// clearly not double sided.
|
||||
if(track_count_ < 40) throw ErrorNotMSXDSK;
|
||||
if(track_count_ > 82*2) throw ErrorNotMSXDSK;
|
||||
if(track_count_ > 82 && track_count_&1) throw ErrorNotMSXDSK;
|
||||
|
||||
// The below effectively prefers the idea of a single-sided 80-track disk
|
||||
// to a double-sided 40-track disk. Emulators have to guess.
|
||||
if(track_count_ > 82) {
|
||||
track_count_ /= 2;
|
||||
head_count_ = 2;
|
||||
}
|
||||
|
||||
set_geometry(sectors_per_track, sector_size, 1, true);
|
||||
}
|
||||
|
||||
int MSXDSK::get_head_position_count() {
|
||||
return track_count_;
|
||||
}
|
||||
|
||||
int MSXDSK::get_head_count() {
|
||||
return head_count_;
|
||||
}
|
||||
|
||||
long MSXDSK::get_file_offset_for_position(Track::Address address) {
|
||||
return (address.position*2 + address.head) * 512 * 9;
|
||||
}
|
42
Storage/Disk/DiskImage/Formats/MSXDSK.hpp
Normal file
42
Storage/Disk/DiskImage/Formats/MSXDSK.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
//
|
||||
// MSXDSK.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 07/01/2018.
|
||||
// Copyright © 2018 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef MSXDSK_hpp
|
||||
#define MSXDSK_hpp
|
||||
|
||||
#include "MFMSectorDump.hpp"
|
||||
|
||||
namespace Storage {
|
||||
namespace Disk {
|
||||
|
||||
/*!
|
||||
Provides a @c Disk containing an MSX-style disk image:
|
||||
a sector dump of appropriate proportions.
|
||||
*/
|
||||
class MSXDSK: public MFMSectorDump {
|
||||
public:
|
||||
MSXDSK(const char *file_name);
|
||||
|
||||
enum {
|
||||
ErrorNotMSXDSK,
|
||||
};
|
||||
|
||||
int get_head_position_count() override;
|
||||
int get_head_count() override;
|
||||
|
||||
private:
|
||||
long get_file_offset_for_position(Track::Address address) override;
|
||||
|
||||
int head_count_;
|
||||
int track_count_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MSXDSK_hpp */
|
@ -16,7 +16,7 @@ namespace Storage {
|
||||
namespace Disk {
|
||||
|
||||
/*!
|
||||
Provies a @c Disk containing an Oric MFM-stype disk image — a stream of the MFM data bits with clocks omitted.
|
||||
Provides a @c Disk containing an Oric MFM-stype disk image — a stream of the MFM data bits with clocks omitted.
|
||||
*/
|
||||
class OricMFMDSK: public DiskImage {
|
||||
public:
|
||||
@ -31,7 +31,7 @@ class OricMFMDSK: public DiskImage {
|
||||
ErrorNotOricMFMDSK,
|
||||
};
|
||||
|
||||
// implemented to satisfy @c Disk
|
||||
// implemented to satisfy @c DiskImage
|
||||
int get_head_position_count() override;
|
||||
int get_head_count() override;
|
||||
bool get_is_read_only() override;
|
||||
|
@ -33,7 +33,7 @@ SSD::SSD(const char *file_name) : MFMSectorDump(file_name) {
|
||||
if(track_count_ < 40) track_count_ = 40;
|
||||
else if(track_count_ < 80) track_count_ = 80;
|
||||
|
||||
set_geometry(sectors_per_track, sector_size, false);
|
||||
set_geometry(sectors_per_track, sector_size, 0, false);
|
||||
}
|
||||
|
||||
int SSD::get_head_position_count() {
|
||||
|
@ -28,7 +28,7 @@ std::shared_ptr<Track> Storage::Disk::track_for_sectors(uint8_t *const source, u
|
||||
|
||||
Storage::Encodings::MFM::Sector &new_sector = sectors.back();
|
||||
new_sector.address.track = track;
|
||||
new_sector.address.side = size;
|
||||
new_sector.address.side = side;
|
||||
new_sector.address.sector = first_sector;
|
||||
first_sector++;
|
||||
new_sector.size = size;
|
||||
|
Loading…
Reference in New Issue
Block a user