new config hadling, first pass; refactor apple core loop; search resources for imported rom files

This commit is contained in:
Christopher A. Mosher 2022-12-05 22:19:24 -05:00
parent e74c631d44
commit c2bd2dcee3
7 changed files with 164 additions and 70 deletions

View File

@ -54,6 +54,11 @@ wxIMPLEMENT_APP_NO_MAIN(E2wxApp);
#define PROJECT_VERSION 0.0.1
#endif
std::promise<void> E2wxApp::barrier_to_init;
E2wxApp::E2wxApp() : id("nu.mine.mosher.epple2"), version(wxSTRINGIZE_T(PROJECT_VERSION)) {
}
@ -151,6 +156,7 @@ bool E2wxApp::OnInit() {
frame->Show();
barrier_to_init.set_value();
return true;
}

View File

@ -27,6 +27,7 @@
#include <thread>
#include <filesystem>
#include <string>
#include <future>
class E2wxApp : public wxApp {
const std::string id;
@ -41,6 +42,8 @@ class E2wxApp : public wxApp {
void InitBoostLog();
public:
static std::promise<void> barrier_to_init;
E2wxApp();
virtual ~E2wxApp();

View File

@ -137,7 +137,7 @@ void PreferencesDialog::OnInit() {
wxConfigBase *appconf = wxConfigBase::Get();
if (!appconf->Read(wxT("/ActivePreferences/name"), &this->active)) {
// TODO what to do when no config?
this->active = ".template";
this->active = "epple2";
appconf->Write(wxT("/ActivePreferences/name"), this->active);
appconf->Flush();
}

View File

@ -17,6 +17,8 @@
*/
#include "configep2.h"
#include "E2wxApp.h"
#include "apple2.h"
#include "memory.h"
#include "memoryrandomaccess.h"
@ -31,6 +33,9 @@
#include "cassetteout.h"
#include "tinyfiledialogs.h"
#include <wx/config.h>
#include <wx/string.h>
#include <iostream>
#include <istream>
#include <fstream>
@ -105,11 +110,46 @@ void Config::parse(MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revis
pConfig = new std::ifstream(path.c_str());
if (!pConfig->is_open())
{
// TODO use filename only and look in standard resources
std::stringstream ss;
ss << "Cannot open config file " << this->file_path.c_str();
throw std::runtime_error(ss.str());
}
}
if (path.empty())
{
// TODO config file location, how to be backwardly compatible?
wxString user_config;
if (!wxConfigBase::Get()->Read(wxT("/ActivePreferences/name"), &user_config)) {
// TODO what to do when no config?
user_config = wxT("epple2");
}
std::filesystem::path f = wxGetApp().GetConfigDir();
f /= user_config.t_str();
f += ".conf";
path = f.string();
std::cout << "looking for config file: " << path << std::endl;
pConfig = new std::ifstream(path.c_str());
if (!pConfig->is_open()) {
f = wxGetApp().GetResDir();
f /= user_config.t_str();
f += ".conf";
path = f.string();
std::cout << "looking for config file: " << path << std::endl;
pConfig = new std::ifstream(path.c_str());
if (!pConfig->is_open()) {
path.clear();
}
}
}
if (path.empty())
{
std::cout << "standard config file location: " ETCDIR "/epple2/epple2.conf" << std::endl;
@ -304,17 +344,23 @@ void Config::tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memo
std::string file;
std::getline(tok,file);
trim(file);
std::ifstream memfile(file.c_str(),std::ios::binary);
if (!memfile.is_open())
std::ifstream *memfile = new std::ifstream(file.c_str(),std::ios::binary);
if (!memfile->is_open())
{
throw ConfigException("cannot open file "+file);
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);
rom.load(base,*memfile);
}
else
{
@ -329,15 +375,15 @@ void Config::tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memo
}
Card* card = slts.get(slot);
if (romtype == "rom")
card->loadRom(base,memfile);
card->loadRom(base,*memfile);
else if (romtype == "rom7")
card->loadSeventhRom(base,memfile);
card->loadSeventhRom(base,*memfile);
else if (romtype == "rombank")
card->loadBankRom(base,memfile);
card->loadBankRom(base,*memfile);
else
throw ConfigException("error at \""+romtype+"\"; expected rom, rom7, or rombank");
}
memfile.close();
memfile->close();
}
else if (cmd == "load" || cmd == "save" || cmd == "unload")
{
@ -375,6 +421,7 @@ void Config::tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memo
}
}
if (fn_optional.length() > 0) {
// TODO check if file exists, if not then check resources
loadDisk(slts,slot,drive,fn_optional);
}
}

View File

