mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-25 03:32:01 +00:00
Split the static analyser functionality so that it's possible just to ask for the set of media implied by a particular file. Extended ConfigurationTarget so that media alone can be pushed to a machine.
This commit is contained in:
parent
175faebdc9
commit
f68565a33f
@ -776,23 +776,29 @@ class ConcreteMachine:
|
||||
read_pointers_[2] = write_pointers_[2];
|
||||
read_pointers_[3] = roms_[upper_rom_].data();
|
||||
|
||||
// Type whatever is required.
|
||||
if(target.loadingCommand.length()) {
|
||||
set_typer_for_string(target.loadingCommand.c_str());
|
||||
}
|
||||
|
||||
insert_media(target.media);
|
||||
}
|
||||
|
||||
bool insert_media(const StaticAnalyser::Media &media) {
|
||||
// If there are any tapes supplied, use the first of them.
|
||||
if(!target.tapes.empty()) {
|
||||
tape_player_.set_tape(target.tapes.front());
|
||||
if(!media.tapes.empty()) {
|
||||
tape_player_.set_tape(media.tapes.front());
|
||||
}
|
||||
|
||||
// Insert up to four disks.
|
||||
int c = 0;
|
||||
for(auto &disk : target.disks) {
|
||||
for(auto &disk : media.disks) {
|
||||
fdc_.set_disk(disk, c);
|
||||
c++;
|
||||
if(c == 4) break;
|
||||
}
|
||||
|
||||
// Type whatever is required.
|
||||
if(target.loadingCommand.length()) {
|
||||
set_typer_for_string(target.loadingCommand.c_str());
|
||||
}
|
||||
return !media.tapes.empty() || (!media.disks.empty() && has_fdc_);
|
||||
}
|
||||
|
||||
// See header; provides the system ROMs.
|
||||
|
@ -45,7 +45,7 @@ class ConcreteMachine:
|
||||
}
|
||||
|
||||
void configure_as_target(const StaticAnalyser::Target &target) {
|
||||
const std::vector<uint8_t> &rom = target.cartridges.front()->get_segments().front().data;
|
||||
const std::vector<uint8_t> &rom = target.media.cartridges.front()->get_segments().front().data;
|
||||
switch(target.atari.paging_model) {
|
||||
case StaticAnalyser::Atari2600PagingModel::ActivisionStack: bus_.reset(new Cartridge::Cartridge<Cartridge::ActivisionStack>(rom)); break;
|
||||
case StaticAnalyser::Atari2600PagingModel::CBSRamPlus: bus_.reset(new Cartridge::Cartridge<Cartridge::CBSRAMPlus>(rom)); break;
|
||||
@ -81,6 +81,10 @@ class ConcreteMachine:
|
||||
}
|
||||
}
|
||||
|
||||
bool insert_media(const StaticAnalyser::Media &media) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void set_digital_input(Atari2600DigitalInput input, bool state) {
|
||||
switch (input) {
|
||||
case Atari2600DigitalInputJoy1Up: bus_->mos6532_.update_port_input(0, 0x10, state); break;
|
||||
|
@ -274,34 +274,6 @@ class ConcreteMachine:
|
||||
}
|
||||
|
||||
void configure_as_target(const StaticAnalyser::Target &target) {
|
||||
if(target.tapes.size()) {
|
||||
tape_->set_tape(target.tapes.front());
|
||||
}
|
||||
|
||||
if(target.disks.size()) {
|
||||
// construct the 1540
|
||||
c1540_.reset(new ::Commodore::C1540::Machine);
|
||||
|
||||
// attach it to the serial bus
|
||||
c1540_->set_serial_bus(serial_bus_);
|
||||
|
||||
// hand it the disk
|
||||
c1540_->set_disk(target.disks.front());
|
||||
|
||||
// install the ROM if it was previously set
|
||||
install_disk_rom();
|
||||
}
|
||||
|
||||
if(target.cartridges.size()) {
|
||||
rom_address_ = 0xa000;
|
||||
std::vector<uint8_t> rom_image = target.cartridges.front()->get_segments().front().data;
|
||||
rom_length_ = (uint16_t)(rom_image.size());
|
||||
|
||||
rom_ = new uint8_t[0x2000];
|
||||
memcpy(rom_, rom_image.data(), rom_image.size());
|
||||
write_to_map(processor_read_memory_map_, rom_, rom_address_, 0x2000);
|
||||
}
|
||||
|
||||
if(target.loadingCommand.length()) {
|
||||
set_typer_for_string(target.loadingCommand.c_str());
|
||||
}
|
||||
@ -317,6 +289,41 @@ class ConcreteMachine:
|
||||
set_memory_size(ThirtyTwoKB);
|
||||
break;
|
||||
}
|
||||
|
||||
if(target.media.disks.size()) {
|
||||
// construct the 1540
|
||||
c1540_.reset(new ::Commodore::C1540::Machine);
|
||||
|
||||
// attach it to the serial bus
|
||||
c1540_->set_serial_bus(serial_bus_);
|
||||
|
||||
// install the ROM if it was previously set
|
||||
install_disk_rom();
|
||||
}
|
||||
|
||||
insert_media(target.media);
|
||||
}
|
||||
|
||||
bool insert_media(const StaticAnalyser::Media &media) {
|
||||
if(!media.tapes.empty()) {
|
||||
tape_->set_tape(media.tapes.front());
|
||||
}
|
||||
|
||||
if(!media.disks.empty() && c1540_) {
|
||||
c1540_->set_disk(media.disks.front());
|
||||
}
|
||||
|
||||
if(!media.cartridges.empty()) {
|
||||
rom_address_ = 0xa000;
|
||||
std::vector<uint8_t> rom_image = media.cartridges.front()->get_segments().front().data;
|
||||
rom_length_ = (uint16_t)(rom_image.size());
|
||||
|
||||
rom_ = new uint8_t[0x2000];
|
||||
memcpy(rom_, rom_image.data(), rom_image.size());
|
||||
write_to_map(processor_read_memory_map_, rom_, rom_address_, 0x2000);
|
||||
}
|
||||
|
||||
return !media.tapes.empty() || (!media.disks.empty() && c1540_ != nullptr) || !media.cartridges.empty();
|
||||
}
|
||||
|
||||
void set_key_state(uint16_t key, bool isPressed) {
|
||||
|
@ -15,11 +15,19 @@ namespace ConfigurationTarget {
|
||||
|
||||
/*!
|
||||
A ConfigurationTarget::Machine is anything that can accept a StaticAnalyser::Target
|
||||
and configure itself appropriately.
|
||||
and configure itself appropriately, or accept a list of media subsequently to insert.
|
||||
*/
|
||||
class Machine {
|
||||
public:
|
||||
/// Instructs the machine to configure itself as described by @c target and insert the included media.
|
||||
virtual void configure_as_target(const StaticAnalyser::Target &target) = 0;
|
||||
|
||||
/*!
|
||||
Requests that the machine insert @c media as a modification to current state
|
||||
|
||||
@returns @c true if any media was inserted; @c false otherwise.
|
||||
*/
|
||||
virtual bool insert_media(const StaticAnalyser::Media &media) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -81,11 +81,15 @@ class ConcreteMachine:
|
||||
}
|
||||
|
||||
void configure_as_target(const StaticAnalyser::Target &target) {
|
||||
if(target.tapes.size()) {
|
||||
tape_.set_tape(target.tapes.front());
|
||||
if(target.loadingCommand.length()) {
|
||||
set_typer_for_string(target.loadingCommand.c_str());
|
||||
}
|
||||
|
||||
if(target.disks.size()) {
|
||||
if(target.acorn.should_shift_restart) {
|
||||
shift_restart_counter_ = 1000000;
|
||||
}
|
||||
|
||||
if(target.acorn.has_dfs || target.acorn.has_adfs) {
|
||||
plus3_.reset(new Plus3);
|
||||
|
||||
if(target.acorn.has_dfs) {
|
||||
@ -95,23 +99,27 @@ class ConcreteMachine:
|
||||
set_rom(ROMSlot4, adfs_, true);
|
||||
set_rom(ROMSlot5, std::vector<uint8_t>(adfs_.begin() + 16384, adfs_.end()), true);
|
||||
}
|
||||
}
|
||||
|
||||
plus3_->set_disk(target.disks.front(), 0);
|
||||
insert_media(target.media);
|
||||
}
|
||||
|
||||
bool insert_media(const StaticAnalyser::Media &media) {
|
||||
if(!media.tapes.empty()) {
|
||||
tape_.set_tape(media.tapes.front());
|
||||
}
|
||||
|
||||
if(!media.disks.empty() && plus3_) {
|
||||
plus3_->set_disk(media.disks.front(), 0);
|
||||
}
|
||||
|
||||
ROMSlot slot = ROMSlot12;
|
||||
for(std::shared_ptr<Storage::Cartridge::Cartridge> cartridge : target.cartridges) {
|
||||
for(std::shared_ptr<Storage::Cartridge::Cartridge> cartridge : media.cartridges) {
|
||||
set_rom(slot, cartridge->get_segments().front().data, false);
|
||||
slot = (ROMSlot)(((int)slot + 1)&15);
|
||||
}
|
||||
|
||||
if(target.loadingCommand.length()) {
|
||||
set_typer_for_string(target.loadingCommand.c_str());
|
||||
}
|
||||
|
||||
if(target.acorn.should_shift_restart) {
|
||||
shift_restart_counter_ = 1000000;
|
||||
}
|
||||
return !media.tapes.empty() || !media.disks.empty() || !media.cartridges.empty();
|
||||
}
|
||||
|
||||
Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
|
@ -91,24 +91,14 @@ class ConcreteMachine:
|
||||
|
||||
// to satisfy ConfigurationTarget::Machine
|
||||
void configure_as_target(const StaticAnalyser::Target &target) {
|
||||
if(target.tapes.size()) {
|
||||
via_.tape->set_tape(target.tapes.front());
|
||||
}
|
||||
|
||||
if(target.loadingCommand.length()) {
|
||||
set_typer_for_string(target.loadingCommand.c_str());
|
||||
}
|
||||
|
||||
if(target.oric.has_microdisc) {
|
||||
microdisc_is_enabled_ = true;
|
||||
microdisc_did_change_paging_flags(µdisc_);
|
||||
microdisc_.set_delegate(this);
|
||||
}
|
||||
|
||||
int drive_index = 0;
|
||||
for(auto disk : target.disks) {
|
||||
if(drive_index < 4) microdisc_.set_disk(disk, drive_index);
|
||||
drive_index++;
|
||||
if(target.loadingCommand.length()) {
|
||||
set_typer_for_string(target.loadingCommand.c_str());
|
||||
}
|
||||
|
||||
if(target.oric.use_atmos_rom) {
|
||||
@ -126,6 +116,22 @@ class ConcreteMachine:
|
||||
scan_keyboard_address_ = 0xf43c;
|
||||
tape_speed_address_ = 0x67;
|
||||
}
|
||||
|
||||
insert_media(target.media);
|
||||
}
|
||||
|
||||
bool insert_media(const StaticAnalyser::Media &media) {
|
||||
if(media.tapes.size()) {
|
||||
via_.tape->set_tape(media.tapes.front());
|
||||
}
|
||||
|
||||
int drive_index = 0;
|
||||
for(auto disk : media.disks) {
|
||||
if(drive_index < 4) microdisc_.set_disk(disk, drive_index);
|
||||
drive_index++;
|
||||
}
|
||||
|
||||
return !media.tapes.empty() || (!media.disks.empty() && microdisc_is_enabled_);
|
||||
}
|
||||
|
||||
// to satisfy CPU::MOS6502::BusHandler
|
||||
|
@ -268,13 +268,19 @@ class ConcreteMachine:
|
||||
}
|
||||
Memory::Fuzz(ram_);
|
||||
|
||||
if(target.tapes.size()) {
|
||||
tape_player_.set_tape(target.tapes.front());
|
||||
}
|
||||
|
||||
if(target.loadingCommand.length()) {
|
||||
set_typer_for_string(target.loadingCommand.c_str());
|
||||
}
|
||||
|
||||
insert_media(target.media);
|
||||
}
|
||||
|
||||
bool insert_media(const StaticAnalyser::Media &media) {
|
||||
if(!media.tapes.empty()) {
|
||||
tape_player_.set_tape(media.tapes.front());
|
||||
}
|
||||
|
||||
return !media.tapes.empty();
|
||||
}
|
||||
|
||||
void set_typer_for_string(const char *string) {
|
||||
|
@ -164,6 +164,10 @@ class MachineDocument:
|
||||
}
|
||||
}
|
||||
|
||||
final func openGLView(_ view: CSOpenGLView, didReceiveFileAt URL: URL) {
|
||||
// TODO: pass to machine.
|
||||
}
|
||||
|
||||
// MARK: NSDocument overrides
|
||||
override func data(ofType typeName: String) throws -> Data {
|
||||
throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)
|
||||
|
@ -15,12 +15,19 @@
|
||||
/*!
|
||||
Requests that the delegate produce an image of its current output state. May be called on
|
||||
any queue or thread.
|
||||
@param view The view makin the request.
|
||||
@param view The view making the request.
|
||||
@param onlyIfDirty If @c YES then the delegate may decline to redraw if its output would be
|
||||
identical to the previous frame. If @c NO then the delegate must draw.
|
||||
*/
|
||||
- (void)openGLView:(nonnull CSOpenGLView *)view drawViewOnlyIfDirty:(BOOL)onlyIfDirty;
|
||||
|
||||
/*!
|
||||
Announces receipt of a file by drag and drop to the delegate.
|
||||
@param view The view making the request.
|
||||
@param URL The file URL of the received file.
|
||||
*/
|
||||
- (void)openGLView:(nonnull CSOpenGLView *)view didReceiveFileAtURL:(nonnull NSURL *)URL;
|
||||
|
||||
@end
|
||||
|
||||
@protocol CSOpenGLViewResponderDelegate <NSObject>
|
||||
|
@ -10,6 +10,9 @@
|
||||
@import CoreVideo;
|
||||
@import GLKit;
|
||||
|
||||
@interface CSOpenGLView () <NSDraggingDestination>
|
||||
@end
|
||||
|
||||
@implementation CSOpenGLView {
|
||||
CVDisplayLinkRef _displayLink;
|
||||
}
|
||||
@ -105,6 +108,9 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
|
||||
self.pixelFormat = pixelFormat;
|
||||
self.openGLContext = context;
|
||||
self.wantsBestResolutionOpenGLSurface = YES;
|
||||
|
||||
// Register to receive dragged and dropped file URLs.
|
||||
[self registerForDraggedTypes:@[(__bridge NSString *)kUTTypeFileURL]];
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
@ -150,4 +156,24 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
|
||||
[self.responderDelegate flagsChanged:theEvent];
|
||||
}
|
||||
|
||||
#pragma mark - NSDraggingDestination
|
||||
|
||||
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
|
||||
{
|
||||
for(NSPasteboardItem *item in [[sender draggingPasteboard] pasteboardItems])
|
||||
{
|
||||
NSURL *URL = [NSURL URLWithString:[item stringForType:(__bridge NSString *)kUTTypeFileURL]];
|
||||
|
||||
NSLog(@"%@", URL);
|
||||
[self.delegate openGLView:self didReceiveFileAtURL:URL];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender
|
||||
{
|
||||
// we'll drag and drop, yeah?
|
||||
return NSDragOperationLink;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -56,11 +56,7 @@ static std::list<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
return acorn_cartridges;
|
||||
}
|
||||
|
||||
void StaticAnalyser::Acorn::AddTargets(
|
||||
const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
|
||||
const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
|
||||
const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
|
||||
std::list<StaticAnalyser::Target> &destination) {
|
||||
void StaticAnalyser::Acorn::AddTargets(const Media &media, std::list<Target> &destination) {
|
||||
Target target;
|
||||
target.machine = Target::Electron;
|
||||
target.probability = 1.0; // TODO: a proper estimation
|
||||
@ -69,11 +65,11 @@ void StaticAnalyser::Acorn::AddTargets(
|
||||
target.acorn.should_shift_restart = false;
|
||||
|
||||
// strip out inappropriate cartridges
|
||||
target.cartridges = AcornCartridgesFrom(cartridges);
|
||||
target.media.cartridges = AcornCartridgesFrom(media.cartridges);
|
||||
|
||||
// if there are any tapes, attempt to get data from the first
|
||||
if(tapes.size() > 0) {
|
||||
std::shared_ptr<Storage::Tape::Tape> tape = tapes.front();
|
||||
if(media.tapes.size() > 0) {
|
||||
std::shared_ptr<Storage::Tape::Tape> tape = media.tapes.front();
|
||||
std::list<File> files = GetFiles(tape);
|
||||
tape->reset();
|
||||
|
||||
@ -102,17 +98,17 @@ void StaticAnalyser::Acorn::AddTargets(
|
||||
// then the loading command is *RUN. Otherwise it's CHAIN"".
|
||||
target.loadingCommand = is_basic ? "CHAIN\"\"\n" : "*RUN\n";
|
||||
|
||||
target.tapes = tapes;
|
||||
target.media.tapes = media.tapes;
|
||||
}
|
||||
}
|
||||
|
||||
if(disks.size() > 0) {
|
||||
std::shared_ptr<Storage::Disk::Disk> disk = disks.front();
|
||||
if(media.disks.size() > 0) {
|
||||
std::shared_ptr<Storage::Disk::Disk> disk = media.disks.front();
|
||||
std::unique_ptr<Catalogue> dfs_catalogue, adfs_catalogue;
|
||||
dfs_catalogue = GetDFSCatalogue(disk);
|
||||
if(dfs_catalogue == nullptr) adfs_catalogue = GetADFSCatalogue(disk);
|
||||
if(dfs_catalogue || adfs_catalogue) {
|
||||
target.disks = disks;
|
||||
target.media.disks = media.disks;
|
||||
target.acorn.has_dfs = !!dfs_catalogue;
|
||||
target.acorn.has_adfs = !!adfs_catalogue;
|
||||
|
||||
@ -124,6 +120,6 @@ void StaticAnalyser::Acorn::AddTargets(
|
||||
}
|
||||
}
|
||||
|
||||
if(target.tapes.size() || target.disks.size() || target.cartridges.size())
|
||||
if(target.media.tapes.size() || target.media.disks.size() || target.media.cartridges.size())
|
||||
destination.push_back(target);
|
||||
}
|
||||
|
@ -14,12 +14,7 @@
|
||||
namespace StaticAnalyser {
|
||||
namespace Acorn {
|
||||
|
||||
void AddTargets(
|
||||
const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
|
||||
const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
|
||||
const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
|
||||
std::list<Target> &destination
|
||||
);
|
||||
void AddTargets(const Media &media, std::list<Target> &destination);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -128,28 +128,24 @@ static void InspectSystemCatalogue(
|
||||
InspectDataCatalogue(catalogue, target);
|
||||
}
|
||||
|
||||
void StaticAnalyser::AmstradCPC::AddTargets(
|
||||
const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
|
||||
const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
|
||||
const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
|
||||
std::list<StaticAnalyser::Target> &destination) {
|
||||
void StaticAnalyser::AmstradCPC::AddTargets(const Media &media, std::list<Target> &destination) {
|
||||
Target target;
|
||||
target.machine = Target::AmstradCPC;
|
||||
target.probability = 1.0;
|
||||
target.disks = disks;
|
||||
target.tapes = tapes;
|
||||
target.cartridges = cartridges;
|
||||
target.media.disks = media.disks;
|
||||
target.media.tapes = media.tapes;
|
||||
target.media.cartridges = media.cartridges;
|
||||
|
||||
target.amstradcpc.model = AmstradCPCModel::CPC6128;
|
||||
|
||||
if(!target.tapes.empty()) {
|
||||
if(!target.media.tapes.empty()) {
|
||||
// Ugliness flows here: assume the CPC isn't smart enough to pause between pressing
|
||||
// enter and responding to the follow-on prompt to press a key, so just type for
|
||||
// a while. Yuck!
|
||||
target.loadingCommand = "|tape\nrun\"\n1234567890";
|
||||
}
|
||||
|
||||
if(!target.disks.empty()) {
|
||||
if(!target.media.disks.empty()) {
|
||||
Storage::Disk::CPM::ParameterBlock data_format;
|
||||
data_format.sectors_per_track = 9;
|
||||
data_format.tracks = 40;
|
||||
@ -158,7 +154,7 @@ void StaticAnalyser::AmstradCPC::AddTargets(
|
||||
data_format.catalogue_allocation_bitmap = 0xc000;
|
||||
data_format.reserved_tracks = 0;
|
||||
|
||||
std::unique_ptr<Storage::Disk::CPM::Catalogue> data_catalogue = Storage::Disk::CPM::GetCatalogue(target.disks.front(), data_format);
|
||||
std::unique_ptr<Storage::Disk::CPM::Catalogue> data_catalogue = Storage::Disk::CPM::GetCatalogue(target.media.disks.front(), data_format);
|
||||
if(data_catalogue) {
|
||||
InspectDataCatalogue(*data_catalogue, target);
|
||||
} else {
|
||||
@ -170,9 +166,9 @@ void StaticAnalyser::AmstradCPC::AddTargets(
|
||||
system_format.catalogue_allocation_bitmap = 0xc000;
|
||||
system_format.reserved_tracks = 2;
|
||||
|
||||
std::unique_ptr<Storage::Disk::CPM::Catalogue> system_catalogue = Storage::Disk::CPM::GetCatalogue(target.disks.front(), system_format);
|
||||
std::unique_ptr<Storage::Disk::CPM::Catalogue> system_catalogue = Storage::Disk::CPM::GetCatalogue(target.media.disks.front(), system_format);
|
||||
if(system_catalogue) {
|
||||
InspectSystemCatalogue(target.disks.front(), *system_catalogue, target);
|
||||
InspectSystemCatalogue(target.media.disks.front(), *system_catalogue, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,12 +14,7 @@
|
||||
namespace StaticAnalyser {
|
||||
namespace AmstradCPC {
|
||||
|
||||
void AddTargets(
|
||||
const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
|
||||
const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
|
||||
const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
|
||||
std::list<Target> &destination
|
||||
);
|
||||
void AddTargets(const Media &media, std::list<Target> &destination);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -178,24 +178,18 @@ static void DeterminePagingForCartridge(StaticAnalyser::Target &target, const St
|
||||
}
|
||||
}
|
||||
|
||||
void StaticAnalyser::Atari::AddTargets(
|
||||
const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
|
||||
const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
|
||||
const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
|
||||
std::list<StaticAnalyser::Target> &destination) {
|
||||
// TODO: sanity checking; is this image really for an Atari 2600?
|
||||
void StaticAnalyser::Atari::AddTargets(const Media &media, std::list<Target> &destination) {
|
||||
// TODO: sanity checking; is this image really for an Atari 2600.
|
||||
Target target;
|
||||
target.machine = Target::Atari2600;
|
||||
target.probability = 1.0;
|
||||
target.disks = disks;
|
||||
target.tapes = tapes;
|
||||
target.cartridges = cartridges;
|
||||
target.media.cartridges = media.cartridges;
|
||||
target.atari.paging_model = Atari2600PagingModel::None;
|
||||
target.atari.uses_superchip = false;
|
||||
|
||||
// try to figure out the paging scheme
|
||||
if(!cartridges.empty()) {
|
||||
const std::list<Storage::Cartridge::Cartridge::Segment> &segments = cartridges.front()->get_segments();
|
||||
if(!media.cartridges.empty()) {
|
||||
const std::list<Storage::Cartridge::Cartridge::Segment> &segments = media.cartridges.front()->get_segments();
|
||||
|
||||
if(segments.size() == 1) {
|
||||
const Storage::Cartridge::Cartridge::Segment &segment = segments.front();
|
||||
|
@ -14,12 +14,7 @@
|
||||
namespace StaticAnalyser {
|
||||
namespace Atari {
|
||||
|
||||
void AddTargets(
|
||||
const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
|
||||
const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
|
||||
const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
|
||||
std::list<Target> &destination
|
||||
);
|
||||
void AddTargets(const Media &media, std::list<Target> &destination);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -38,11 +38,7 @@ static std::list<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
return vic20_cartridges;
|
||||
}
|
||||
|
||||
void StaticAnalyser::Commodore::AddTargets(
|
||||
const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
|
||||
const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
|
||||
const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
|
||||
std::list<StaticAnalyser::Target> &destination) {
|
||||
void StaticAnalyser::Commodore::AddTargets(const Media &media, std::list<Target> &destination) {
|
||||
Target target;
|
||||
target.machine = Target::Vic20; // TODO: machine estimation
|
||||
target.probability = 1.0; // TODO: a proper estimation
|
||||
@ -52,26 +48,26 @@ void StaticAnalyser::Commodore::AddTargets(
|
||||
bool is_disk = false;
|
||||
|
||||
// strip out inappropriate cartridges
|
||||
target.cartridges = Vic20CartridgesFrom(cartridges);
|
||||
target.media.cartridges = Vic20CartridgesFrom(media.cartridges);
|
||||
|
||||
// check disks
|
||||
for(auto &disk : disks) {
|
||||
for(auto &disk : media.disks) {
|
||||
std::list<File> disk_files = GetFiles(disk);
|
||||
if(disk_files.size()) {
|
||||
is_disk = true;
|
||||
files.splice(files.end(), disk_files);
|
||||
target.disks = disks;
|
||||
target.media.disks.push_back(disk);
|
||||
if(!device) device = 8;
|
||||
}
|
||||
}
|
||||
|
||||
// check tapes
|
||||
for(auto &tape : tapes) {
|
||||
for(auto &tape : media.tapes) {
|
||||
std::list<File> tape_files = GetFiles(tape);
|
||||
tape->reset();
|
||||
if(tape_files.size()) {
|
||||
files.splice(files.end(), tape_files);
|
||||
target.tapes = tapes;
|
||||
target.media.tapes.push_back(tape);
|
||||
if(!device) device = 1;
|
||||
}
|
||||
}
|
||||
@ -140,6 +136,6 @@ void StaticAnalyser::Commodore::AddTargets(
|
||||
}
|
||||
}
|
||||
|
||||
if(target.tapes.size() || target.cartridges.size() || target.disks.size())
|
||||
if(target.media.tapes.size() || target.media.cartridges.size() || target.media.disks.size())
|
||||
destination.push_back(target);
|
||||
}
|
||||
|
@ -14,12 +14,7 @@
|
||||
namespace StaticAnalyser {
|
||||
namespace Commodore {
|
||||
|
||||
void AddTargets(
|
||||
const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
|
||||
const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
|
||||
const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
|
||||
std::list<Target> &destination
|
||||
);
|
||||
void AddTargets(const Media &media, std::list<Target> &destination);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -72,11 +72,7 @@ static int Basic11Score(const StaticAnalyser::MOS6502::Disassembly &disassembly)
|
||||
return Score(disassembly, rom_functions, variable_locations);
|
||||
}
|
||||
|
||||
void StaticAnalyser::Oric::AddTargets(
|
||||
const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
|
||||
const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
|
||||
const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
|
||||
std::list<StaticAnalyser::Target> &destination) {
|
||||
void StaticAnalyser::Oric::AddTargets(const Media &media, std::list<Target> &destination) {
|
||||
Target target;
|
||||
target.machine = Target::Oric;
|
||||
target.probability = 1.0;
|
||||
@ -84,7 +80,7 @@ void StaticAnalyser::Oric::AddTargets(
|
||||
int basic10_votes = 0;
|
||||
int basic11_votes = 0;
|
||||
|
||||
for(auto &tape : tapes) {
|
||||
for(auto &tape : media.tapes) {
|
||||
std::list<File> tape_files = GetFiles(tape);
|
||||
tape->reset();
|
||||
if(tape_files.size()) {
|
||||
@ -100,15 +96,15 @@ void StaticAnalyser::Oric::AddTargets(
|
||||
}
|
||||
}
|
||||
|
||||
target.tapes.push_back(tape);
|
||||
target.media.tapes.push_back(tape);
|
||||
target.loadingCommand = "CLOAD\"\"\n";
|
||||
}
|
||||
}
|
||||
|
||||
// trust that any disk supplied can be handled by the Microdisc. TODO: check.
|
||||
if(!disks.empty()) {
|
||||
if(!media.disks.empty()) {
|
||||
target.oric.has_microdisc = true;
|
||||
target.disks = disks;
|
||||
target.media.disks = media.disks;
|
||||
} else {
|
||||
target.oric.has_microdisc = false;
|
||||
}
|
||||
@ -117,6 +113,6 @@ void StaticAnalyser::Oric::AddTargets(
|
||||
target.oric.use_atmos_rom = basic11_votes >= basic10_votes;
|
||||
if(target.oric.has_microdisc) target.oric.use_atmos_rom = true;
|
||||
|
||||
if(target.tapes.size() || target.disks.size() || target.cartridges.size())
|
||||
if(target.media.tapes.size() || target.media.disks.size() || target.media.cartridges.size())
|
||||
destination.push_back(target);
|
||||
}
|
||||
|
@ -14,12 +14,7 @@
|
||||
namespace StaticAnalyser {
|
||||
namespace Oric {
|
||||
|
||||
void AddTargets(
|
||||
const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
|
||||
const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
|
||||
const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
|
||||
std::list<Target> &destination
|
||||
);
|
||||
void AddTargets(const Media &media, std::list<Target> &destination);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,86 @@ enum class TargetPlatform: TargetPlatformType {
|
||||
|
||||
using namespace StaticAnalyser;
|
||||
|
||||
static Media GetMediaAndPlatforms(const char *file_name, TargetPlatformType &potential_platforms) {
|
||||
// Get the extension, if any; it will be assumed that extensions are reliable, so an extension is a broad-phase
|
||||
// test as to file format.
|
||||
const char *mixed_case_extension = strrchr(file_name, '.');
|
||||
char *lowercase_extension = nullptr;
|
||||
if(mixed_case_extension) {
|
||||
lowercase_extension = strdup(mixed_case_extension+1);
|
||||
char *parser = lowercase_extension;
|
||||
while(*parser) {
|
||||
*parser = (char)tolower(*parser);
|
||||
parser++;
|
||||
}
|
||||
}
|
||||
|
||||
Media result;
|
||||
#define Insert(list, class, platforms) \
|
||||
list.emplace_back(new Storage::class(file_name));\
|
||||
potential_platforms |= (TargetPlatformType)(platforms);\
|
||||
|
||||
#define TryInsert(list, class, platforms) \
|
||||
try {\
|
||||
Insert(list, class, platforms) \
|
||||
} catch(...) {}
|
||||
|
||||
#define Format(extension, list, class, platforms) \
|
||||
if(!strcmp(lowercase_extension, extension)) { \
|
||||
TryInsert(list, class, platforms) \
|
||||
}
|
||||
|
||||
if(lowercase_extension) {
|
||||
Format("80", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // 80
|
||||
Format("81", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // 81
|
||||
Format("a26", result.cartridges, Cartridge::BinaryDump, TargetPlatform::Atari2600) // A26
|
||||
Format("adf", result.disks, Disk::AcornADF, TargetPlatform::Acorn) // ADF
|
||||
Format("bin", result.cartridges, Cartridge::BinaryDump, TargetPlatform::Atari2600) // BIN
|
||||
Format("cdt", result.tapes, Tape::TZX, TargetPlatform::AmstradCPC) // CDT
|
||||
Format("csw", result.tapes, Tape::CSW, TargetPlatform::AllTape) // CSW
|
||||
Format("d64", result.disks, Disk::D64, TargetPlatform::Commodore) // D64
|
||||
Format("dsd", result.disks, Disk::SSD, TargetPlatform::Acorn) // DSD
|
||||
Format("dsk", result.disks, Disk::CPCDSK, TargetPlatform::AmstradCPC) // DSK (Amstrad CPC)
|
||||
Format("dsk", result.disks, Disk::OricMFMDSK, TargetPlatform::Oric) // DSK (Oric)
|
||||
Format("g64", result.disks, Disk::G64, TargetPlatform::Commodore) // G64
|
||||
Format("o", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // O
|
||||
Format("p", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P
|
||||
Format("p81", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P81
|
||||
|
||||
// PRG
|
||||
if(!strcmp(lowercase_extension, "prg")) {
|
||||
// try instantiating as a ROM; failing that accept as a tape
|
||||
try {
|
||||
Insert(result.cartridges, Cartridge::PRG, TargetPlatform::Commodore)
|
||||
} catch(...) {
|
||||
try {
|
||||
Insert(result.tapes, Tape::PRG, TargetPlatform::Commodore)
|
||||
} catch(...) {}
|
||||
}
|
||||
}
|
||||
|
||||
Format("rom", result.cartridges, Cartridge::BinaryDump, TargetPlatform::Acorn) // ROM
|
||||
Format("ssd", result.disks, Disk::SSD, TargetPlatform::Acorn) // SSD
|
||||
Format("tap", result.tapes, Tape::CommodoreTAP, TargetPlatform::Commodore) // TAP (Commodore)
|
||||
Format("tap", result.tapes, Tape::OricTAP, TargetPlatform::Oric) // TAP (Oric)
|
||||
Format("tzx", result.tapes, Tape::TZX, TargetPlatform::ZX8081) // TZX
|
||||
Format("uef", result.tapes, Tape::UEF, TargetPlatform::Acorn) // UEF (tape)
|
||||
|
||||
#undef Format
|
||||
#undef Insert
|
||||
#undef TryInsert
|
||||
|
||||
free(lowercase_extension);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Media StaticAnalyser::GetMedia(const char *file_name) {
|
||||
TargetPlatformType throwaway;
|
||||
return GetMediaAndPlatforms(file_name, throwaway);
|
||||
}
|
||||
|
||||
std::list<Target> StaticAnalyser::GetTargets(const char *file_name) {
|
||||
std::list<Target> targets;
|
||||
|
||||
@ -71,80 +151,21 @@ std::list<Target> StaticAnalyser::GetTargets(const char *file_name) {
|
||||
|
||||
// Collect all disks, tapes and ROMs as can be extrapolated from this file, forming the
|
||||
// union of all platforms this file might be a target for.
|
||||
std::list<std::shared_ptr<Storage::Disk::Disk>> disks;
|
||||
std::list<std::shared_ptr<Storage::Tape::Tape>> tapes;
|
||||
std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> cartridges;
|
||||
TargetPlatformType potential_platforms = 0;
|
||||
Media media = GetMediaAndPlatforms(file_name, potential_platforms);
|
||||
|
||||
#define Insert(list, class, platforms) \
|
||||
list.emplace_back(new Storage::class(file_name));\
|
||||
potential_platforms |= (TargetPlatformType)(platforms);\
|
||||
|
||||
#define TryInsert(list, class, platforms) \
|
||||
try {\
|
||||
Insert(list, class, platforms) \
|
||||
} catch(...) {}
|
||||
|
||||
#define Format(extension, list, class, platforms) \
|
||||
if(!strcmp(lowercase_extension, extension)) { \
|
||||
TryInsert(list, class, platforms) \
|
||||
}
|
||||
|
||||
if(lowercase_extension) {
|
||||
Format("80", tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // 80
|
||||
Format("81", tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // 81
|
||||
Format("a26", cartridges, Cartridge::BinaryDump, TargetPlatform::Atari2600) // A26
|
||||
Format("adf", disks, Disk::AcornADF, TargetPlatform::Acorn) // ADF
|
||||
Format("bin", cartridges, Cartridge::BinaryDump, TargetPlatform::Atari2600) // BIN
|
||||
Format("cdt", tapes, Tape::TZX, TargetPlatform::AmstradCPC) // CDT
|
||||
Format("csw", tapes, Tape::CSW, TargetPlatform::AllTape) // CSW
|
||||
Format("d64", disks, Disk::D64, TargetPlatform::Commodore) // D64
|
||||
Format("dsd", disks, Disk::SSD, TargetPlatform::Acorn) // DSD
|
||||
Format("dsk", disks, Disk::CPCDSK, TargetPlatform::AmstradCPC) // DSK (Amstrad CPC)
|
||||
Format("dsk", disks, Disk::OricMFMDSK, TargetPlatform::Oric) // DSK (Oric)
|
||||
Format("g64", disks, Disk::G64, TargetPlatform::Commodore) // G64
|
||||
Format("o", tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // O
|
||||
Format("p", tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P
|
||||
Format("p81", tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P81
|
||||
|
||||
// PRG
|
||||
if(!strcmp(lowercase_extension, "prg")) {
|
||||
// try instantiating as a ROM; failing that accept as a tape
|
||||
try {
|
||||
Insert(cartridges, Cartridge::PRG, TargetPlatform::Commodore)
|
||||
} catch(...) {
|
||||
try {
|
||||
Insert(tapes, Tape::PRG, TargetPlatform::Commodore)
|
||||
} catch(...) {}
|
||||
}
|
||||
}
|
||||
|
||||
Format("rom", cartridges, Cartridge::BinaryDump, TargetPlatform::Acorn) // ROM
|
||||
Format("ssd", disks, Disk::SSD, TargetPlatform::Acorn) // SSD
|
||||
Format("tap", tapes, Tape::CommodoreTAP, TargetPlatform::Commodore) // TAP (Commodore)
|
||||
Format("tap", tapes, Tape::OricTAP, TargetPlatform::Oric) // TAP (Oric)
|
||||
Format("tzx", tapes, Tape::TZX, TargetPlatform::ZX8081) // TZX
|
||||
Format("uef", tapes, Tape::UEF, TargetPlatform::Acorn) // UEF (tape)
|
||||
|
||||
#undef Format
|
||||
#undef Insert
|
||||
#undef TryInsert
|
||||
|
||||
// Hand off to platform-specific determination of whether these things are actually compatible and,
|
||||
// if so, how to load them. (TODO)
|
||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::Acorn) Acorn::AddTargets(disks, tapes, cartridges, targets);
|
||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::AmstradCPC) AmstradCPC::AddTargets(disks, tapes, cartridges, targets);
|
||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::Atari2600) Atari::AddTargets(disks, tapes, cartridges, targets);
|
||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::Commodore) Commodore::AddTargets(disks, tapes, cartridges, targets);
|
||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::Oric) Oric::AddTargets(disks, tapes, cartridges, targets);
|
||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::ZX8081) ZX8081::AddTargets(disks, tapes, cartridges, targets);
|
||||
|
||||
free(lowercase_extension);
|
||||
}
|
||||
// Hand off to platform-specific determination of whether these things are actually compatible and,
|
||||
// if so, how to load them.
|
||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::Acorn) Acorn::AddTargets(media, targets);
|
||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::AmstradCPC) AmstradCPC::AddTargets(media, targets);
|
||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::Atari2600) Atari::AddTargets(media, targets);
|
||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::Commodore) Commodore::AddTargets(media, targets);
|
||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::Oric) Oric::AddTargets(media, targets);
|
||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::ZX8081) ZX8081::AddTargets(media, targets);
|
||||
|
||||
// Reset any tapes to their initial position
|
||||
for(auto target : targets) {
|
||||
for(auto tape : target.tapes) {
|
||||
for(auto tape : media.tapes) {
|
||||
tape->reset();
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,15 @@ enum class AmstradCPCModel {
|
||||
CPC6128
|
||||
};
|
||||
|
||||
/*!
|
||||
A list of disks, tapes and cartridges.
|
||||
*/
|
||||
struct Media {
|
||||
std::list<std::shared_ptr<Storage::Disk::Disk>> disks;
|
||||
std::list<std::shared_ptr<Storage::Tape::Tape>> tapes;
|
||||
std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> cartridges;
|
||||
};
|
||||
|
||||
/*!
|
||||
A list of disks, tapes and cartridges plus information about the machine to which to attach them and its configuration,
|
||||
and instructions on how to launch the software attached, plus a measure of confidence in this target's correctness.
|
||||
@ -102,10 +111,7 @@ struct Target {
|
||||
};
|
||||
|
||||
std::string loadingCommand;
|
||||
|
||||
std::list<std::shared_ptr<Storage::Disk::Disk>> disks;
|
||||
std::list<std::shared_ptr<Storage::Tape::Tape>> tapes;
|
||||
std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> cartridges;
|
||||
Media media;
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -115,6 +121,11 @@ struct Target {
|
||||
*/
|
||||
std::list<Target> GetTargets(const char *file_name);
|
||||
|
||||
/*!
|
||||
Inspects the supplied file and determines the media included.
|
||||
*/
|
||||
Media GetMedia(const char *file_name);
|
||||
|
||||
}
|
||||
|
||||
#endif /* StaticAnalyser_hpp */
|
||||
|
@ -27,15 +27,10 @@ static std::vector<Storage::Data::ZX8081::File> GetFiles(const std::shared_ptr<S
|
||||
return files;
|
||||
}
|
||||
|
||||
void StaticAnalyser::ZX8081::AddTargets(
|
||||
const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
|
||||
const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
|
||||
const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
|
||||
std::list<StaticAnalyser::Target> &destination) {
|
||||
|
||||
if(!tapes.empty()) {
|
||||
std::vector<Storage::Data::ZX8081::File> files = GetFiles(tapes.front());
|
||||
tapes.front()->reset();
|
||||
void StaticAnalyser::ZX8081::AddTargets(const Media &media, std::list<Target> &destination) {
|
||||
if(!media.tapes.empty()) {
|
||||
std::vector<Storage::Data::ZX8081::File> files = GetFiles(media.tapes.front());
|
||||
media.tapes.front()->reset();
|
||||
if(!files.empty()) {
|
||||
StaticAnalyser::Target target;
|
||||
target.machine = Target::ZX8081;
|
||||
@ -47,7 +42,7 @@ void StaticAnalyser::ZX8081::AddTargets(
|
||||
} else {
|
||||
target.zx8081.memory_model = ZX8081MemoryModel::Unexpanded;
|
||||
}
|
||||
target.tapes = tapes;
|
||||
target.media.tapes = media.tapes;
|
||||
|
||||
// TODO: how to run software once loaded? Might require a BASIC detokeniser.
|
||||
if(target.zx8081.isZX81) {
|
||||
|
@ -14,12 +14,7 @@
|
||||
namespace StaticAnalyser {
|
||||
namespace ZX8081 {
|
||||
|
||||
void AddTargets(
|
||||
const std::list<std::shared_ptr<Storage::Disk::Disk>> &disks,
|
||||
const std::list<std::shared_ptr<Storage::Tape::Tape>> &tapes,
|
||||
const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges,
|
||||
std::list<Target> &destination
|
||||
);
|
||||
void AddTargets(const Media &media, std::list<Target> &destination);
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user