This commit is contained in:
Christopher A. Mosher 2022-11-03 18:26:07 -04:00
parent 617bad3e51
commit 348f85e391
14 changed files with 131 additions and 51 deletions

View File

@ -11,6 +11,8 @@
cpu epple2
# standard 48K RAM with mixed chip brands # standard 48K RAM with mixed chip brands
motherboard ram E MM5290 MM5290 MM5290 MK4116 MM5290 MM5290 MM5290 MK4116 motherboard ram E MM5290 MM5290 MM5290 MK4116 MM5290 MM5290 MM5290 MK4116
motherboard strap E 16K 8000 motherboard strap E 16K 8000

View File

@ -0,0 +1,16 @@
# Use the Visual 6502 emulation algorithm (from http://www.visual6502.org/).
# WARNING: this is EXTREMELY SLOW
cpu visual6502
motherboard ram E MM5290 MM5290 MM5290 MK4116 MM5290 MM5290 MM5290 MK4116
motherboard strap E 16K 8000
motherboard ram D MM5290 MM5290 MK4116 MK4116 MM5290 MK4116 MM5290 MCM4116
motherboard strap D 16K 4000
motherboard ram C MK4116 MK4116 MM5290 MM5290 MM5290 MM5290 MM5290 MM5290
motherboard strap C 16K 0000
import motherboard rom 2C00 ${LIBDIR}/epple2/system/epple2sys.a65

View File

@ -121,6 +121,26 @@ strap c 4K 0000
#### cpu
The `cpu` command chooses which CPU emulator to run with.
``` conf
cpu epple2
```
Valid values are:
`epple2` The standard, faster, albeit less accurate, high-level emulator. Works for 99.99% of known cases.
This is the default value, used when the `cpu` command is not present.
`visual6502` The emulator based on the algorithm and transistor circuitry from http://www.visual6502.org/.
WARNING: this emulator is *extremely slow*, but absolutely 100% accurate to the original MOS6502.
Note: the CPU cannot be changed in the user interface, only in the configuration file.
#### import #### import
The `import` command imports a binary image file into the emulated Apple's ROMs. The `import` command imports a binary image file into the emulated Apple's ROMs.

View File

@ -72,17 +72,9 @@ add_executable(epple2 ${sources})
find_package(SDL2 CONFIG) find_package(SDL2 CONFIG)
message(STATUS "SDL2_INCLUDE_DIRS: ${SDL2_INCLUDE_DIRS}") message(STATUS "SDL2_INCLUDE_DIRS: ${SDL2_INCLUDE_DIRS}")
message(STATUS "SDL2_LIBRARIES: ${SDL2_LIBRARIES}")
target_include_directories(epple2 PRIVATE ${SDL2_INCLUDE_DIRS}) target_include_directories(epple2 PRIVATE ${SDL2_INCLUDE_DIRS})
message(STATUS "SDL2_LIBRARIES: ${SDL2_LIBRARIES}")
target_link_libraries(epple2 ${SDL2_LIBRARIES}) target_link_libraries(epple2 ${SDL2_LIBRARIES})
target_compile_features(epple2 PRIVATE cxx_std_17) target_compile_features(epple2 PRIVATE cxx_std_17)
target_compile_definitions(epple2 PRIVATE ETCDIR="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}") target_compile_definitions(epple2 PRIVATE ETCDIR="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}")
option(USE_EMU "Use http://www.visual6502.org/ CPU (will run slowly)")
if (USE_EMU)
message(STATUS "USE_EMU")
target_compile_definitions(epple2 PRIVATE USE_EMU)
# target_compile_definitions(epple2 PRIVATE TRACESEG)
target_compile_definitions(epple2 PRIVATE TRACEREG)
endif()

View File

@ -1,4 +1,4 @@
/* /*
* File: Emu6502.h * File: Emu6502.h
* Author: Christopher * Author: Christopher
* *
@ -8,6 +8,7 @@
#ifndef EMU6502_H #ifndef EMU6502_H
#define EMU6502_H #define EMU6502_H
#include "abstractcpu.h"
#include "Cpu6502Helper.h" #include "Cpu6502Helper.h"
#include "Cpu6502.h" #include "Cpu6502.h"
#include "Trace.h" #include "Trace.h"
@ -19,7 +20,7 @@
class AddressBus; class AddressBus;
class Emu6502 { class Emu6502 : public AbstractCpu {
public: public:
Emu6502(std::istream& transistors, AddressBus& mem) : tn(transistors, segs, transes), c(tn), trace(segs, transes, c), cpu(mem, trace, c), cpuhelper(cpu, c) { Emu6502(std::istream& transistors, AddressBus& mem) : tn(transistors, segs, transes), c(tn), trace(segs, transes, c), cpu(mem, trace, c), cpuhelper(cpu, c) {

29
src/abstractcpu.h Normal file
View File

@ -0,0 +1,29 @@
/*
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/>.
*/
#ifndef ABSTRACTCPU_H
#define ABSTRACTCPU_H
class AbstractCpu {
public:
virtual ~AbstractCpu() {};
virtual void powerOn() = 0;
virtual void reset() = 0;
virtual void tick() = 0;
};
#endif