@ -95,81 +95,101 @@ void Emulator::init() {
static const int CYCLES_PER_REPT(E2Const::AVG_CPU_HZ / 10);
// The core of this Apple
// If the Apple ][ keyboard repeat is on (the REPT key is
// down)...
void Emulator::handleRepeatKey() {
if (this->repeat) {
// Count our way down to when the timer for the REPT key
// fires off: 10Hz in terms of how many CPU cycles have gone
// by
--this->rept;
// If it's time for the REPT key timer to fire (at long
// last)...
if (this->rept <= 0) {
// ...reload the timer for the next firing 1/10 second from
// now ( *reset* the timer )
this->rept = CYCLES_PER_REPT;
// If any other keys are actually being held down...
if (this->keysDown > 0) {
// ...REPEAT the most recent one that was pressed
this->keypresses.push(this->lastKeyDown);
}
}
}
}
void Emulator::handleAnyPendingEvents() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
// If SDL is going away...
quitIfSafe();
break;
case SDL_KEYDOWN:
// If we're collecting a command line for changing any
// of the configurables of the emulator...
if (this->command)
cmdKey(event.key);
else
// ...else we're collecting keypresses for the keyboard
// emulation (and thus the Apple ][ emulation itself)
dispatchKeypress(event.key);
break;
case SDL_KEYUP:
// If we're collecting a command line for changing any
// of the configurables of the emulator...
if (this->command) {
if (this->pendingCommandExit) {
this->command = false;
this->pendingCommandExit = false;
}
} else {
// ...else we're collecting keypresses for the keyboard
// emulation (and thus the Apple ][ emulation itself)
dispatchKeyUp(event.key);
}
break;
}
}
}
// The core of this Apple
int Emulator::run() {
int skip = CHECK_EVERY_CYCLE;
int skip = 0;
Uint32 prev_ms = SDL_GetTicks();
// While the user still wants to run this emulation...
while (!this->quit) {
// (Obligatory protection against NULL object pointer)
if (this->timable) {
this->timable->tick();
// If the Apple ][ keyboard repeat is on (the REPT key is
// down)...
if (this->repeat) {
// Count our way down to when the timer for the REPT key
// fires off: 10Hz in terms of how many CPU cycles have gone
// by
--this->rept;
// If it's time for the REPT key timer to fire (at long
// last)...
if (this->rept <= 0) {
// ...reload the timer for the next firing 1/10 second from
// now ( *reset* the timer )
this->rept = CYCLES_PER_REPT;
// If any other keys are actually being held down...
if (this->keysDown > 0) {
// ...REPEAT the most recent one that was pressed
this->keypresses.push(this->lastKeyDown);
}
}
}
handleRepeatKey();
}
// People who have too many press releases should be referred to as
// keyboards
--skip;
// If skip has been decremented to zero...
if (!skip) {
if (CHECK_EVERY_CYCLE <= ++skip) {
// ...then it's time to drain away any piled-up user interaction
// events that SDL has stored up for us
// Reload the skip quantity
skip = CHECK_EVERY_CYCLE;
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
// If SDL is going away...
case SDL_QUIT:
quitIfSafe();
break;
case SDL_KEYDOWN:
// If we're collecting a command line for changing any
// of the configurables of the emulator...
if (this->command)
cmdKey(event.key);
else
// ...else we're collecting keypresses for the keyboard
// emulation (and thus the Apple ][ emulation itself)
dispatchKeypress(event.key);
break;
case SDL_KEYUP:
// If we're collecting a command line for changing any
// of the configurables of the emulator...
if (this->command) {
if (this->pendingCommandExit) {
this->command = false;
this->pendingCommandExit = false;
}
} else {
// ...else we're collecting keypresses for the keyboard
// emulation (and thus the Apple ][ emulation itself)
dispatchKeyUp(event.key);
}
break;
}
}
skip = 0;
handleAnyPendingEvents();
// If we're trying to run as slow as a real Apple ][...
if (!this->fhyper.isHyper()) {
const int delta_ms = EXPECTED_MS - (SDL_GetTicks() - prev_ms);
@ -178,15 +198,23 @@ int Emulator::run() {
}
}
// Display the current estimate of the emulator's actual speed
// performance
this->screenImage.displayHz(CHECK_CYCLES_K / (SDL_GetTicks() - prev_ms));
prev_ms = SDL_GetTicks();
}
}
return 0;
}
void Emulator::dispatchKeyUp(const SDL_KeyboardEvent& keyEvent) {
SDL_Keycode sym = keyEvent.keysym.sym;
SDL_Keymod mod = (SDL_Keymod) keyEvent.keysym.mod;
@ -429,7 +457,6 @@ void Emulator::cmdKey(const SDL_KeyboardEvent& keyEvent) {
}
// Process a command line typed at the bottom of the emulator window
void Emulator::processCommand() {
this->screenImage.exitCommandMode();
this->screenImage.drawPower(this->timable == &this->apple2);

View File

@ -62,6 +62,9 @@ class Emulator
void processCommand();
bool isSafeToQuit();
void handleRepeatKey();
void handleAnyPendingEvents();
public:
Emulator();
virtual ~Emulator();

View File

@ -26,6 +26,7 @@
#include <wx/app.h>
#include <thread>
#include <future>
#include <iostream>
#include <ostream>
#include <stdexcept>
@ -48,19 +49,26 @@ static std::string parse_args(int argc, char* argv[]) {
}
static int fake_argc(0);
static int fake_argc(1);
static char fake_prog[] = "epple2";
static char *fake_argv[] { fake_prog };
static int runWx() {
std::cout << "starting wx..." << std::endl;
return wxEntry(fake_argc, fake_argv);
}
static int runSdl(const std::string config_file) {
GUI gui;
std::future<void> barrier_to_app_init = E2wxApp::barrier_to_init.get_future();
std::thread thread_wx(runWx);
std::cout << "wait for wx init" << std::endl;
barrier_to_app_init.wait();
std::cout << "wx init finished" << std::endl;
std::unique_ptr<Emulator> emu(new Emulator());
Config cfg(config_file);