2016-09-06 10:39:40 +00:00
|
|
|
//
|
|
|
|
// CommodoreAnalyser.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 06/09/2016.
|
|
|
|
// Copyright © 2016 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
2016-09-15 23:24:59 +00:00
|
|
|
#include "StaticAnalyser.hpp"
|
2016-09-06 10:39:40 +00:00
|
|
|
|
2016-09-13 11:26:51 +00:00
|
|
|
#include "File.hpp"
|
2016-09-06 10:39:40 +00:00
|
|
|
#include "Tape.hpp"
|
2016-09-13 11:26:51 +00:00
|
|
|
#include "Disk.hpp"
|
2016-09-29 23:39:13 +00:00
|
|
|
#include "../../Storage/Cartridge/Encodings/CommodoreROM.hpp"
|
2016-09-06 10:39:40 +00:00
|
|
|
|
2017-05-06 23:55:42 +00:00
|
|
|
#include <sstream>
|
|
|
|
|
2016-09-06 10:39:40 +00:00
|
|
|
using namespace StaticAnalyser::Commodore;
|
|
|
|
|
2016-09-29 23:39:13 +00:00
|
|
|
static std::list<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
2017-03-26 18:34:47 +00:00
|
|
|
Vic20CartridgesFrom(const std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
|
2016-09-29 23:39:13 +00:00
|
|
|
std::list<std::shared_ptr<Storage::Cartridge::Cartridge>> vic20_cartridges;
|
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
for(std::shared_ptr<Storage::Cartridge::Cartridge> cartridge : cartridges) {
|
2016-09-29 23:39:13 +00:00
|
|
|
const std::list<Storage::Cartridge::Cartridge::Segment> &segments = cartridge->get_segments();
|
|
|
|
|
|
|
|
// only one mapped item is allowed
|
|
|
|
if(segments.size() != 1) continue;
|
|
|
|
|
|
|
|
// which must be 16 kb in size
|
|
|
|
Storage::Cartridge::Cartridge::Segment segment = segments.front();
|
|
|
|
if(segment.start_address != 0xa000) continue;
|
|
|
|
if(!Storage::Cartridge::Encodings::CommodoreROM::isROM(segment.data)) continue;
|
|
|
|
|
|
|
|
vic20_cartridges.push_back(cartridge);
|
|
|
|
}
|
|
|
|
|
|
|
|
return vic20_cartridges;
|
|
|
|
}
|
|
|
|
|
2016-09-06 10:39:40 +00:00
|
|
|
void StaticAnalyser::Commodore::AddTargets(
|
2017-03-26 18:34:47 +00:00
|
|
|
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) {
|
2016-09-06 10:39:40 +00:00
|
|
|
Target target;
|
|
|
|
target.machine = Target::Vic20; // TODO: machine estimation
|
|
|
|
target.probability = 1.0; // TODO: a proper estimation
|
|
|
|
|
2016-09-13 11:26:51 +00:00
|
|
|
int device = 0;
|
|
|
|
std::list<File> files;
|
2016-09-15 23:21:09 +00:00
|
|
|
bool is_disk = false;
|
2016-09-13 11:26:51 +00:00
|
|
|
|
2016-09-06 10:39:40 +00:00
|
|
|
// strip out inappropriate cartridges
|
2016-09-29 23:39:13 +00:00
|
|
|
target.cartridges = Vic20CartridgesFrom(cartridges);
|
2016-09-06 10:39:40 +00:00
|
|
|
|
2016-09-13 11:26:51 +00:00
|
|
|
// check disks
|
2017-03-26 18:34:47 +00:00
|
|
|
for(auto &disk : disks) {
|
2016-09-13 11:26:51 +00:00
|
|
|
std::list<File> disk_files = GetFiles(disk);
|
2017-03-26 18:34:47 +00:00
|
|
|
if(disk_files.size()) {
|
2016-09-15 23:21:09 +00:00
|
|
|
is_disk = true;
|
2016-09-13 11:26:51 +00:00
|
|
|
files.splice(files.end(), disk_files);
|
|
|
|
target.disks = disks;
|
|
|
|
if(!device) device = 8;
|
|
|
|
}
|
|
|
|
}
|
2016-09-07 11:39:47 +00:00
|
|
|
|
2016-09-13 11:26:51 +00:00
|
|
|
// check tapes
|
2017-03-26 18:34:47 +00:00
|
|
|
for(auto &tape : tapes) {
|
2016-09-13 11:26:51 +00:00
|
|
|
std::list<File> tape_files = GetFiles(tape);
|
2017-03-26 18:34:47 +00:00
|
|
|
if(tape_files.size()) {
|
2016-09-13 11:26:51 +00:00
|
|
|
files.splice(files.end(), tape_files);
|
2016-09-11 21:09:00 +00:00
|
|
|
target.tapes = tapes;
|
2016-09-13 11:26:51 +00:00
|
|
|
if(!device) device = 1;
|
|
|
|
}
|
|
|
|
}
|
2016-09-08 02:17:19 +00:00
|
|
|
|
2017-03-26 18:34:47 +00:00
|
|
|
if(files.size()) {
|
2016-09-13 11:26:51 +00:00
|
|
|
target.vic20.memory_model = Vic20MemoryModel::Unexpanded;
|
2017-05-06 23:55:42 +00:00
|
|
|
std::ostringstream string_stream;
|
|
|
|
string_stream << "LOAD\"" << (is_disk ? "*" : "") << "\"," << device << ",";
|
|
|
|
if(files.front().is_basic()) {
|
|
|
|
string_stream << "0";
|
2017-03-26 18:34:47 +00:00
|
|
|
} else {
|
2017-05-06 23:55:42 +00:00
|
|
|
string_stream << "1";
|
2016-09-13 11:26:51 +00:00
|
|
|
}
|
2017-05-06 23:55:42 +00:00
|
|
|
string_stream << "\nRUN\n";
|
|
|
|
target.loadingCommand = string_stream.str();
|
2016-09-13 11:26:51 +00:00
|
|
|
|
|
|
|
// make a first guess based on loading address
|
2017-03-26 18:34:47 +00:00
|
|
|
switch(files.front().starting_address) {
|
2016-09-13 11:26:51 +00:00
|
|
|
case 0x1001:
|
|
|
|
default: break;
|
|
|
|
case 0x1201:
|
|
|
|
target.vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB;
|
|
|
|
break;
|
|
|
|
case 0x0401:
|
|
|
|
target.vic20.memory_model = Vic20MemoryModel::EightKB;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// General approach: increase memory size conservatively such that the largest file found will fit.
|
2017-03-26 18:34:47 +00:00
|
|
|
for(File &file : files) {
|
2016-09-13 11:26:51 +00:00
|
|
|
size_t file_size = file.data.size();
|
|
|
|
// bool is_basic = file.is_basic();
|
2016-09-09 01:09:37 +00:00
|
|
|
|
2016-09-13 11:26:51 +00:00
|
|
|
/*if(is_basic)
|
2016-09-13 02:06:03 +00:00
|
|
|
{
|
2016-09-13 11:26:51 +00:00
|
|
|
// BASIC files may be relocated, so the only limit is size.
|
|
|
|
//
|
|
|
|
// An unexpanded machine has 3583 bytes free for BASIC;
|
|
|
|
// a 3kb expanded machine has 6655 bytes free.
|
|
|
|
if(file_size > 6655)
|
2016-09-13 02:06:03 +00:00
|
|
|
target.vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB;
|
2016-09-13 11:26:51 +00:00
|
|
|
else if(target.vic20.memory_model == Vic20MemoryModel::Unexpanded && file_size > 3583)
|
2016-09-13 02:06:03 +00:00
|
|
|
target.vic20.memory_model = Vic20MemoryModel::EightKB;
|
|
|
|
}
|
2016-09-13 11:26:51 +00:00
|
|
|
else
|
|
|
|
{*/
|
|
|
|
// if(!file.type == File::NonRelocatableProgram)
|
|
|
|
// {
|
|
|
|
// Non-BASIC files may be relocatable but, if so, by what logic?
|
|
|
|
// Given that this is unknown, take starting address as literal
|
|
|
|
// and check against memory windows.
|
|
|
|
//
|
|
|
|
// (ignoring colour memory...)
|
|
|
|
// An unexpanded Vic has memory between 0x0000 and 0x0400; and between 0x1000 and 0x2000.
|
|
|
|
// A 3kb expanded Vic fills in the gap and has memory between 0x0000 and 0x2000.
|
|
|
|
// A 32kb expanded Vic has memory in the entire low 32kb.
|
|
|
|
uint16_t starting_address = file.starting_address;
|
2016-09-09 01:09:37 +00:00
|
|
|
|
2016-09-13 11:26:51 +00:00
|
|
|
// If anything above the 8kb mark is touched, mark as a 32kb machine; otherwise if the
|
|
|
|
// region 0x0400 to 0x1000 is touched and this is an unexpanded machine, mark as 3kb.
|
|
|
|
if(starting_address + file_size > 0x2000)
|
|
|
|
target.vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB;
|
|
|
|
else if(target.vic20.memory_model == Vic20MemoryModel::Unexpanded && !(starting_address >= 0x1000 || starting_address+file_size < 0x0400))
|
|
|
|
target.vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB;
|
|
|
|
// }
|
2016-09-07 11:39:47 +00:00
|
|
|
}
|
2016-09-06 10:39:40 +00:00
|
|
|
}
|
2016-09-07 11:39:47 +00:00
|
|
|
|
|
|
|
if(target.tapes.size() || target.cartridges.size() || target.disks.size())
|
|
|
|
destination.push_back(target);
|
2016-09-08 02:17:19 +00:00
|
|
|
}
|