refactor: split commands out of config, clean up some parsing, add media concept to card abstraction
This commit is contained in:
parent
b138df21eb
commit
46582c6566
|
@ -77,6 +77,7 @@ diskcontroller.cpp
|
|||
drive.cpp
|
||||
drivemotor.cpp
|
||||
e2config.cpp
|
||||
e2command.cpp
|
||||
e2filesystem.cpp
|
||||
e2string.cpp
|
||||
E2wxApp.cpp
|
||||
|
|
99
src/card.cpp
99
src/card.cpp
|
@ -14,96 +14,89 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
*/
|
||||
#include "card.h"
|
||||
#include "e2config.h"
|
||||
|
||||
Card::Card():
|
||||
rom(0x0100),
|
||||
seventhRom(0x0800)
|
||||
{
|
||||
|
||||
|
||||
Card::Card() : rom(0x0100), seventhRom(0x0800) {
|
||||
}
|
||||
|
||||
Card::~Card() {
|
||||
}
|
||||
|
||||
|
||||
Card::~Card()
|
||||
{
|
||||
|
||||
std::string Card::getName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
void Card::reset()
|
||||
{
|
||||
|
||||
void Card::tick() {
|
||||
}
|
||||
|
||||
void Card::tick()
|
||||
{
|
||||
void Card::reset() {
|
||||
}
|
||||
|
||||
|
||||
unsigned char Card::io(const unsigned short /*address*/, const unsigned char data, const bool /*writing*/)
|
||||
{
|
||||
unsigned char Card::io(const unsigned short address, const unsigned char data, const bool writing) {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned char Card::readRom(const unsigned short address, const unsigned char data)
|
||||
{
|
||||
unsigned char Card::readRom(const unsigned short address, const unsigned char data) {
|
||||
this->activeSeventhRom = true;
|
||||
return this->rom.read(address, data);
|
||||
}
|
||||
|
||||
void Card::readSeventhRom(const unsigned short address, unsigned char* const pb)
|
||||
{
|
||||
if (address == 0x7FF)
|
||||
{
|
||||
|
||||
|
||||
bool Card::hasSeventhRom() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Card::readSeventhRom(const unsigned short address, unsigned char* const pb) {
|
||||
if (address == 0x7FF) {
|
||||
this->activeSeventhRom = false;
|
||||
}
|
||||
else if (this->activeSeventhRom && hasSeventhRom())
|
||||
{
|
||||
} else if (this->activeSeventhRom && hasSeventhRom()) {
|
||||
*pb = this->seventhRom.read(address, *pb);
|
||||
}
|
||||
}
|
||||
|
||||
void Card::loadRom(const unsigned short base, std::istream& in)
|
||||
{
|
||||
this->rom.load(base,in);
|
||||
void Card::loadRom(const unsigned short base, std::istream& in) {
|
||||
this->rom.load(base, in);
|
||||
}
|
||||
|
||||
void Card::loadSeventhRom(const unsigned short base, std::istream& in)
|
||||
{
|
||||
this->seventhRom.load(base,in);
|
||||
void Card::loadSeventhRom(const unsigned short base, std::istream& in) {
|
||||
this->seventhRom.load(base, in);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Card::inhibitMotherboardRom()
|
||||
{
|
||||
bool Card::inhibitMotherboardRom() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Card::ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write) {
|
||||
}
|
||||
|
||||
|
||||
void Card::ioBankRom(const unsigned short /*addr*/, unsigned char* const /*pb*/, const bool /*write*/)
|
||||
{
|
||||
void Card::loadBankRom(const unsigned short base, std::istream& in) {
|
||||
// TODO? maybe just do nothing
|
||||
// throw ConfigException("This card has no $D000 ROM");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Card::loadBankRom(const unsigned short /*base*/, std::istream& /*in*/)
|
||||
{
|
||||
throw ConfigException("This card has no $D000 ROM");
|
||||
}
|
||||
|
||||
std::string Card::getName()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
bool Card::isDirty()
|
||||
{
|
||||
bool Card::isMediaDirty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Card::save(int unit)
|
||||
{
|
||||
bool Card::hasMedia() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Card::loadMedia(int unit, const std::filesystem::path &media) {
|
||||
}
|
||||
|
||||
void Card::unloadMedia(int unit) {
|
||||
}
|
||||
|
||||
void Card::saveMedia(int unit) {
|
||||
}
|
||||
|
|
27
src/card.h
27
src/card.h
|
@ -14,19 +14,19 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
*/
|
||||
#ifndef CARD_H
|
||||
#define CARD_H
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <istream>
|
||||
#include <string>
|
||||
|
||||
class Card
|
||||
{
|
||||
private:
|
||||
class Card {
|
||||
bool activeSeventhRom;
|
||||
|
||||
protected:
|
||||
Memory rom;
|
||||
Memory seventhRom;
|
||||
|
@ -34,20 +34,27 @@ protected:
|
|||
public:
|
||||
Card();
|
||||
virtual ~Card();
|
||||
virtual void tick();
|
||||
virtual void reset();
|
||||
|
||||
virtual std::string getName();
|
||||
|
||||
virtual void tick();
|
||||
virtual void reset();
|
||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
||||
virtual unsigned char readRom(const unsigned short address, const unsigned char data);
|
||||
virtual bool hasSeventhRom() { return false; }
|
||||
|
||||
virtual bool hasSeventhRom();
|
||||
virtual void readSeventhRom(const unsigned short address, unsigned char* const pb);
|
||||
virtual void loadRom(const unsigned short base, std::istream& in);
|
||||
virtual void loadSeventhRom(const unsigned short base, std::istream& in);
|
||||
virtual bool inhibitMotherboardRom();
|
||||
virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write);
|
||||
virtual void loadBankRom(const unsigned short base, std::istream& in);
|
||||
virtual bool isDirty();
|
||||
virtual void save(int unit);
|
||||
virtual std::string getName();
|
||||
virtual bool isMediaDirty();
|
||||
|
||||
virtual bool hasMedia();
|
||||
virtual void loadMedia(int unit, const std::filesystem::path &media);
|
||||
virtual void unloadMedia(int unit);
|
||||
virtual void saveMedia(int unit);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "wozfile.h"
|
||||
#include "lss.h"
|
||||
#include "screenimage.h"
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
|
@ -94,21 +95,25 @@ public:
|
|||
this->gui.setCurrentDrive(this->slot,getCurrentDriveNumber(),getTrack(),false);
|
||||
}
|
||||
|
||||
void loadDisk(unsigned char drive, const std::string& fnib) {
|
||||
if (!this->getDrive(drive).loadDisk(fnib)) {
|
||||
virtual bool hasMedia() override {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void loadMedia(int unit, const std::filesystem::path &media) override {
|
||||
if (!this->getDrive(unit).loadDisk(media)) {
|
||||
return;
|
||||
}
|
||||
this->gui.setDiskFile(this->slot,drive,fnib);
|
||||
this->gui.setDiskFile(this->slot,unit,media);
|
||||
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
|
||||
}
|
||||
|
||||
void unloadDisk(unsigned char drive) {
|
||||
this->getDrive(drive).unloadDisk();
|
||||
this->gui.setDiskFile(this->slot,drive,"");
|
||||
virtual void unloadMedia(int unit) override {
|
||||
this->getDrive(unit).unloadDisk();
|
||||
this->gui.setDiskFile(this->slot,unit,std::filesystem::path{});
|
||||
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
|
||||
}
|
||||
|
||||
void save(int drive) {
|
||||
virtual void saveMedia(int drive) override {
|
||||
this->getDrive(drive).saveDisk();
|
||||
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
|
||||
}
|
||||
|
@ -137,7 +142,7 @@ public:
|
|||
return this->currentDrive->isWriteProtected();
|
||||
}
|
||||
|
||||
bool isDirty() {
|
||||
bool isMediaDirty() {
|
||||
return isModified() || isModifiedOther();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,406 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY, without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: e2command.cpp
|
||||
* Author: user
|
||||
*
|
||||
* Created on December 11, 2022, 8:21 PM
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "e2command.h"
|
||||
#include "E2wxApp.h"
|
||||
#include "apple2.h"
|
||||
#include "memoryrandomaccess.h"
|
||||
#include "memorychip.h"
|
||||
#include "cassette.h"
|
||||
#include "cassettein.h"
|
||||
#include "cassetteout.h"
|
||||
#include "card.h"
|
||||
#include "slots.h"
|
||||
#include "diskcontroller.h"
|
||||
#include "languagecard.h"
|
||||
#include "firmwarecard.h"
|
||||
#include "standardout.h"
|
||||
#include "standardin.h"
|
||||
#include "clockcard.h"
|
||||
#include "screenimage.h"
|
||||
|
||||
#include <wx/filedlg.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
#define K 1024u
|
||||
|
||||
static std::uint16_t memory_block_size(const std::string &block_size) {
|
||||
if (block_size == "4K") {
|
||||
return 4u*K;
|
||||
}
|
||||
if (block_size == "16K") {
|
||||
return 16u*K;
|
||||
}
|
||||
throw ConfigException("invalid RAM strapping block size (must be 4K or 16K)");
|
||||
}
|
||||
|
||||
static void trim(std::string& s) {
|
||||
wxString w{s};
|
||||
s = w.Trim(false).Trim(true);
|
||||
}
|
||||
|
||||
static std::string filter_row(const std::string &row) {
|
||||
if (row.length() != 1) {
|
||||
return "";
|
||||
}
|
||||
return std::string(1, static_cast<char> (std::toupper(row[0])));
|
||||
}
|
||||
|
||||
|
||||
|
||||
E2Command::E2Command() {
|
||||
}
|
||||
|
||||
E2Command::~E2Command() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
void E2Command::parseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2) {
|
||||
try {
|
||||
tryParseLine(line, ram, rom, slts, revision, gui, cassetteIn, cassetteOut, apple2);
|
||||
} catch (const ConfigException& err) {
|
||||
// TODO fix error handling
|
||||
std::cerr << err.msg.c_str() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void E2Command::tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2) {
|
||||
std::istringstream tok(line);
|
||||
|
||||
std::string cmd;
|
||||
tok >> cmd;
|
||||
if (cmd == "slot") {
|
||||
int slot;
|
||||
std::string sCardType;
|
||||
tok >> slot >> sCardType;
|
||||
|
||||
double random_ones_rate(0.3); // WOZ spec v2.0: 30%
|
||||
if (sCardType=="disk" || sCardType=="disk13") {
|
||||
tok >> random_ones_rate;
|
||||
}
|
||||
|
||||
insertCard(sCardType, slot, slts, gui, random_ones_rate);
|
||||
} else if (cmd == "motherboard") {
|
||||
std::string op;
|
||||
tok >> op;
|
||||
if (op == "ram") {
|
||||
/* ram ROW BIT0 [BIT1 [... [BIT7]]]
|
||||
* ram e -
|
||||
* ram d 4096 MK4096 4K
|
||||
* ram c 16K 4116 MK4116 MM5290 16K 16K 16K 16K
|
||||
*/
|
||||
std::string row;
|
||||
tok >> row;
|
||||
row = filter_row(row);
|
||||
if (row != "C" && row != "D" && row != "E") {
|
||||
throw ConfigException("expected row to be C, D, or E");
|
||||
}
|
||||
|
||||
std::string chip_model;
|
||||
tok >> chip_model;
|
||||
for (std::uint_fast8_t bit = 0u; bit < 8u; ++bit) {
|
||||
ram.insert_chip(row, MemoryChip::instance(chip_model), bit);
|
||||
|
||||
std::string chip_model_optional;
|
||||
tok >> chip_model_optional;
|
||||
if (chip_model_optional.length()) {
|
||||
chip_model = chip_model_optional;
|
||||
}
|
||||
}
|
||||
} else if (op == "strap") {
|
||||
/* strap ROM K start-addr
|
||||
* strap e 4K 5000
|
||||
* strap d 4K 4000
|
||||
* strap c 16K 0000
|
||||
*/
|
||||
std::string row;
|
||||
tok >> row;
|
||||
row = filter_row(row);
|
||||
if (row != "C" && row != "D" && row != "E") {
|
||||
throw ConfigException("expected row to be C, D, or E");
|
||||
}
|
||||
|
||||
std::string block_size;
|
||||
tok >> block_size;
|
||||
std::uint16_t siz = memory_block_size(block_size);
|
||||
unsigned short base(0);
|
||||
tok >> std::hex >> base;
|
||||
// TODO validate siz/base combination
|
||||
ram.strap_to(row, base, siz);
|
||||
} else {
|
||||
throw ConfigException("error at \"motherboard\"; expected \"ram\" or \"strap\"");
|
||||
}
|
||||
} else if (cmd == "import") {
|
||||
std::string sm;
|
||||
tok >> sm;
|
||||
|
||||
int slot(-1);
|
||||
if (sm == "slot") {
|
||||
tok >> slot;
|
||||
} else if (sm != "motherboard") {
|
||||
throw ConfigException("error at \"" + sm + "\"; expected \"slot #\" or \"motherboard\"");
|
||||
}
|
||||
|
||||
std::string romtype;
|
||||
tok >> romtype;
|
||||
|
||||
unsigned short base(0);
|
||||
tok >> std::hex >> base;
|
||||
|
||||
std::string file;
|
||||
std::getline(tok, file);
|
||||
trim(file);
|
||||
std::ifstream *memfile = new std::ifstream(file.c_str(), std::ios::binary);
|
||||
if (!memfile->is_open()) {
|
||||
std::filesystem::path f = wxGetApp().GetResDir();
|
||||
f /= file;
|
||||
memfile = new std::ifstream(f, std::ios::binary);
|
||||
if (!memfile->is_open()) {
|
||||
throw ConfigException("cannot open file " + file);
|
||||
}
|
||||
}
|
||||
|
||||
if (slot < 0) // motherboard
|
||||
{
|
||||
if (romtype == "rom") {
|
||||
rom.load(base, *memfile);
|
||||
} else {
|
||||
throw ConfigException("error at \"" + romtype + "\"; expected rom or ram");
|
||||
}
|
||||
} else {
|
||||
if (8 <= slot) {
|
||||
throw ConfigException("invalid slot number");
|
||||
}
|
||||
Card* card = slts.get(slot);
|
||||
if (romtype == "rom")
|
||||
card->loadRom(base, *memfile);
|
||||
else if (romtype == "rom7")
|
||||
card->loadSeventhRom(base, *memfile);
|
||||
else if (romtype == "rombank")
|
||||
card->loadBankRom(base, *memfile);
|
||||
else
|
||||
throw ConfigException("error at \"" + romtype + "\"; expected rom, rom7, or rombank");
|
||||
}
|
||||
memfile->close();
|
||||
} else if (cmd == "load" || cmd == "save" || cmd == "unload") {
|
||||
std::string slotk;
|
||||
tok >> slotk;
|
||||
if (slotk != "slot") {
|
||||
throw ConfigException("error at \"" + slotk + "\"; expected \"slot\"");
|
||||
}
|
||||
|
||||
int slot(-1);
|
||||
tok >> slot;
|
||||
|
||||
std::string drivek;
|
||||
tok >> drivek;
|
||||
if (drivek != "drive") {
|
||||
throw ConfigException("error at \"" + drivek + "\"; expected \"drive\"");
|
||||
}
|
||||
|
||||
int drive(-1);
|
||||
tok >> drive;
|
||||
|
||||
if (cmd == "load") {
|
||||
std::string fn_optional;
|
||||
std::getline(tok, fn_optional);
|
||||
trim(fn_optional);
|
||||
if (fn_optional.length() == 0) {
|
||||
gui.exitFullScreen();
|
||||
wxFileDialog dlg{nullptr, "Load floppy", "", "", "WOZ 2.0 disk images (*.woz)|*.woz", wxFD_OPEN|wxFD_FILE_MUST_EXIST};
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
fn_optional = dlg.GetPath().c_str();
|
||||
}
|
||||
}
|
||||
if (fn_optional.length() > 0) {
|
||||
loadDisk(slts, slot, drive, fn_optional);
|
||||
}
|
||||
} else if (cmd == "unload") {
|
||||
unloadDisk(slts, slot, drive);
|
||||
} else if (cmd == "save") {
|
||||
saveDisk(slts, slot, drive);
|
||||
}
|
||||
} else if (cmd == "revision") {
|
||||
tok >> std::hex >> revision;
|
||||
} else if (cmd == "cassette") {
|
||||
std::string cas;
|
||||
tok >> cas;
|
||||
|
||||
if (cas == "rewind") {
|
||||
cassetteIn.rewind();
|
||||
} else if (cas == "tone") {
|
||||
cassetteIn.tone();
|
||||
} else if (cas == "blank") {
|
||||
std::string fcas;
|
||||
std::getline(tok, fcas);
|
||||
trim(fcas);
|
||||
if (!fcas.empty()) {
|
||||
cassetteOut.blank(fcas);
|
||||
}
|
||||
} else if (cas == "load") {
|
||||
std::string fn_optional;
|
||||
std::getline(tok, fn_optional);
|
||||
trim(fn_optional);
|
||||
if (fn_optional.length() == 0) {
|
||||
gui.exitFullScreen();
|
||||
wxFileDialog dlg{nullptr, "Load cassette (audio)", "", "", "WAVE cassette images (*.wav)|*.wav", wxFD_OPEN|wxFD_FILE_MUST_EXIST};
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
fn_optional = dlg.GetPath().c_str();
|
||||
}
|
||||
}
|
||||
if (fn_optional.length() > 0) {
|
||||
cassetteIn.load(fn_optional);
|
||||
}
|
||||
} else if (cas == "eject") {
|
||||
std::string eject;
|
||||
tok >> eject;
|
||||
if (eject == "in") {
|
||||
cassetteIn.eject();
|
||||
} else if (eject == "out") {
|
||||
cassetteOut.eject();
|
||||
} else {
|
||||
throw ConfigException("error: unknown cassette to eject: " + eject);
|
||||
}
|
||||
} else if (cas == "save") {
|
||||
cassetteOut.save();
|
||||
} else {
|
||||
throw ConfigException("error: unknown cassette command: " + cas);
|
||||
}
|
||||
} else if (cmd == "cpu") {
|
||||
std::string cpu;
|
||||
tok >> cpu;
|
||||
if (apple2 != NULL) {
|
||||
if (cpu == "epple2") {
|
||||
apple2->useEpple2Cpu();
|
||||
} else if (cpu == "visual6502") {
|
||||
apple2->useVisual6502Cpu();
|
||||
} else {
|
||||
throw ConfigException("invalid value for cpu command: " + cpu);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw ConfigException("Invalid command: " + cmd);
|
||||
}
|
||||
|
||||
if (apple2 != NULL) {
|
||||
apple2->useEpple2Cpu(); // set default CPU
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void E2Command::loadDisk(Slots& slts, int slot, int drive, const std::filesystem::path &media) {
|
||||
Card* card = slts.get(slot);
|
||||
if (!card->hasMedia()) {
|
||||
// TODO if file doesn't exist, name still gets displayed, and there's no error message
|
||||
// TODO error message
|
||||
// std::cerr << "Slot " << slot << " doesn't have a disk controller card" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (drive < 1 || 2 < drive) {
|
||||
throw ConfigException("Invalid drive; must be 1 or 2");
|
||||
}
|
||||
|
||||
card->loadMedia(drive - 1, media);
|
||||
}
|
||||
|
||||
void E2Command::unloadDisk(Slots& slts, int slot, int drive) {
|
||||
Card* card = slts.get(slot);
|
||||
if (!card->hasMedia()) {
|
||||
// TODO do we even need an error here?
|
||||
// std::cerr << "Slot " << slot << " doesn't have a disk controller card" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (drive < 1 || 2 < drive) {
|
||||
throw ConfigException("Invalid drive; must be 1 or 2");
|
||||
}
|
||||
|
||||
card->unloadMedia(drive - 1);
|
||||
}
|
||||
|
||||
void E2Command::saveDisk(Slots& slts, int slot, int drive) {
|
||||
Card* card = slts.get(slot);
|
||||
if (!card->hasMedia()) {
|
||||
// TODO do we even need an error here?
|
||||
// std::cerr << "Slot " << slot << " doesn't have a disk controller card" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (drive < 1 || 2 < drive) {
|
||||
throw ConfigException("Invalid drive; must be 1 or 2");
|
||||
}
|
||||
|
||||
card->saveMedia(drive - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void E2Command::insertCard(const std::string& cardType, const int slot, Slots& slts, ScreenImage& gui, const double random_ones_rate) {
|
||||
if (slot < 0 || 8 <= slot) {
|
||||
throw ConfigException("Invalid slot number");
|
||||
}
|
||||
|
||||
Card* card = nullptr;
|
||||
|
||||
if (cardType == "language") {
|
||||
card = new LanguageCard(gui, slot);
|
||||
} else if (cardType == "firmware") {
|
||||
card = new FirmwareCard(gui, slot);
|
||||
} else if (cardType == "disk") {
|
||||
card = new DiskController(gui, slot, false, random_ones_rate);
|
||||
} else if (cardType == "disk13") {
|
||||
card = new DiskController(gui, slot, true, random_ones_rate);
|
||||
} else if (cardType == "clock") {
|
||||
card = new ClockCard();
|
||||
} else if (cardType == "stdout") {
|
||||
card = new StandardOut();
|
||||
} else if (cardType == "stdin") {
|
||||
card = new StandardIn();
|
||||
} else if (cardType == "empty") {
|
||||
card = 0;
|
||||
} else {
|
||||
throw ConfigException("Invalid card type: " + cardType);
|
||||
}
|
||||
|
||||
if (card) {
|
||||
slts.set(slot, card);
|
||||
} else {
|
||||
slts.remove(slot);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Christopher A. Mosher <cmosher01@gmail.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY, without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File: e2command.h
|
||||
* Author: user
|
||||
*
|
||||
* Created on December 11, 2022, 8:21 PM
|
||||
*/
|
||||
|
||||
#ifndef E2COMMAND_H
|
||||
#define E2COMMAND_H
|
||||
|
||||
|
||||
|
||||
#include <filesystem>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
class MemoryRandomAccess;
|
||||
class Memory;
|
||||
class Slots;
|
||||
class ScreenImage;
|
||||
class CassetteIn;
|
||||
class CassetteOut;
|
||||
class Apple2;
|
||||
|
||||
|
||||
|
||||
class ConfigException {
|
||||
public:
|
||||
const std::string msg;
|
||||
ConfigException(const std::string& msg) : msg(msg) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class E2Command {
|
||||
void tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2);
|
||||
|
||||
void insertCard(const std::string& cardType, const int slot, Slots& slts, ScreenImage& gui, const double random_ones_rate);
|
||||
|
||||
void loadDisk(Slots& slts, int slot, int drive, const std::filesystem::path &media);
|
||||
void unloadDisk(Slots& slts, int slot, int drive);
|
||||
void saveDisk(Slots& slts, int slot, int drive);
|
||||
|
||||
public:
|
||||
E2Command();
|
||||
virtual ~E2Command();
|
||||
|
||||
void parseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* E2COMMAND_H */
|
388
src/e2config.cpp
388
src/e2config.cpp
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
#include "e2config.h"
|
||||
|
||||
#include "e2command.h"
|
||||
#include "E2wxApp.h"
|
||||
#include "e2filesystem.h"
|
||||
#include "apple2.h"
|
||||
|
@ -38,11 +39,11 @@
|
|||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <cctype>
|
||||
|
@ -53,17 +54,6 @@ static const wxString DEFAULT_CONFIG_NAME{"epple2"};
|
|||
|
||||
|
||||
|
||||
#define K 1024u
|
||||
|
||||
static std::uint16_t memory_block_size(const std::string &block_size) {
|
||||
if (block_size == "4K") {
|
||||
return 4u*K;
|
||||
}
|
||||
if (block_size == "16K") {
|
||||
return 16u*K;
|
||||
}
|
||||
throw ConfigException("invalid RAM strapping block size (must be 4K or 16K)");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -74,31 +64,16 @@ E2Config::E2Config(const std::filesystem::path& f, bool p): file_path {f}, prefs
|
|||
E2Config::~E2Config() {
|
||||
}
|
||||
|
||||
static void strip_comment(std::string& str)
|
||||
{
|
||||
static void strip_comment(std::string& str) {
|
||||
const size_t comment = str.find('#');
|
||||
if (comment < std::string::npos)
|
||||
{
|
||||
if (comment < std::string::npos) {
|
||||
str.erase(comment);
|
||||
}
|
||||
}
|
||||
|
||||
static void trim(std::string& str)
|
||||
{
|
||||
{
|
||||
const size_t p = str.find_first_not_of(" \t");
|
||||
if (p < std::string::npos)
|
||||
{
|
||||
str.erase(0,p);
|
||||
}
|
||||
}
|
||||
{
|
||||
const size_t p = str.find_last_not_of(" \t");
|
||||
if (p+1 < std::string::npos)
|
||||
{
|
||||
str.erase(p+1);
|
||||
}
|
||||
}
|
||||
static void trim(std::string& s) {
|
||||
wxString w{s};
|
||||
s = w.Trim(false).Trim(true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -280,8 +255,7 @@ void E2Config::parse(MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& rev
|
|||
strip_comment(line);
|
||||
trim(line);
|
||||
if (!line.empty()) {
|
||||
// TODO "parseLine" will become Command::execute, or similar
|
||||
parseLine(line, ram, rom, slts, revision, gui, cassetteIn, cassetteOut, apple2);
|
||||
E2Command{}.parseLine(line, ram, rom, slts, revision, gui, cassetteIn, cassetteOut, apple2);
|
||||
}
|
||||
std::getline(*p_ifstream_config, line);
|
||||
}
|
||||
|
@ -290,349 +264,3 @@ void E2Config::parse(MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& rev
|
|||
|
||||
// TODO: make sure there is no more than ONE stdin and/or ONE stdout card
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void E2Config::parseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2) {
|
||||
try {
|
||||
tryParseLine(line, ram, rom, slts, revision, gui, cassetteIn, cassetteOut, apple2);
|
||||
} catch (const ConfigException& err) {
|
||||
std::cerr << err.msg.c_str() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string filter_row(const std::string &row) {
|
||||
if (row.length() != 1) {
|
||||
return "";
|
||||
}
|
||||
return std::string(1, static_cast<char> (std::toupper(row[0])));
|
||||
}
|
||||
|
||||
void E2Config::tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2) {
|
||||
std::istringstream tok(line);
|
||||
|
||||
std::string cmd;
|
||||
tok >> cmd;
|
||||
if (cmd == "slot") {
|
||||
int slot;
|
||||
std::string sCardType;
|
||||
tok >> slot >> sCardType;
|
||||
|
||||
insertCard(sCardType, slot, slts, gui, tok);
|
||||
} else if (cmd == "motherboard") {
|
||||
std::string op;
|
||||
tok >> op;
|
||||
if (op == "ram") {
|
||||
/* ram ROW BIT0 [BIT1 [... [BIT7]]]
|
||||
* ram e -
|
||||
* ram d 4096 MK4096 4K
|
||||
* ram c 16K 4116 MK4116 MM5290 16K 16K 16K 16K
|
||||
*/
|
||||
std::string row;
|
||||
tok >> row;
|
||||
row = filter_row(row);
|
||||
if (row != "C" && row != "D" && row != "E") {
|
||||
throw ConfigException("expected row to be C, D, or E");
|
||||
}
|
||||
|
||||
std::string chip_model;
|
||||
tok >> chip_model;
|
||||
for (std::uint_fast8_t bit = 0u; bit < 8u; ++bit) {
|
||||
ram.insert_chip(row, MemoryChip::instance(chip_model), bit);
|
||||
|
||||
std::string chip_model_optional;
|
||||
tok >> chip_model_optional;
|
||||
if (chip_model_optional.length()) {
|
||||
chip_model = chip_model_optional;
|
||||
}
|
||||
}
|
||||
} else if (op == "strap") {
|
||||
/* strap ROM K start-addr
|
||||
* strap e 4K 5000
|
||||
* strap d 4K 4000
|
||||
* strap c 16K 0000
|
||||
*/
|
||||
std::string row;
|
||||
tok >> row;
|
||||
row = filter_row(row);
|
||||
if (row != "C" && row != "D" && row != "E") {
|
||||
throw ConfigException("expected row to be C, D, or E");
|
||||
}
|
||||
|
||||
std::string block_size;
|
||||
tok >> block_size;
|
||||
std::uint16_t siz = memory_block_size(block_size);
|
||||
unsigned short base(0);
|
||||
tok >> std::hex >> base;
|
||||
// TODO validate siz/base combination
|
||||
ram.strap_to(row, base, siz);
|
||||
} else {
|
||||
throw ConfigException("error at \"motherboard\"; expected \"ram\" or \"strap\"");
|
||||
}
|
||||
} else if (cmd == "import") {
|
||||
std::string sm;
|
||||
tok >> sm;
|
||||
|
||||
int slot(-1);
|
||||
if (sm == "slot") {
|
||||
tok >> slot;
|
||||
} else if (sm != "motherboard") {
|
||||
throw ConfigException("error at \"" + sm + "\"; expected \"slot #\" or \"motherboard\"");
|
||||
}
|
||||
|
||||
std::string romtype;
|
||||
tok >> romtype;
|
||||
|
||||
unsigned short base(0);
|
||||
tok >> std::hex >> base;
|
||||
|
||||
std::string file;
|
||||
std::getline(tok, file);
|
||||
trim(file);
|
||||
std::ifstream *memfile = new std::ifstream(file.c_str(), std::ios::binary);
|
||||
if (!memfile->is_open()) {
|
||||
std::filesystem::path f = wxGetApp().GetResDir();
|
||||
f /= file;
|
||||
memfile = new std::ifstream(f, std::ios::binary);
|
||||
if (!memfile->is_open()) {
|
||||
throw ConfigException("cannot open file " + file);
|
||||
}
|
||||
}
|
||||
|
||||
if (slot < 0) // motherboard
|
||||
{
|
||||
if (romtype == "rom") {
|
||||
rom.load(base, *memfile);
|
||||
} else {
|
||||
throw ConfigException("error at \"" + romtype + "\"; expected rom or ram");
|
||||
}
|
||||
} else {
|
||||
if (8 <= slot) {
|
||||
throw ConfigException("invalid slot number");
|
||||
}
|
||||
Card* card = slts.get(slot);
|
||||
if (romtype == "rom")
|
||||
card->loadRom(base, *memfile);
|
||||
else if (romtype == "rom7")
|
||||
card->loadSeventhRom(base, *memfile);
|
||||
else if (romtype == "rombank")
|
||||
card->loadBankRom(base, *memfile);
|
||||
else
|
||||
throw ConfigException("error at \"" + romtype + "\"; expected rom, rom7, or rombank");
|
||||
}
|
||||
memfile->close();
|
||||
} else if (cmd == "load" || cmd == "save" || cmd == "unload") {
|
||||
std::string slotk;
|
||||
tok >> slotk;
|
||||
if (slotk != "slot") {
|
||||
throw ConfigException("error at \"" + slotk + "\"; expected \"slot\"");
|
||||
}
|
||||
|
||||
int slot(-1);
|
||||
tok >> slot;
|
||||
|
||||
std::string drivek;
|
||||
tok >> drivek;
|
||||
if (drivek != "drive") {
|
||||
throw ConfigException("error at \"" + drivek + "\"; expected \"drive\"");
|
||||
}
|
||||
|
||||
int drive(-1);
|
||||
tok >> drive;
|
||||
|
||||
if (cmd == "load") {
|
||||
std::string fn_optional;
|
||||
std::getline(tok, fn_optional);
|
||||
trim(fn_optional);
|
||||
if (fn_optional.length() == 0) {
|
||||
gui.exitFullScreen();
|
||||
wxFileDialog dlg{nullptr, "Load floppy", "", "", "WOZ 2.0 disk images (*.woz)|*.woz", wxFD_OPEN|wxFD_FILE_MUST_EXIST};
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
fn_optional = dlg.GetPath().c_str();
|
||||
}
|
||||
}
|
||||
if (fn_optional.length() > 0) {
|
||||
loadDisk(slts, slot, drive, fn_optional);
|
||||
}
|
||||
} else if (cmd == "unload") {
|
||||
unloadDisk(slts, slot, drive);
|
||||
} else if (cmd == "save") {
|
||||
saveDisk(slts, slot, drive);
|
||||
}
|
||||
} else if (cmd == "revision") {
|
||||
tok >> std::hex >> revision;
|
||||
} else if (cmd == "cassette") {
|
||||
std::string cas;
|
||||
tok >> cas;
|
||||
|
||||
if (cas == "rewind") {
|
||||
cassetteIn.rewind();
|
||||
} else if (cas == "tone") {
|
||||
cassetteIn.tone();
|
||||
} else if (cas == "blank") {
|
||||
std::string fcas;
|
||||
std::getline(tok, fcas);
|
||||
trim(fcas);
|
||||
if (!fcas.empty()) {
|
||||
cassetteOut.blank(fcas);
|
||||
}
|
||||
} else if (cas == "load") {
|
||||
std::string fn_optional;
|
||||
std::getline(tok, fn_optional);
|
||||
trim(fn_optional);
|
||||
if (fn_optional.length() == 0) {
|
||||
gui.exitFullScreen();
|
||||
wxFileDialog dlg{nullptr, "Load cassette (audio)", "", "", "WAVE cassette images (*.wav)|*.wav", wxFD_OPEN|wxFD_FILE_MUST_EXIST};
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
fn_optional = dlg.GetPath().c_str();
|
||||
}
|
||||
}
|
||||
if (fn_optional.length() > 0) {
|
||||
cassetteIn.load(fn_optional);
|
||||
}
|
||||
} else if (cas == "eject") {
|
||||
std::string eject;
|
||||
tok >> eject;
|
||||
if (eject == "in") {
|
||||
cassetteIn.eject();
|
||||
} else if (eject == "out") {
|
||||
cassetteOut.eject();
|
||||
} else {
|
||||
throw ConfigException("error: unknown cassette to eject: " + eject);
|
||||
}
|
||||
} else if (cas == "save") {
|
||||
cassetteOut.save();
|
||||
} else {
|
||||
throw ConfigException("error: unknown cassette command: " + cas);
|
||||
}
|
||||
} else if (cmd == "cpu") {
|
||||
std::string cpu;
|
||||
tok >> cpu;
|
||||
if (apple2 != NULL) {
|
||||
if (cpu == "epple2") {
|
||||
apple2->useEpple2Cpu();
|
||||
} else if (cpu == "visual6502") {
|
||||
apple2->useVisual6502Cpu();
|
||||
} else {
|
||||
throw ConfigException("invalid value for cpu command: " + cpu);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw ConfigException("Invalid command: " + cmd);
|
||||
}
|
||||
|
||||
if (apple2 != NULL) {
|
||||
apple2->useEpple2Cpu(); // set default CPU
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned char E2Config::disk_mask(0);
|
||||
|
||||
void E2Config::loadDisk(Slots& slts, int slot, int drive, const std::string& fnib) {
|
||||
if (drive < 1 || 2 < drive) {
|
||||
throw ConfigException("Invalid drive; must be 1 or 2");
|
||||
}
|
||||
|
||||
// TODO if file doesn't exist, name still gets displayed, and there's no error message
|
||||
Card* card = slts.get(slot);
|
||||
if (!(disk_mask & (1 << slot))) {
|
||||
std::cerr << "Slot " << slot << " doesn't have a disk controller card" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
DiskController* controller = (DiskController*) card;
|
||||
controller->loadDisk(drive - 1, fnib);
|
||||
}
|
||||
|
||||
void E2Config::unloadDisk(Slots& slts, int slot, int drive) {
|
||||
if (drive < 1 || 2 < drive) {
|
||||
throw ConfigException("Invalid drive; must be 1 or 2");
|
||||
}
|
||||
|
||||
Card* card = slts.get(slot);
|
||||
if (!(disk_mask & (1 << slot))) {
|
||||
std::cerr << "Slot " << slot << " doesn't have a disk controller card" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
DiskController* controller = (DiskController*) card;
|
||||
controller->unloadDisk(drive - 1);
|
||||
}
|
||||
|
||||
void E2Config::saveDisk(Slots& slts, int slot, int drive) {
|
||||
if (drive < 1 || 2 < drive) {
|
||||
throw ConfigException("Invalid drive; must be 1 or 2");
|
||||
}
|
||||
slts.get(slot)->save(drive - 1);
|
||||
}
|
||||
|
||||
void E2Config::insertCard(const std::string& cardType, int slot, Slots& slts, ScreenImage& gui, std::istringstream& tok) {
|
||||
if (slot < 0 || 8 <= slot) {
|
||||
throw ConfigException("Invalid slot number");
|
||||
}
|
||||
|
||||
Card* card;
|
||||
|
||||
disk_mask &= ~(1 << slot);
|
||||
|
||||
if (cardType == "language") {
|
||||
card = new LanguageCard(gui, slot);
|
||||
} else if (cardType == "firmware") {
|
||||
card = new FirmwareCard(gui, slot);
|
||||
} else if (cardType == "disk") {
|
||||
// 16-sector LSS ROM
|
||||
double random_ones_rate(0.3); // WOZ spec v2.0: 30%
|
||||
tok >> random_ones_rate;
|
||||
std::cerr << "MC3470: rate of 1 bits during random bit generation: " << random_ones_rate << std::endl;
|
||||
card = new DiskController(gui, slot, false, random_ones_rate);
|
||||
disk_mask |= (1 << slot);
|
||||
} else if (cardType == "disk13") {
|
||||
// 13-sector LSS ROM
|
||||
double random_ones_rate(0.3); // WOZ spec v2.0: 30%
|
||||
tok >> random_ones_rate;
|
||||
std::cerr << "MC3470: rate of 1 bits during random bit generation: " << random_ones_rate << std::endl;
|
||||
card = new DiskController(gui, slot, true, random_ones_rate);
|
||||
disk_mask |= (1 << slot);
|
||||
} else if (cardType == "clock") {
|
||||
card = new ClockCard();
|
||||
} else if (cardType == "stdout") {
|
||||
card = new StandardOut();
|
||||
} else if (cardType == "stdin") {
|
||||
card = new StandardIn();
|
||||
} else if (cardType == "empty") {
|
||||
card = 0;
|
||||
} else {
|
||||
throw ConfigException("Invalid card type: " + cardType);
|
||||
}
|
||||
|
||||
if (card) {
|
||||
slts.set(slot, card);
|
||||
} else {
|
||||
slts.remove(slot);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,11 +29,6 @@ class CassetteIn;
|
|||
class CassetteOut;
|
||||
class Apple2;
|
||||
|
||||
class ConfigException {
|
||||
public:
|
||||
const std::string msg;
|
||||
ConfigException(const std::string& msg) : msg(msg) {}
|
||||
};
|
||||
|
||||
// TODO split out all static things into their own class (and don't make them static)
|
||||
// Remember that, besides config, also command line entry calls parseLine
|
||||
|
@ -42,24 +37,17 @@ class E2Config {
|
|||
private:
|
||||
const std::filesystem::path file_path;
|
||||
const bool prefs_only;
|
||||
static unsigned char disk_mask;
|
||||
|
||||
std::ifstream *openFile();
|
||||
std::ifstream *openFilePref(const wxString& s_name);
|
||||
std::ifstream *openFileExternal(const std::filesystem::path& path);
|
||||
std::ifstream *openFileLegacy();
|
||||
static void loadDisk(Slots& slts, int slot, int drive, const std::string& fnib);
|
||||
static void unloadDisk(Slots& slts, int slot, int drive);
|
||||
static void saveDisk(Slots& slts, int slot, int drive);
|
||||
static void insertCard(const std::string& cardType, int slot, Slots& slts, ScreenImage& gui, std::istringstream& tok);
|
||||
static void tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2);
|
||||
|
||||
public:
|
||||
E2Config(const std::filesystem::path& f, bool p);
|
||||
~E2Config();
|
||||
|
||||
void parse(MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2);
|
||||
static void parseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
#include "emulator.h"
|
||||
#include "e2config.h"
|
||||
#include "e2command.h"
|
||||
#include "e2const.h"
|
||||
|
||||
#include <wx/msgdlg.h>
|
||||
|
@ -479,7 +480,7 @@ void Emulator::processCommand() {
|
|||
return;
|
||||
}
|
||||
|
||||
E2Config::parseLine(cmdline, this->apple2.ram, this->apple2.rom, this->apple2.slts, this->apple2.revision, this->screenImage, this->apple2.cassetteIn, this->apple2.cassetteOut, NULL);
|
||||
E2Command{}.parseLine(cmdline, this->apple2.ram, this->apple2.rom, this->apple2.slts, this->apple2.revision, this->screenImage, this->apple2.cassetteIn, this->apple2.cassetteOut, NULL);
|
||||
cmdline.erase(cmdline.begin(), cmdline.end());
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "card.h"
|
||||
#include "util.h"
|
||||
#include <SDL.h>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
|
@ -366,7 +367,7 @@ void ScreenImage::removeCard(const int slot, Card* card /* empty */) {
|
|||
789012345678901234567890123456789012345678901234567890123456789012345
|
||||
6: disk][ drive 1M*filename.nib T$FF drive 2M*filename.nib T$FF
|
||||
*/
|
||||
void ScreenImage::setDiskFile(int slot, int drive, const std::string& filepath) {
|
||||
void ScreenImage::setDiskFile(int slot, int drive, const std::filesystem::path &filepath) {
|
||||
std::string f = truncateFilePath(filepath);
|
||||
int r(R_SLOT + slot);
|
||||
int c(37 + 32 * drive);
|
||||
|
@ -382,8 +383,8 @@ void ScreenImage::setDiskFile(int slot, int drive, const std::string& filepath)
|
|||
this->slotnames[slot].replace(c - 20, f.length(), f);
|
||||
}
|
||||
|
||||
std::string ScreenImage::truncateFilePath(const std::string& filepath) {
|
||||
std::string f(filepath);
|
||||
std::string ScreenImage::truncateFilePath(const std::filesystem::path& filepath) {
|
||||
std::string f(filepath.c_str());
|
||||
size_t slash = f.find_last_of("/\\");
|
||||
if (slash != std::string::npos) {
|
||||
f = f.substr(slash + 1);
|
||||
|
@ -453,7 +454,7 @@ void ScreenImage::setDirty(int slot, int drive, bool dirty) {
|
|||
this->slotnames[slot][c - 20] = dirty ? '*' : ' ';
|
||||
}
|
||||
|
||||
void ScreenImage::setCassetteInFile(const std::string& filepath) {
|
||||
void ScreenImage::setCassetteInFile(const std::filesystem::path& filepath) {
|
||||
std::string f = truncateFilePath(filepath);
|
||||
int r(65);
|
||||
int c(85 + 11);
|
||||
|
@ -469,7 +470,7 @@ void ScreenImage::setCassetteInFile(const std::string& filepath) {
|
|||
this->cassInName.replace(c - 94, f.length(), f);
|
||||
}
|
||||
|
||||
void ScreenImage::setCassetteOutFile(const std::string& filepath) {
|
||||
void ScreenImage::setCassetteOutFile(const std::filesystem::path& filepath) {
|
||||
std::string f = truncateFilePath(filepath);
|
||||
int r(66);
|
||||
int c(85 + 11);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#define SCREENIMAGE_H
|
||||
|
||||
#include "analogtv.h"
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
@ -45,7 +46,7 @@ private:
|
|||
std::string cassInName;
|
||||
std::string cassOutName;
|
||||
|
||||
static std::string truncateFilePath(const std::string& filepath);
|
||||
static std::string truncateFilePath(const std::filesystem::path& filepath);
|
||||
|
||||
// TODO some of these methods should be private
|
||||
public:
|
||||
|
@ -80,7 +81,7 @@ public:
|
|||
void addkeyCommand(unsigned char key);
|
||||
void backspaceCommand();
|
||||
|
||||
void setDiskFile(int slot, int drive, const std::string& filename);
|
||||
void setDiskFile(int slot, int drive, const std::filesystem::path& filename);
|
||||
|
||||
void setAnnunciator(int ann, bool on);
|
||||
|
||||
|
@ -90,8 +91,8 @@ public:
|
|||
void setIO(int slot, int drive, bool on);
|
||||
void setDirty(int slot, int drive, bool dirty);
|
||||
|
||||
void setCassetteInFile(const std::string& filepath);
|
||||
void setCassetteOutFile(const std::string& filepath);
|
||||
void setCassetteInFile(const std::filesystem::path& filepath);
|
||||
void setCassetteOutFile(const std::filesystem::path& filepath);
|
||||
void setCassetteDirty(bool dirty); // cassette out only
|
||||
void setCassettePos(unsigned int pos, unsigned int siz); // cassette in only
|
||||
|
||||
|
|
|
@ -134,8 +134,8 @@ void Slots::forceGuiUpdate()
|
|||
}
|
||||
|
||||
void Slots::save(int unit) {
|
||||
for (std::vector<Card*>::iterator i = this->cards.begin(); i != this->cards.end(); ++i) {
|
||||
(*i)->save(unit);
|
||||
for (auto &i : this->cards) {
|
||||
i->saveMedia(unit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,14 +154,12 @@ bool isAnyDiskDriveMotorOn()
|
|||
return on.inhibit;
|
||||
}
|
||||
*/
|
||||
struct Slots_Card_isDirty
|
||||
{
|
||||
bool dirty;
|
||||
Slots_Card_isDirty():dirty(false) {}
|
||||
void operator() (Card* p) { if (p->isDirty()) dirty = true; }
|
||||
};
|
||||
|
||||
bool Slots::isDirty()
|
||||
{
|
||||
return std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_isDirty()).dirty;
|
||||
bool Slots::isDirty() {
|
||||
for (auto &i : this->cards) {
|
||||
if (i->isMediaDirty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
10
src/slots.h
10
src/slots.h
|
@ -24,9 +24,7 @@
|
|||
|
||||
class ScreenImage;
|
||||
|
||||
class Slots
|
||||
{
|
||||
private:
|
||||
class Slots {
|
||||
ScreenImage& gui;
|
||||
EmptySlot empty;
|
||||
std::vector<Card*> cards;
|
||||
|
@ -35,7 +33,7 @@ public:
|
|||
Slots(ScreenImage& gui);
|
||||
~Slots();
|
||||
|
||||
void tick();
|
||||
void tick();
|
||||
unsigned char io(const int islot, const int iswch, const unsigned char b, const bool writing);
|
||||
void reset();
|
||||
unsigned char readRom(const int islot, const unsigned short addr, const unsigned char data);
|
||||
|
@ -46,8 +44,8 @@ public:
|
|||
Card* get(const int slot);
|
||||
void remove(const int slot);
|
||||
bool isDirty();
|
||||
void save(int unit);
|
||||
void forceGuiUpdate();
|
||||
void save(int unit);
|
||||
void forceGuiUpdate();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue