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:
commit
6c0a746470
100
Analyser/Static/FAT12/StaticAnalyser.cpp
Normal file
100
Analyser/Static/FAT12/StaticAnalyser.cpp
Normal 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);
|
||||
}
|
22
Analyser/Static/FAT12/StaticAnalyser.hpp
Normal file
22
Analyser/Static/FAT12/StaticAnalyser.hpp
Normal 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 */
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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>();
|
||||
|
@ -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 */,
|
||||
|
@ -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 \
|
||||
|
@ -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')
|
||||
|
Loading…
Reference in New Issue
Block a user