mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Merge pull request #706 from TomHarte/Vic20Flags
Permits Vic-20 memory to be specified in banks;
This commit is contained in:
commit
ec9357e080
@ -16,6 +16,7 @@
|
|||||||
#include "../../../Outputs/Log.hpp"
|
#include "../../../Outputs/Log.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
using namespace Analyser::Static::Commodore;
|
using namespace Analyser::Static::Commodore;
|
||||||
@ -78,7 +79,7 @@ Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(const Media
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!files.empty()) {
|
if(!files.empty()) {
|
||||||
target->memory_model = Target::MemoryModel::Unexpanded;
|
auto memory_model = Target::MemoryModel::Unexpanded;
|
||||||
std::ostringstream string_stream;
|
std::ostringstream string_stream;
|
||||||
string_stream << "LOAD\"" << (is_disk ? "*" : "") << "\"," << device << ",";
|
string_stream << "LOAD\"" << (is_disk ? "*" : "") << "\"," << device << ",";
|
||||||
if(files.front().is_basic()) {
|
if(files.front().is_basic()) {
|
||||||
@ -94,16 +95,18 @@ Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(const Media
|
|||||||
default:
|
default:
|
||||||
LOG("Unrecognised loading address for Commodore program: " << PADHEX(4) << files.front().starting_address);
|
LOG("Unrecognised loading address for Commodore program: " << PADHEX(4) << files.front().starting_address);
|
||||||
case 0x1001:
|
case 0x1001:
|
||||||
target->memory_model = Target::MemoryModel::Unexpanded;
|
memory_model = Target::MemoryModel::Unexpanded;
|
||||||
break;
|
break;
|
||||||
case 0x1201:
|
case 0x1201:
|
||||||
target->memory_model = Target::MemoryModel::ThirtyTwoKB;
|
memory_model = Target::MemoryModel::ThirtyTwoKB;
|
||||||
break;
|
break;
|
||||||
case 0x0401:
|
case 0x0401:
|
||||||
target->memory_model = Target::MemoryModel::EightKB;
|
memory_model = Target::MemoryModel::EightKB;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
target->set_memory_model(memory_model);
|
||||||
|
|
||||||
// General approach: increase memory size conservatively such that the largest file found will fit.
|
// General approach: increase memory size conservatively such that the largest file found will fit.
|
||||||
// for(File &file : files) {
|
// for(File &file : files) {
|
||||||
// std::size_t file_size = file.data.size();
|
// std::size_t file_size = file.data.size();
|
||||||
@ -145,13 +148,52 @@ Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(const Media
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!target->media.empty()) {
|
if(!target->media.empty()) {
|
||||||
// Inspect filename for a region hint.
|
// Inspect filename for configuration hints.
|
||||||
std::string lowercase_name = file_name;
|
std::string lowercase_name = file_name;
|
||||||
std::transform(lowercase_name.begin(), lowercase_name.end(), lowercase_name.begin(), ::tolower);
|
std::transform(lowercase_name.begin(), lowercase_name.end(), lowercase_name.begin(), ::tolower);
|
||||||
|
|
||||||
|
// Hint 1: 'ntsc' anywhere in the name implies America.
|
||||||
if(lowercase_name.find("ntsc") != std::string::npos) {
|
if(lowercase_name.find("ntsc") != std::string::npos) {
|
||||||
target->region = Analyser::Static::Commodore::Target::Region::American;
|
target->region = Analyser::Static::Commodore::Target::Region::American;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Potential additional hints: check for TheC64 tags.
|
||||||
|
auto final_underscore = lowercase_name.find_last_of('_');
|
||||||
|
if(final_underscore != std::string::npos) {
|
||||||
|
auto iterator = lowercase_name.begin() + ssize_t(final_underscore) + 1;
|
||||||
|
|
||||||
|
while(iterator != lowercase_name.end()) {
|
||||||
|
// Grab the next tag.
|
||||||
|
char next_tag[3] = {0, 0, 0};
|
||||||
|
next_tag[0] = *iterator++;
|
||||||
|
if(iterator == lowercase_name.end()) break;
|
||||||
|
next_tag[1] = *iterator++;
|
||||||
|
|
||||||
|
// Exit early if attempting to read another tag has run over the file extension.
|
||||||
|
if(next_tag[0] == '.' || next_tag[1] == '.') break;
|
||||||
|
|
||||||
|
// Check whether it's anything.
|
||||||
|
target->enabled_ram.bank0 |= !strcmp(next_tag, "b0");
|
||||||
|
target->enabled_ram.bank1 |= !strcmp(next_tag, "b1");
|
||||||
|
target->enabled_ram.bank2 |= !strcmp(next_tag, "b2");
|
||||||
|
target->enabled_ram.bank3 |= !strcmp(next_tag, "b3");
|
||||||
|
target->enabled_ram.bank5 |= !strcmp(next_tag, "b5");
|
||||||
|
if(!strcmp(next_tag, "tn")) { // i.e. NTSC.
|
||||||
|
target->region = Analyser::Static::Commodore::Target::Region::American;
|
||||||
|
}
|
||||||
|
if(!strcmp(next_tag, "tp")) { // i.e. PAL.
|
||||||
|
target->region = Analyser::Static::Commodore::Target::Region::European;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unhandled:
|
||||||
|
//
|
||||||
|
// M6: this is a C64 file.
|
||||||
|
// MV: this is a Vic-20 file.
|
||||||
|
// J1/J2: this C64 file should have the primary joystick in slot 1/2.
|
||||||
|
// RO: this disk image should be treated as read-only.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Attach a 1540 if there are any disks here.
|
// Attach a 1540 if there are any disks here.
|
||||||
target->has_c1540 = !target->media.disks.empty();
|
target->has_c1540 = !target->media.disks.empty();
|
||||||
|
|
||||||
|
@ -31,7 +31,26 @@ struct Target: public ::Analyser::Static::Target {
|
|||||||
Swedish
|
Swedish
|
||||||
};
|
};
|
||||||
|
|
||||||
MemoryModel memory_model = MemoryModel::Unexpanded;
|
/// Maps from a named memory model to a bank enabled/disabled set.
|
||||||
|
void set_memory_model(MemoryModel memory_model) {
|
||||||
|
// This is correct for unexpanded and 32kb memory models.
|
||||||
|
enabled_ram.bank0 = enabled_ram.bank1 =
|
||||||
|
enabled_ram.bank2 = enabled_ram.bank3 =
|
||||||
|
enabled_ram.bank5 = memory_model == MemoryModel::ThirtyTwoKB;
|
||||||
|
|
||||||
|
// Bank 0 will need to be enabled if this is an 8kb machine.
|
||||||
|
enabled_ram.bank0 |= memory_model == MemoryModel::EightKB;
|
||||||
|
}
|
||||||
|
struct {
|
||||||
|
bool bank0 = false;
|
||||||
|
bool bank1 = false;
|
||||||
|
bool bank2 = false;
|
||||||
|
bool bank3 = false;
|
||||||
|
bool bank5 = false;
|
||||||
|
// Sic. There is no bank 4; this is because the area that logically would be
|
||||||
|
// bank 4 is occupied by the character ROM, colour RAM, hardware registers, etc.
|
||||||
|
} enabled_ram;
|
||||||
|
|
||||||
Region region = Region::European;
|
Region region = Region::European;
|
||||||
bool has_c1540 = false;
|
bool has_c1540 = false;
|
||||||
std::string loading_command;
|
std::string loading_command;
|
||||||
|
@ -320,7 +320,7 @@ class ConcreteMachine:
|
|||||||
tape_->set_delegate(this);
|
tape_->set_delegate(this);
|
||||||
tape_->set_clocking_hint_observer(this);
|
tape_->set_clocking_hint_observer(this);
|
||||||
|
|
||||||
// install a joystick
|
// Install a joystick.
|
||||||
joysticks_.emplace_back(new Joystick(*user_port_via_port_handler_, *keyboard_via_port_handler_));
|
joysticks_.emplace_back(new Joystick(*user_port_via_port_handler_, *keyboard_via_port_handler_));
|
||||||
|
|
||||||
const std::string machine_name = "Vic20";
|
const std::string machine_name = "Vic20";
|
||||||
@ -401,22 +401,14 @@ class ConcreteMachine:
|
|||||||
write_to_map(processor_read_memory_map_, &ram_[baseaddr], baseaddr, length); \
|
write_to_map(processor_read_memory_map_, &ram_[baseaddr], baseaddr, length); \
|
||||||
write_to_map(processor_write_memory_map_, &ram_[baseaddr], baseaddr, length);
|
write_to_map(processor_write_memory_map_, &ram_[baseaddr], baseaddr, length);
|
||||||
|
|
||||||
// Add 6502-visible RAM as requested
|
// Add 6502-visible RAM as requested.
|
||||||
switch(target.memory_model) {
|
set_ram(0x0000, 0x0400);
|
||||||
case Analyser::Static::Commodore::Target::MemoryModel::Unexpanded:
|
set_ram(0x1000, 0x1000); // Built-in RAM.
|
||||||
// The default Vic-20 memory map has 1kb at address 0 and another 4kb at address 0x1000.
|
if(target.enabled_ram.bank0) set_ram(0x0400, 0x0c00); // Bank 0: 0x0400 -> 0x1000.
|
||||||
set_ram(0x0000, 0x0400);
|
if(target.enabled_ram.bank1) set_ram(0x2000, 0x2000); // Bank 1: 0x2000 -> 0x4000.
|
||||||
set_ram(0x1000, 0x1000);
|
if(target.enabled_ram.bank2) set_ram(0x4000, 0x2000); // Bank 2: 0x4000 -> 0x6000.
|
||||||
break;
|
if(target.enabled_ram.bank3) set_ram(0x6000, 0x2000); // Bank 3: 0x6000 -> 0x8000.
|
||||||
case Analyser::Static::Commodore::Target::MemoryModel::EightKB:
|
if(target.enabled_ram.bank5) set_ram(0xa000, 0x2000); // Bank 5: 0xa000 -> 0xc000.
|
||||||
// An 8kb Vic-20 fills in the gap between the two blocks of RAM on an unexpanded machine.
|
|
||||||
set_ram(0x0000, 0x2000);
|
|
||||||
break;
|
|
||||||
case Analyser::Static::Commodore::Target::MemoryModel::ThirtyTwoKB:
|
|
||||||
// A 32kb Vic-20 fills the entire lower 32kb with RAM.
|
|
||||||
set_ram(0x0000, 0x8000);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef set_ram
|
#undef set_ram
|
||||||
|
|
||||||
@ -453,6 +445,8 @@ class ConcreteMachine:
|
|||||||
write_to_map(mos6560_bus_handler_.video_memory_map, character_rom_.data(), 0x0000, static_cast<uint16_t>(character_rom_.size()));
|
write_to_map(mos6560_bus_handler_.video_memory_map, character_rom_.data(), 0x0000, static_cast<uint16_t>(character_rom_.size()));
|
||||||
write_to_map(processor_read_memory_map_, kernel_rom_.data(), 0xe000, static_cast<uint16_t>(kernel_rom_.size()));
|
write_to_map(processor_read_memory_map_, kernel_rom_.data(), 0xe000, static_cast<uint16_t>(kernel_rom_.size()));
|
||||||
|
|
||||||
|
// The insert_media occurs last, so if there's a conflict between cartridges and RAM,
|
||||||
|
// the cartridge wins.
|
||||||
insert_media(target.media);
|
insert_media(target.media);
|
||||||
if(!target.loading_command.empty()) {
|
if(!target.loading_command.empty()) {
|
||||||
type_string(target.loading_command);
|
type_string(target.loading_command);
|
||||||
@ -711,7 +705,7 @@ class ConcreteMachine:
|
|||||||
|
|
||||||
std::vector<uint8_t> rom_;
|
std::vector<uint8_t> rom_;
|
||||||
uint16_t rom_address_, rom_length_;
|
uint16_t rom_address_, rom_length_;
|
||||||
uint8_t ram_[0x8000];
|
uint8_t ram_[0x10000];
|
||||||
uint8_t colour_ram_[0x0400];
|
uint8_t colour_ram_[0x0400];
|
||||||
|
|
||||||
uint8_t *processor_read_memory_map_[64];
|
uint8_t *processor_read_memory_map_[64];
|
||||||
|
@ -121,11 +121,13 @@
|
|||||||
case CSMachineVic20RegionEuropean: target->region = Target::Region::European; break;
|
case CSMachineVic20RegionEuropean: target->region = Target::Region::European; break;
|
||||||
case CSMachineVic20RegionJapanese: target->region = Target::Region::Japanese; break;
|
case CSMachineVic20RegionJapanese: target->region = Target::Region::Japanese; break;
|
||||||
}
|
}
|
||||||
|
auto memory_model = Target::MemoryModel::Unexpanded;
|
||||||
switch(memorySize) {
|
switch(memorySize) {
|
||||||
default: target->memory_model = Target::MemoryModel::Unexpanded; break;
|
default: break;
|
||||||
case 8: target->memory_model = Target::MemoryModel::EightKB; break;
|
case 8: memory_model = Target::MemoryModel::EightKB; break;
|
||||||
case 32: target->memory_model = Target::MemoryModel::ThirtyTwoKB; break;
|
case 32: memory_model = Target::MemoryModel::ThirtyTwoKB; break;
|
||||||
}
|
}
|
||||||
|
target->set_memory_model(memory_model);
|
||||||
target->has_c1540 = !!hasC1540;
|
target->has_c1540 = !!hasC1540;
|
||||||
_targets.push_back(std::move(target));
|
_targets.push_back(std::move(target));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user