View File

@ -48,12 +48,8 @@ Apple2::Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates
addressBus(gui,revision,ram,rom,kbd,videoMode,paddles,paddleButtonStates,speaker,cassetteIn,cassetteOut,slts), addressBus(gui,revision,ram,rom,kbd,videoMode,paddles,paddleButtonStates,speaker,cassetteIn,cassetteOut,slts),
picgen(tv,videoMode,revision), picgen(tv,videoMode,revision),
video(videoMode,addressBus,picgen,textRows), video(videoMode,addressBus,picgen,textRows),
#ifdef USE_EMU transistors("transistors"),
transistors("transistors"), cpu(NULL),
cpu(transistors,addressBus),
#else
cpu(addressBus),
#endif
powerUpReset(*this), powerUpReset(*this),
revision(1) revision(1)
{ {
@ -63,9 +59,22 @@ Apple2::~Apple2()
{ {
} }
void Apple2::useEpple2Cpu() {
if (this->cpu == NULL) {
std::cout << "Using fast Epple2 CPU emulator" << std::endl;
this->cpu = new CPU(this->addressBus);
}
}
void Apple2::useVisual6502Cpu() {
if (this->cpu == NULL) {
std::cout << "Using http://www.visual6502.org/ CPU emulation (which will be slow)." << std::endl;
this->cpu = new Emu6502(this->transistors, this->addressBus);
}
}
void Apple2::tick() { void Apple2::tick() {
this->cpu.tick(); this->cpu->tick();
this->slts.tick(); this->slts.tick();
this->video.tick(); this->video.tick();
this->paddles.tick(); this->paddles.tick();
@ -81,7 +90,7 @@ void Apple2::tick() {
void Apple2::powerOn() void Apple2::powerOn()
{ {
this->ram.powerOn(); this->ram.powerOn();
this->cpu.powerOn(); this->cpu->powerOn();
this->videoMode.powerOn(); this->videoMode.powerOn();
this->video.powerOn(); this->video.powerOn();
this->picgen.powerOn(); this->picgen.powerOn();
@ -95,6 +104,6 @@ void Apple2::powerOff()
void Apple2::reset() void Apple2::reset()
{ {
this->cpu.reset(); this->cpu->reset();
this->slts.reset(); this->slts.reset();
} }

View File

@ -28,6 +28,7 @@
#include "picturegenerator.h" #include "picturegenerator.h"
#include "textcharacters.h" #include "textcharacters.h"
#include "video.h" #include "video.h"
#include "abstractcpu.h"
#include "cpu.h" #include "cpu.h"
#include "paddles.h" #include "paddles.h"
#include "paddlebuttonstates.h" #include "paddlebuttonstates.h"
@ -56,12 +57,8 @@ class Apple2 : public Timable
PictureGenerator picgen; PictureGenerator picgen;
TextCharacters textRows; TextCharacters textRows;
Video video; Video video;
#ifdef USE_EMU std::ifstream transistors;
std::ifstream transistors; AbstractCpu* cpu;
Emu6502 cpu;
#else
CPU cpu;
#endif
PowerUpReset powerUpReset; PowerUpReset powerUpReset;
int revision; int revision;
@ -69,6 +66,9 @@ public:
Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui); Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui);
~Apple2(); ~Apple2();
void useEpple2Cpu();
void useVisual6502Cpu();
void powerOn(); void powerOn();
void powerOff(); void powerOff();
void reset(); void reset();

View File

@ -17,6 +17,7 @@
*/ */
#include "configep2.h" #include "configep2.h"
#include "apple2.h"
#include "memory.h" #include "memory.h"
#include "memoryrandomaccess.h" #include "memoryrandomaccess.h"
#include "slots.h" #include "slots.h"
@ -93,14 +94,8 @@ static void trim(std::string& str)
} }
} }
void Config::parse(MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut) void Config::parse(MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2)
{ {
#ifdef USE_EMU
std::cout << "Running with http://www.visual6502.org/ CPU emulation (which will be slow)." << std::endl;
#endif
std::ifstream* pConfig; std::ifstream* pConfig;
std::string path(this->file_path); std::string path(this->file_path);
@ -192,7 +187,7 @@ void Config::parse(MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revis
trim(line); trim(line);
if (!line.empty()) if (!line.empty())
{ {
parseLine(line,ram,rom,slts,revision,gui,cassetteIn,cassetteOut); parseLine(line,ram,rom,slts,revision,gui,cassetteIn,cassetteOut,apple2);
} }
std::getline(*pConfig,line); std::getline(*pConfig,line);
} }
@ -201,11 +196,11 @@ void Config::parse(MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revis
// TODO: make sure there is no more than ONE stdin and/or ONE stdout card // TODO: make sure there is no more than ONE stdin and/or ONE stdout card
} }
void Config::parseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut) void Config::parseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2)
{ {
try try
{ {
tryParseLine(line,ram,rom,slts,revision,gui,cassetteIn,cassetteOut); tryParseLine(line,ram,rom,slts,revision,gui,cassetteIn,cassetteOut,apple2);
} }
catch (const ConfigException& err) catch (const ConfigException& err)
{ {
@ -220,7 +215,7 @@ static std::string filter_row(const std::string &row) {
return std::string(1, static_cast<char>(std::toupper(row[0]))); return std::string(1, static_cast<char>(std::toupper(row[0])));
} }
void Config::tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut) void Config::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::istringstream tok(line);
@ -456,10 +451,28 @@ void Config::tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memo
throw ConfigException("error: unknown cassette command: "+cas); 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 else
{ {
throw ConfigException("Invalid command: "+cmd); throw ConfigException("Invalid command: "+cmd);
} }
if (apple2 != NULL) {
apple2->useEpple2Cpu(); // set default CPU
}
} }
void Config::loadDisk(Slots& slts, int slot, int drive, const std::string& fnib) void Config::loadDisk(Slots& slts, int slot, int drive, const std::string& fnib)

