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

Merge pull request #1248 from TomHarte/FAT12Analyser

Add something of a FAT12 analyser.
This commit is contained in:
Thomas Harte 2023-12-05 14:58:18 -05:00 committed by GitHub
commit 6c0a746470
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 326 additions and 148 deletions

View File

@ -0,0 +1,100 @@
//
// StaticAnalyser.cpp
// Clock Signal
//
// Created by Thomas Harte on 05/12/2023.
// Copyright 2023 Thomas Harte. All rights reserved.
//
#include "StaticAnalyser.hpp"
#include "../Enterprise/StaticAnalyser.hpp"
#include "../PCCompatible/StaticAnalyser.hpp"
#include "../../../Storage/Disk/Track/TrackSerialiser.hpp"
#include "../../../Storage/Disk/Encodings/MFM/Constants.hpp"
#include "../../../Storage/Disk/Encodings/MFM/SegmentParser.hpp"
Analyser::Static::TargetList Analyser::Static::FAT12::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType platforms) {
// This analyser can comprehend disks only.
if(media.disks.empty()) return {};
auto &disk = media.disks.front();
TargetList targets;
// Total list of potential platforms is:
//
// * the Enterprise (and, by extension, CP/M-targetted software);
// * the Atari ST;
// * the MSX (ditto on CP/M); and
// * the PC.
//
// (though the MSX and Atari ST don't currently call in here for now)
// If the disk image is very small or large, map it to the PC. That's the only option old enough
// to have used 5.25" media.
if(disk->get_maximum_head_position() <= Storage::Disk::HeadPosition(40)) {
return Analyser::Static::PCCompatible::GetTargets(media, file_name, platforms);
}
// Attempt to grab MFM track 0, sector 1: the boot sector.
const auto track_zero = disk->get_track_at_position(Storage::Disk::Track::Address(0, Storage::Disk::HeadPosition(0)));
const auto sector_map = Storage::Encodings::MFM::sectors_from_segment(
Storage::Disk::track_serialisation(
*track_zero,
Storage::Encodings::MFM::MFMBitLength
), true);
// If no sectors were found, assume this disk was either single density or high density, which both imply the PC.
if(sector_map.empty() || sector_map.size() > 10) {
return Analyser::Static::PCCompatible::GetTargets(media, file_name, platforms);
}
const Storage::Encodings::MFM::Sector *boot_sector = nullptr;
for(const auto &pair: sector_map) {
if(pair.second.address.sector == 1) {
boot_sector = &pair.second;
break;
}
}
// This shouldn't technically be possible since the disk has been identified as FAT12, but be safe.
if(!boot_sector) {
return {};
}
// Check for key phrases that imply a PC disk.
const auto &sample = boot_sector->samples[0];
const std::vector<std::string> pc_strings = {
// MS-DOS strings.
"MSDOS",
"Non-System disk or disk error",
// DOS Plus strings.
"Insert a SYSTEM disk",
};
for(const auto &string: pc_strings) {
if(
std::search(sample.begin(), sample.end(), string.begin(), string.end()) != sample.end()
) {
return Analyser::Static::PCCompatible::GetTargets(media, file_name, platforms);
}
}
// TODO: look for a COM, EXE or BAT, inspect. AUTOEXEC.BAT and/or CONFIG.SYS could be either PC or MSX.
// Disassembling the boot sector doesn't necessarily work, as several Enterprise titles out there in the wild seem
// to have been created by WINIMAGE which adds an x86 PC-style boot sector.
// Enterprise notes: EXOS files all start with a 16-byte header which should begin with a 0 and then have a type
// byte that will be 0xa or lower; cf http://epbas.lgb.hu/readme.html
//
// Some disks commonly passed around as Enterprise software are actually CP/M software, expecting IS-DOS (the CP/M
// clone) to be present. It's certainly possible the same could be true of MSX disks and MSX-DOS. So analysing COM
// files probably means searching for CALL 5s and/or INT 21hs, if not a more rigorous disassembly.
//
// I have not been able to locate a copy of IS-DOS so there's probably not much that can be done here; perhaps I
// could redirect to an MSX2 with MSX-DOS2? Though it'd be nicer if I had a machine that was pure CP/M.
// Being unable to prove that this is a PC disk, throw it to the Enterprise.
return Analyser::Static::Enterprise::GetTargets(media, file_name, platforms);
}

View File

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

View File

@ -25,6 +25,7 @@
#include "Commodore/StaticAnalyser.hpp"
#include "DiskII/StaticAnalyser.hpp"
#include "Enterprise/StaticAnalyser.hpp"
#include "FAT12/StaticAnalyser.hpp"
#include "Macintosh/StaticAnalyser.hpp"
#include "MSX/StaticAnalyser.hpp"
#include "Oric/StaticAnalyser.hpp"
@ -179,11 +180,19 @@ 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("ima", result.disks, Disk::DiskImageHolder<Storage::Disk::FAT12>, TargetPlatform::PCCompatible) // IMG (MS-DOS style)
Format("image", result.disks, Disk::DiskImageHolder<Storage::Disk::MacintoshIMG>, TargetPlatform::Macintosh) // IMG (DiskCopy 4.2)
Format("img", 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)
Format("img", result.disks, Disk::DiskImageHolder<Storage::Disk::PCBooter>, TargetPlatform::PCCompatible) // IMG (PC raw booter)
// Treat PC booter as a potential backup only if this doesn't parse as a FAT12.
if(extension == "img") {
try {
Insert(result.disks, Disk::DiskImageHolder<Storage::Disk::FAT12>, TargetPlatform::FAT12, file_name) // IMG (Enterprise or MS-DOS style)
} catch(...) {
Format("img", result.disks, Disk::DiskImageHolder<Storage::Disk::PCBooter>, TargetPlatform::PCCompatible) // IMG (PC raw booter)
}
}
Format( "ipf",
result.disks,
Disk::DiskImageHolder<Storage::Disk::IPF>,
@ -290,6 +299,7 @@ TargetList Analyser::Static::GetTargets(const std::string &file_name) {
Append(Commodore);
Append(DiskII);
Append(Enterprise);
Append(FAT12);
Append(Macintosh);
Append(MSX);
Append(Oric);

View File

@ -25,135 +25,73 @@ enum class AccessResult {
class i8237 {
public:
void flip_flop_reset() {
printf("DMA: Flip flop reset\n");
next_access_low_ = true;
}
void mask_reset() {
printf("DMA: Mask reset\n");
for(auto &channel : channels_) {
channel.mask = false;
}
}
void master_reset() {
printf("DMA: Master reset\n");
flip_flop_reset();
for(auto &channel : channels_) {
channel.mask = true;
channel.transfer_complete = false;
channel.request = false;
}
// This is a bit of a hack; DMA channel 0 is supposed to be linked to the PIT,
// performing DRAM refresh. It isn't yet. So hack this, and hack that.
channels_[0].transfer_complete = true;
}
//
// CPU-facing interface.
//
template <int address>
void write(uint8_t value) {
printf("DMA: Write %02x to %d\n", value, address);
constexpr int channel = (address >> 1) & 3;
constexpr bool is_count = address & 1;
next_access_low_ ^= true;
if(next_access_low_) {
if constexpr (is_count) {
channels_[channel].count.halves.high = value;
} else {
channels_[channel].address.halves.high = value;
}
} else {
if constexpr (is_count) {
channels_[channel].count.halves.low = value;
} else {
channels_[channel].address.halves.low = value;
}
switch(address) {
default: {
constexpr int channel = (address >> 1) & 3;
constexpr bool is_count = address & 1;
next_access_low_ ^= true;
if(next_access_low_) {
if constexpr (is_count) {
channels_[channel].count.halves.high = value;
} else {
channels_[channel].address.halves.high = value;
}
} else {
if constexpr (is_count) {
channels_[channel].count.halves.low = value;
} else {
channels_[channel].address.halves.low = value;
}
}
} break;
case 0x8: set_command(value); break;
case 0x9: set_reset_request(value); break;
case 0xa: set_reset_mask(value); break;
case 0xb: set_mode(value); break;
case 0xc: flip_flop_reset(); break;
case 0xd: master_reset(); break;
case 0xe: mask_reset(); break;
case 0xf: set_mask(value); break;
}
}
template <int address>
uint8_t read() {
printf("DMA: Read %d\n", address);
constexpr int channel = (address >> 1) & 3;
constexpr bool is_count = address & 1;
switch(address) {
default: {
constexpr int channel = (address >> 1) & 3;
constexpr bool is_count = address & 1;
next_access_low_ ^= true;
if(next_access_low_) {
if constexpr (is_count) {
return channels_[channel].count.halves.high;
} else {
return channels_[channel].address.halves.high;
}
} else {
if constexpr (is_count) {
return channels_[channel].count.halves.low;
} else {
return channels_[channel].address.halves.low;
}
next_access_low_ ^= true;
if(next_access_low_) {
if constexpr (is_count) {
return channels_[channel].count.halves.high;
} else {
return channels_[channel].address.halves.high;
}
} else {
if constexpr (is_count) {
return channels_[channel].count.halves.low;
} else {
return channels_[channel].address.halves.low;
}
}
} break;
case 0x8: return status(); break;
case 0xd: return temporary_register(); break;
}
}
void set_reset_mask(uint8_t value) {
printf("DMA: Set/reset mask %02x\n", value);
channels_[value & 3].mask = value & 4;
}
void set_reset_request(uint8_t value) {
printf("DMA: Set/reset request %02x\n", value);
channels_[value & 3].request = value & 4;
}
void set_mask(uint8_t value) {
printf("DMA: Set mask %02x\n", value);
channels_[0].mask = value & 1;
channels_[1].mask = value & 2;
channels_[2].mask = value & 4;
channels_[3].mask = value & 8;
}
void set_mode(uint8_t value) {
printf("DMA: Set mode %02x\n", value);
channels_[value & 3].transfer = Channel::Transfer((value >> 2) & 3);
channels_[value & 3].autoinitialise = value & 0x10;
channels_[value & 3].address_decrement = value & 0x20;
channels_[value & 3].mode = Channel::Mode(value >> 6);
}
void set_command(uint8_t value) {
printf("DMA: Set command %02x\n", value);
enable_memory_to_memory_ = value & 0x01;
enable_channel0_address_hold_ = value & 0x02;
enable_controller_ = value & 0x04;
compressed_timing_ = value & 0x08;
rotating_priority_ = value & 0x10;
extended_write_selection_ = value & 0x20;
dreq_active_low_ = value & 0x40;
dack_sense_active_high_ = value & 0x80;
}
uint8_t status() {
const uint8_t result =
(channels_[0].transfer_complete ? 0x01 : 0x00) |
(channels_[1].transfer_complete ? 0x02 : 0x00) |
(channels_[2].transfer_complete ? 0x04 : 0x00) |
(channels_[3].transfer_complete ? 0x08 : 0x00) |
(channels_[0].request ? 0x10 : 0x00) |
(channels_[1].request ? 0x20 : 0x00) |
(channels_[2].request ? 0x40 : 0x00) |
(channels_[3].request ? 0x80 : 0x00);
for(auto &channel : channels_) {
channel.transfer_complete = false;
}
printf("DMA: status is %02x\n", result);
return result;
}
//
// Interface for reading/writing via DMA.
//
@ -192,6 +130,96 @@ class i8237 {
}
private:
uint8_t status() {
const uint8_t result =
(channels_[0].transfer_complete ? 0x01 : 0x00) |
(channels_[1].transfer_complete ? 0x02 : 0x00) |
(channels_[2].transfer_complete ? 0x04 : 0x00) |
(channels_[3].transfer_complete ? 0x08 : 0x00) |
(channels_[0].request ? 0x10 : 0x00) |
(channels_[1].request ? 0x20 : 0x00) |
(channels_[2].request ? 0x40 : 0x00) |
(channels_[3].request ? 0x80 : 0x00);
for(auto &channel : channels_) {
channel.transfer_complete = false;
}
printf("DMA: status is %02x\n", result);
return result;
}
uint8_t temporary_register() const {
// Not actually implemented, so...
return 0xff;
}
void flip_flop_reset() {
printf("DMA: Flip flop reset\n");
next_access_low_ = true;
}
void mask_reset() {
printf("DMA: Mask reset\n");
for(auto &channel : channels_) {
channel.mask = false;
}
}
void master_reset() {
printf("DMA: Master reset\n");
flip_flop_reset();
for(auto &channel : channels_) {
channel.mask = true;
channel.transfer_complete = false;
channel.request = false;
}
// This is a bit of a hack; DMA channel 0 is supposed to be linked to the PIT,
// performing DRAM refresh. It isn't yet. So hack this, and hack that.
channels_[0].transfer_complete = true;
}
void set_reset_mask(uint8_t value) {
printf("DMA: Set/reset mask %02x\n", value);
channels_[value & 3].mask = value & 4;
}
void set_reset_request(uint8_t value) {
printf("DMA: Set/reset request %02x\n", value);
channels_[value & 3].request = value & 4;
}
void set_mask(uint8_t value) {
printf("DMA: Set mask %02x\n", value);
channels_[0].mask = value & 1;
channels_[1].mask = value & 2;
channels_[2].mask = value & 4;
channels_[3].mask = value & 8;
}
void set_mode(uint8_t value) {
printf("DMA: Set mode %02x\n", value);
channels_[value & 3].transfer = Channel::Transfer((value >> 2) & 3);
channels_[value & 3].autoinitialise = value & 0x10;
channels_[value & 3].address_decrement = value & 0x20;
channels_[value & 3].mode = Channel::Mode(value >> 6);
}
void set_command(uint8_t value) {
printf("DMA: Set command %02x\n", value);
enable_memory_to_memory_ = value & 0x01;
enable_channel0_address_hold_ = value & 0x02;
enable_controller_ = value & 0x04;
compressed_timing_ = value & 0x08;
rotating_priority_ = value & 0x10;
extended_write_selection_ = value & 0x20;
dreq_active_low_ = value & 0x40;
dack_sense_active_high_ = value & 0x80;
}
// Low/high byte latch.
bool next_access_low_ = true;

View File

@ -806,25 +806,25 @@ class IO {
printf("TODO: NMIs %s\n", (value & 0x80) ? "masked" : "unmasked");
break;
case 0x0000: dma_.controller.write<0>(value); break;
case 0x0001: dma_.controller.write<1>(value); break;
case 0x0002: dma_.controller.write<2>(value); break;
case 0x0003: dma_.controller.write<3>(value); break;
case 0x0004: dma_.controller.write<4>(value); break;
case 0x0005: dma_.controller.write<5>(value); break;
case 0x0006: dma_.controller.write<6>(value); break;
case 0x0007: dma_.controller.write<7>(value); break;
case 0x0008: dma_.controller.set_command(uint8_t(value)); break;
case 0x0009: dma_.controller.set_reset_request(uint8_t(value)); break;
case 0x000a: dma_.controller.set_reset_mask(uint8_t(value)); break;
case 0x000b: dma_.controller.set_mode(uint8_t(value)); break;
case 0x000c: dma_.controller.flip_flop_reset(); break;
case 0x000d: dma_.controller.master_reset(); break;
case 0x000e: dma_.controller.mask_reset(); break;
case 0x000f: dma_.controller.set_mask(uint8_t(value)); break;
case 0x0000: dma_.controller.write<0x0>(uint8_t(value)); break;
case 0x0001: dma_.controller.write<0x1>(uint8_t(value)); break;
case 0x0002: dma_.controller.write<0x2>(uint8_t(value)); break;
case 0x0003: dma_.controller.write<0x3>(uint8_t(value)); break;
case 0x0004: dma_.controller.write<0x4>(uint8_t(value)); break;
case 0x0005: dma_.controller.write<0x5>(uint8_t(value)); break;
case 0x0006: dma_.controller.write<0x6>(uint8_t(value)); break;
case 0x0007: dma_.controller.write<0x7>(uint8_t(value)); break;
case 0x0008: dma_.controller.write<0x8>(uint8_t(value)); break;
case 0x0009: dma_.controller.write<0x9>(uint8_t(value)); break;
case 0x000a: dma_.controller.write<0xa>(uint8_t(value)); break;
case 0x000b: dma_.controller.write<0xb>(uint8_t(value)); break;
case 0x000c: dma_.controller.write<0xc>(uint8_t(value)); break;
case 0x000d: dma_.controller.write<0xd>(uint8_t(value)); break;
case 0x000e: dma_.controller.write<0xe>(uint8_t(value)); break;
case 0x000f: dma_.controller.write<0xf>(uint8_t(value)); break;
case 0x0020: pic_.write<0>(value); break;
case 0x0021: pic_.write<1>(value); break;
case 0x0020: pic_.write<0>(uint8_t(value)); break;
case 0x0021: pic_.write<1>(uint8_t(value)); break;
case 0x0040: pit_.write<0>(uint8_t(value)); break;
case 0x0041: pit_.write<1>(uint8_t(value)); break;
@ -910,21 +910,20 @@ class IO {
printf("Unhandled in: %04x\n", port);
break;
case 0x0000: return dma_.controller.template read<0>();
case 0x0001: return dma_.controller.template read<1>();
case 0x0002: return dma_.controller.template read<2>();
case 0x0003: return dma_.controller.template read<3>();
case 0x0004: return dma_.controller.template read<4>();
case 0x0005: return dma_.controller.template read<5>();
case 0x0006: return dma_.controller.template read<6>();
case 0x0007: return dma_.controller.template read<7>();
case 0x0000: return dma_.controller.read<0x0>();
case 0x0001: return dma_.controller.read<0x1>();
case 0x0002: return dma_.controller.read<0x2>();
case 0x0003: return dma_.controller.read<0x3>();
case 0x0004: return dma_.controller.read<0x4>();
case 0x0005: return dma_.controller.read<0x5>();
case 0x0006: return dma_.controller.read<0x6>();
case 0x0007: return dma_.controller.read<0x7>();
case 0x0008: return dma_.controller.read<0x8>();
case 0x000d: return dma_.controller.read<0xd>();
case 0x0008: return dma_.controller.status();
case 0x0009:
case 0x000a: case 0x000b:
case 0x0009: case 0x000b:
case 0x000c: case 0x000f:
printf("TODO: DMA read from %04x\n", port);
// DMA area, but it doesn't respond.
break;
case 0x0020: return pic_.read<0>();

View File

@ -16,6 +16,8 @@
425739382B051EA800B7D1E4 /* PCCompatible.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 425739372B051EA800B7D1E4 /* PCCompatible.cpp */; };
425739392B051EA800B7D1E4 /* PCCompatible.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 425739372B051EA800B7D1E4 /* PCCompatible.cpp */; };
4281683A2A37AFB4008ECD27 /* DispatcherTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 428168392A37AFB4008ECD27 /* DispatcherTests.mm */; };
429B13602B1F7BDA006BB4CB /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 429B135F2B1F7BDA006BB4CB /* StaticAnalyser.cpp */; };
429B13612B1F7BDA006BB4CB /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 429B135F2B1F7BDA006BB4CB /* StaticAnalyser.cpp */; };
42A5E80C2ABBE04600A0DD5D /* NeskellTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42A5E80B2ABBE04600A0DD5D /* NeskellTests.swift */; };
42A5E8442ABBE16F00A0DD5D /* illegal_rmw_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 42A5E8332ABBE16F00A0DD5D /* illegal_rmw_test.bin */; };
42A5E8452ABBE16F00A0DD5D /* arr_bcd_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 42A5E8342ABBE16F00A0DD5D /* arr_bcd_test.bin */; };
@ -1164,6 +1166,8 @@
4281572E2AA0334300E16AA1 /* Carry.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Carry.hpp; sourceTree = "<group>"; };
428168372A16C25C008ECD27 /* LineLayout.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = LineLayout.hpp; sourceTree = "<group>"; };
428168392A37AFB4008ECD27 /* DispatcherTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DispatcherTests.mm; sourceTree = "<group>"; };
429B135E2B1F7BDA006BB4CB /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaticAnalyser.hpp; sourceTree = "<group>"; };
429B135F2B1F7BDA006BB4CB /* StaticAnalyser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaticAnalyser.cpp; sourceTree = "<group>"; };
42A5E80B2ABBE04600A0DD5D /* NeskellTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NeskellTests.swift; sourceTree = "<group>"; };
42A5E8332ABBE16F00A0DD5D /* illegal_rmw_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = illegal_rmw_test.bin; sourceTree = "<group>"; };
42A5E8342ABBE16F00A0DD5D /* arr_bcd_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = arr_bcd_test.bin; sourceTree = "<group>"; };
@ -2402,6 +2406,15 @@
path = PCCompatible;
sourceTree = "<group>";
};
429B135D2B1F7BDA006BB4CB /* FAT12 */ = {
isa = PBXGroup;
children = (
429B135E2B1F7BDA006BB4CB /* StaticAnalyser.hpp */,
429B135F2B1F7BDA006BB4CB /* StaticAnalyser.cpp */,
);
path = FAT12;
sourceTree = "<group>";
};
42A5E8322ABBE16F00A0DD5D /* Neskell Tests */ = {
isa = PBXGroup;
children = (
@ -3605,6 +3618,7 @@
4B894507201967B4007DE474 /* Disassembler */,
4BD67DC8209BE4D600AB2146 /* DiskII */,
4B051CA426781D6500CA44E8 /* Enterprise */,
429B135D2B1F7BDA006BB4CB /* FAT12 */,
4BB4BFB622A4372E0069048D /* Macintosh */,
4B89450F201967B4007DE474 /* MSX */,
4B8944F6201967B4007DE474 /* Oric */,
@ -5866,6 +5880,7 @@
4B055ADB1FAE9B460060FFFF /* 6560.cpp in Sources */,
4B17B58C20A8A9D9007CCA8F /* StringSerialiser.cpp in Sources */,
4B055AA01FAE85DA0060FFFF /* MFMSectorDump.cpp in Sources */,
429B13612B1F7BDA006BB4CB /* StaticAnalyser.cpp in Sources */,
4B1A1B1F27320FBC00119335 /* Disk.cpp in Sources */,
4BEBFB522002DB30000708CC /* DiskROM.cpp in Sources */,
4BC23A2D2467600F001A6030 /* OPLL.cpp in Sources */,
@ -6107,6 +6122,7 @@
4B71368E1F788112008B8ED9 /* Parser.cpp in Sources */,
4B12C0ED1FCFA98D005BFD93 /* Keyboard.cpp in Sources */,
4BA0F68E1EEA0E8400E9489E /* ZX8081.cpp in Sources */,
429B13602B1F7BDA006BB4CB /* StaticAnalyser.cpp in Sources */,
4BD468F71D8DF41D0084958B /* 1770.cpp in Sources */,
4B051CA22676F52200CA44E8 /* Enterprise.cpp in Sources */,
4B7F1897215486A200388727 /* StaticAnalyser.cpp in Sources */,

View File

@ -49,6 +49,7 @@ SOURCES += \
$$SRC/Analyser/Static/Disassembler/*.cpp \
$$SRC/Analyser/Static/DiskII/*.cpp \
$$SRC/Analyser/Static/Enterprise/*.cpp \
$$SRC/Analyser/Static/FAT12/*.cpp \
$$SRC/Analyser/Static/Macintosh/*.cpp \
$$SRC/Analyser/Static/MSX/*.cpp \
$$SRC/Analyser/Static/Oric/*.cpp \
@ -172,6 +173,7 @@ HEADERS += \
$$SRC/Analyser/Static/Disassembler/*.hpp \
$$SRC/Analyser/Static/DiskII/*.hpp \
$$SRC/Analyser/Static/Enterprise/*.hpp \
$$SRC/Analyser/Static/FAT12/*.hpp \
$$SRC/Analyser/Static/Macintosh/*.hpp \
$$SRC/Analyser/Static/MSX/*.hpp \
$$SRC/Analyser/Static/Oric/*.hpp \

View File

@ -33,6 +33,7 @@ SOURCES += glob.glob('../../Analyser/Static/Commodore/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/Disassembler/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/DiskII/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/Enterprise/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/FAT12/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/Macintosh/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/MSX/*.cpp')
SOURCES += glob.glob('../../Analyser/Static/Oric/*.cpp')