View File

@ -25,6 +25,7 @@ class Slots;
class ScreenImage; class ScreenImage;
class CassetteIn; class CassetteIn;
class CassetteOut; class CassetteOut;
class Apple2;
class ConfigException { class ConfigException {
public: public:
@ -41,14 +42,14 @@ private:
static void unloadDisk(Slots& slts, int slot, int drive); static void unloadDisk(Slots& slts, int slot, int drive);
static void saveDisk(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 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); static void tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2);
public: public:
Config(const std::string& file_path); Config(const std::string& file_path);
~Config(); ~Config();
void parse(MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut); 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); static void parseLine(const std::string& line, MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, CassetteIn& cassetteIn, CassetteOut& cassetteOut, Apple2* apple2);
}; };
#endif #endif

View File

@ -18,10 +18,11 @@
#ifndef CPU_H #ifndef CPU_H
#define CPU_H #define CPU_H
#include "abstractcpu.h"
class AddressBus; class AddressBus;
#include <istream>
class CPU class CPU : public AbstractCpu {
{
private: private:
enum { MEMORY_LIM = 1 << 0x10 }; enum { MEMORY_LIM = 1 << 0x10 };
enum { IRQ_VECTOR = MEMORY_LIM-2 }; // or BRK enum { IRQ_VECTOR = MEMORY_LIM-2 }; // or BRK
@ -43,7 +44,7 @@ private:
bool pendingIRQ; bool pendingIRQ;
bool pendingNMI; bool pendingNMI;
bool pendingReset; bool pendingReset;
bool started; bool started;
unsigned char a; unsigned char a;
@ -205,7 +206,7 @@ private:
public: public:
CPU(AddressBus& addressBus); CPU(AddressBus& addressBus);
~CPU(); virtual ~CPU();
void powerOn(); void powerOn();
void reset(); void reset();

View File

@ -72,7 +72,7 @@ void Emulator::powerOffComputer() {
} }
void Emulator::config(Config& cfg) { void Emulator::config(Config& cfg) {
cfg.parse(this->apple2.ram, this->apple2.rom, this->apple2.slts, this->apple2.revision, this->screenImage, this->apple2.cassetteIn, this->apple2.cassetteOut); cfg.parse(this->apple2.ram, this->apple2.rom, this->apple2.slts, this->apple2.revision, this->screenImage, this->apple2.cassetteIn, this->apple2.cassetteOut, &this->apple2);
this->apple2.ram.dump_config(); this->apple2.ram.dump_config();
} }
@ -444,7 +444,7 @@ void Emulator::processCommand() {
return; return;
} }
Config::parseLine(cmdline, this->apple2.ram, this->apple2.rom, this->apple2.slts, this->apple2.revision, this->screenImage, this->apple2.cassetteIn, this->apple2.cassetteOut); Config::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()); cmdline.erase(cmdline.begin(), cmdline.end());
} }

View File

@ -60,7 +60,7 @@ class Emulator
void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent); void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent);
void cmdKey(const SDL_KeyboardEvent& keyEvent); void cmdKey(const SDL_KeyboardEvent& keyEvent);
void processCommand(); void processCommand();
bool isSafeToQuit(); bool isSafeToQuit();
public: public:
Emulator(); Emulator();

View File

@ -44,9 +44,5 @@ void PowerUpReset::tick()
void PowerUpReset::powerOn() void PowerUpReset::powerOn()
{ {
#ifdef USE_EMU
this->pendingTicks = 99; // TODO REMOVE THIS
#else
this->pendingTicks = (int)(E2Const::AVG_CPU_HZ*.3); // U.A.II, p. 7-15 this->pendingTicks = (int)(E2Const::AVG_CPU_HZ*.3); // U.A.II, p. 7-15
#endif
} }