mirror of
https://github.com/ArthurFerreira2/reinette-IIe.git
synced 2024-12-26 10:32:44 +00:00
initial commit
first public release
This commit is contained in:
parent
af2334c245
commit
4c8b396e53
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2021 ArthurFerreira2
|
Copyright (c) 2020 Arthur Ferreira
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
104
Makefile
Normal file
104
Makefile
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#
|
||||||
|
# Cross Platform Makefile
|
||||||
|
# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X
|
||||||
|
#
|
||||||
|
# You will need SDL2 (http://www.libsdl.org):
|
||||||
|
# Linux:
|
||||||
|
# apt-get install libsdl2-dev
|
||||||
|
# Mac OS X:
|
||||||
|
# brew install sdl2
|
||||||
|
# MSYS2:
|
||||||
|
# pacman -S mingw-w64-i686-SDL2
|
||||||
|
#
|
||||||
|
|
||||||
|
# pick one
|
||||||
|
CXX = g++
|
||||||
|
#CXX = clang++
|
||||||
|
|
||||||
|
EXE = reinette
|
||||||
|
SOURCES = main.cpp puce65c02.cpp mmu.cpp video.cpp disk.cpp speaker.cpp paddles.cpp gui.cpp
|
||||||
|
|
||||||
|
IMGUI_DIR = lib/imgui-1.82
|
||||||
|
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
|
||||||
|
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl2.cpp
|
||||||
|
|
||||||
|
ImGuiColorTextEdit_DIR = lib/ImGuiColorTextEdit-master
|
||||||
|
SOURCES += $(ImGuiColorTextEdit_DIR)/TextEditor.cpp
|
||||||
|
|
||||||
|
imfilebrowser_DIR = lib/imgui-filebrowser
|
||||||
|
imgui_club_DIR = lib/imgui_club-master
|
||||||
|
|
||||||
|
|
||||||
|
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
|
||||||
|
UNAME_S := $(shell uname -s)
|
||||||
|
|
||||||
|
CXXFLAGS = -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -I$(ImGuiColorTextEdit_DIR) -I$(imfilebrowser_DIR) -I$(imgui_club_DIR)
|
||||||
|
# CXXFLAGS += -O3
|
||||||
|
CXXFLAGS += -std=c++17 -lstdc++fs -Wall -Wformat -pedantic -Wpedantic -O3
|
||||||
|
LIBS =
|
||||||
|
|
||||||
|
WIN32-RC = reinette.rc
|
||||||
|
WIN32-RES = reinette.res
|
||||||
|
|
||||||
|
|
||||||
|
##---------------------------------------------------------------------
|
||||||
|
## BUILD FLAGS PER PLATFORM
|
||||||
|
##---------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(UNAME_S), Linux) #LINUX
|
||||||
|
ECHO_MESSAGE = "Linux"
|
||||||
|
LIBS += -lGL -ldl `sdl2-config --libs`
|
||||||
|
|
||||||
|
CXXFLAGS += `sdl2-config --cflags`
|
||||||
|
CFLAGS = $(CXXFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME_S), Darwin) #APPLE
|
||||||
|
ECHO_MESSAGE = "Mac OS X"
|
||||||
|
LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo `sdl2-config --libs`
|
||||||
|
LIBS += -L/usr/local/lib -L/opt/local/lib
|
||||||
|
|
||||||
|
CXXFLAGS += `sdl2-config --cflags`
|
||||||
|
CXXFLAGS += -I/usr/local/include -I/opt/local/include
|
||||||
|
CFLAGS = $(CXXFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(OS), Windows_NT)
|
||||||
|
ECHO_MESSAGE = "MinGW"
|
||||||
|
# LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl2`
|
||||||
|
LIBS += -lgdi32 -lopengl32 -limm32 -lmingw32 --static -Wl,-subsystem,windows -LC:/msys64/mingw64/lib -lmingw32 -lSDL2main -lSDL2 -mwindows -lmingw32 -ldinput8 -lshell32 -lsetupapi -ladvapi32 -luuid -lversion -loleaut32 -lole32 -limm32 -lwinmm -lgdi32 -luser32 -lm -mwindows -Wl,--no-undefined -pipe -Wl,--dynamicbase,--high-entropy-va,--nxcompat,--default-image-base-high
|
||||||
|
|
||||||
|
# CXXFLAGS += `pkg-config --cflags sdl2 `
|
||||||
|
CXXFLAGS += -IC:/msys64/mingw64/include/SDL2
|
||||||
|
CFLAGS = $(CXXFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
##---------------------------------------------------------------------
|
||||||
|
## BUILD RULES
|
||||||
|
##---------------------------------------------------------------------
|
||||||
|
|
||||||
|
%.o:%.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
%.o:$(IMGUI_DIR)/%.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
%.o:$(IMGUI_DIR)/backends/%.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
%.o:$(ImGuiColorTextEdit_DIR)/%.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
all: $(EXE)
|
||||||
|
@echo Build complete for $(ECHO_MESSAGE)
|
||||||
|
|
||||||
|
$(EXE): $(OBJS) $(WIN32-RES)
|
||||||
|
$(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
$(WIN32-RES): $(WIN32-RC)
|
||||||
|
windres -o $@ $^ -O coff
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(EXE) $(OBJS) $(WIN32-RES)
|
16
README.md
16
README.md
@ -1,2 +1,14 @@
|
|||||||
# reinetteIIe
|
WORK IN PROGRESS
|
||||||
Reinette IIe, an enhanced Apple //e emulator
|
|
||||||
|
|
||||||
|
# reinette IIe
|
||||||
|
|
||||||
|
### reinette gets enhanced !
|
||||||
|
|
||||||
|
![screenshots](animated.gif)
|
||||||
|
|
||||||
|
|
||||||
|
\
|
||||||
|
\
|
||||||
|
\
|
||||||
|
*simplicity is the ultimate sophistication*
|
||||||
|
BIN
animated.gif
Normal file
BIN
animated.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 MiB |
129
disk.cpp
Normal file
129
disk.cpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "reinette.h"
|
||||||
|
|
||||||
|
Disk::Disk() {
|
||||||
|
curDrv = 0; // Current Drive - only one can be enabled at a time
|
||||||
|
// TODO : initialize the unit[x] structs
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Disk::load( char *path, int drive) {
|
||||||
|
FILE *f = fopen(path, "rb"); // open file in read binary mode
|
||||||
|
|
||||||
|
if (!f || fread(unit[drive].data, 1, 232960, f) != 232960) // load it into memory and check size
|
||||||
|
return 0;
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
sprintf(unit[drive].pathName, "%s", path); // update floppy image pathName record
|
||||||
|
|
||||||
|
// get filename
|
||||||
|
int i =0, a = 0;
|
||||||
|
while (unit[drive].pathName[i] != 0) { // find start of filename for disk0
|
||||||
|
if (unit[drive].pathName[i] == '/' || unit[drive].pathName[i] == '\\')
|
||||||
|
a = i + 1;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
sprintf(unit[drive].fileName, "%s", unit[drive].pathName + a);
|
||||||
|
|
||||||
|
// is the file read only ?
|
||||||
|
f = fopen(path, "ab"); // try to open the file in append binary mode
|
||||||
|
if (f) { // success, file is writable
|
||||||
|
unit[drive].readOnly = false; // update the readOnly flag
|
||||||
|
fclose(f); // and close it untouched
|
||||||
|
} else {
|
||||||
|
unit[drive].readOnly = true; // f is NULL, no writable, no need to close it
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Disk::save(int drive) {
|
||||||
|
if (!unit[drive].pathName[0]) return 0; // no file loaded into drive
|
||||||
|
if (unit[drive].readOnly) return 0; // file is read only write no aptempted
|
||||||
|
|
||||||
|
FILE *f = fopen(unit[drive].pathName, "wb");
|
||||||
|
|
||||||
|
if (!f) return 0; // could not open the file in write overide binary
|
||||||
|
if (fwrite(unit[drive].data, 1, 232960, f) != 232960) { // failed to write the full file (hdd full ?)
|
||||||
|
fclose(f); // release the ressource
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fclose(f); // success, release the ressource
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Disk::eject(int drive) {
|
||||||
|
unit[drive].fileName[0] = 0;
|
||||||
|
unit[drive].pathName[0] = 0;
|
||||||
|
unit[drive].readOnly = false;
|
||||||
|
|
||||||
|
for (int i=0; i<232960; i++) // erase data
|
||||||
|
unit[drive].data[i]=0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Disk::stepMotor(uint16_t address) {
|
||||||
|
static bool phases[2][4] = { 0 }; // phases states (for both drives)
|
||||||
|
static bool phasesB[2][4] = { 0 }; // phases states Before
|
||||||
|
static bool phasesBB[2][4] = { 0 }; // phases states Before Before
|
||||||
|
static int pIdx[2] = { 0 }; // phase index (for both drives)
|
||||||
|
static int pIdxB[2] = { 0 }; // phase index Before
|
||||||
|
static int halfTrackPos[2] = { 0 };
|
||||||
|
|
||||||
|
address &= 7;
|
||||||
|
int phase = address >> 1;
|
||||||
|
|
||||||
|
phasesBB[curDrv][pIdxB[curDrv]] = phasesB[curDrv][pIdxB[curDrv]];
|
||||||
|
phasesB[curDrv][pIdx[curDrv]] = phases[curDrv][pIdx[curDrv]];
|
||||||
|
pIdxB[curDrv] = pIdx[curDrv];
|
||||||
|
pIdx[curDrv] = phase;
|
||||||
|
|
||||||
|
if (!(address & 1)) { // head not moving (PHASE x OFF)
|
||||||
|
phases[curDrv][phase] = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((phasesBB[curDrv][(phase + 1) & 3]) && (--halfTrackPos[curDrv] < 0)) // head is moving in
|
||||||
|
halfTrackPos[curDrv] = 0;
|
||||||
|
|
||||||
|
if ((phasesBB[curDrv][(phase - 1) & 3]) && (++halfTrackPos[curDrv] > 140)) // head is moving out
|
||||||
|
halfTrackPos[curDrv] = 140;
|
||||||
|
|
||||||
|
phases[curDrv][phase] = true; // update track#
|
||||||
|
unit[curDrv].track = (halfTrackPos[curDrv] + 1) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Disk::setDrv(int drv) {
|
||||||
|
unit[drv].motorOn = unit[!drv].motorOn || unit[drv].motorOn; // if any of the motors were ON
|
||||||
|
unit[!drv].motorOn = false; // motor of the other drive is set to OFF
|
||||||
|
curDrv = drv; // set the current drive
|
||||||
|
}
|
57
disk.h
Normal file
57
disk.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DISK_H__
|
||||||
|
#define __DISK_H__
|
||||||
|
|
||||||
|
typedef struct Drive_t {
|
||||||
|
char fileName[400]; // the floppy image file name
|
||||||
|
char pathName[400]; // the full floppy image path name
|
||||||
|
bool readOnly; // based on the image file attributes
|
||||||
|
uint8_t data[232960]; // nibblelized floppy image
|
||||||
|
bool motorOn; // motor status
|
||||||
|
bool writeMode; // writes to file are not implemented
|
||||||
|
uint8_t track; // current track position
|
||||||
|
uint16_t nibble; // ptr to nibble under head position
|
||||||
|
} Drive;
|
||||||
|
|
||||||
|
|
||||||
|
class Disk {
|
||||||
|
public:
|
||||||
|
int curDrv = 0; // Current Drive - only one can be enabled at a time
|
||||||
|
Drive unit[2] = {0}; // two disk ][ drive units
|
||||||
|
|
||||||
|
Disk();
|
||||||
|
~Disk();
|
||||||
|
|
||||||
|
int load(char *filename, int drv);
|
||||||
|
int save(int drive);
|
||||||
|
int eject(int drive);
|
||||||
|
|
||||||
|
void setDrv(int drv);
|
||||||
|
void stepMotor(uint16_t address);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
748
gui.cpp
Normal file
748
gui.cpp
Normal file
@ -0,0 +1,748 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "reinette.h"
|
||||||
|
|
||||||
|
Gui::Gui() {
|
||||||
|
frameNumber = 0;
|
||||||
|
screenScale = 2.0f;
|
||||||
|
fps = 60;
|
||||||
|
|
||||||
|
show_about_window = false;
|
||||||
|
show_help_window = false;
|
||||||
|
CRT_is_focused = false;
|
||||||
|
show_crt_window = true;
|
||||||
|
show_control_window = true;
|
||||||
|
show_disks_window = true;
|
||||||
|
show_info_window = true;
|
||||||
|
show_cpu_window = true;
|
||||||
|
show_code_window = true;
|
||||||
|
show_pageZero_window = true;
|
||||||
|
show_stack_window = true;
|
||||||
|
show_ram_window = true;
|
||||||
|
show_aux_window = true;
|
||||||
|
show_rom_window = true;
|
||||||
|
show_editor_window = true;
|
||||||
|
show_ramHeatmap_window = true;
|
||||||
|
show_auxHeatmap_window = true;
|
||||||
|
|
||||||
|
// Setup SDL
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) {
|
||||||
|
printf("Error: %s\n", SDL_GetError());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup window
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||||
|
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||||
|
wdo = SDL_CreateWindow("Reinette", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1700, 900, window_flags);
|
||||||
|
gl_context = SDL_GL_CreateContext(wdo);
|
||||||
|
SDL_GL_MakeCurrent(wdo, gl_context);
|
||||||
|
SDL_GL_SetSwapInterval(1); // Enable vsync
|
||||||
|
|
||||||
|
SDL_EventState(SDL_DROPFILE, SDL_ENABLE); // ask SDL2 to read dropfile events
|
||||||
|
|
||||||
|
// Setup Dear ImGui context
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
ImGui::CreateContext();
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||||
|
// io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||||
|
// io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
||||||
|
|
||||||
|
#include "imguiTheme.h"
|
||||||
|
|
||||||
|
// Setup Platform/Renderer backends
|
||||||
|
ImGui_ImplSDL2_InitForOpenGL(wdo, gl_context);
|
||||||
|
ImGui_ImplOpenGL2_Init();
|
||||||
|
|
||||||
|
clear_color = ImVec4((float)51/256, (float)58/256, (float)64/256, 1.00f); // fond de la fenetre principale
|
||||||
|
glGenTextures(1, &screenTexture);
|
||||||
|
glGenTextures(1, &ramHeatmapTexture);
|
||||||
|
glGenTextures(1, &auxHeatmapTexture);
|
||||||
|
|
||||||
|
// editor init
|
||||||
|
auto lang = TextEditor::LanguageDefinition::AppleSoft();
|
||||||
|
editor.SetLanguageDefinition(lang);
|
||||||
|
editor.SetShowWhitespaces(false);
|
||||||
|
editor.SetPalette(TextEditor::GetLightPalette());
|
||||||
|
fileToEdit = "program.bas";
|
||||||
|
std::ifstream t(fileToEdit);
|
||||||
|
if (t.good()) {
|
||||||
|
std::string str((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
|
||||||
|
editor.SetText(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int Gui::newFrame() {
|
||||||
|
// Start the Dear ImGui frame
|
||||||
|
ImGui_ImplOpenGL2_NewFrame();
|
||||||
|
ImGui_ImplSDL2_NewFrame(wdo);
|
||||||
|
ImGui::NewFrame();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Gui::getInputs() {
|
||||||
|
|
||||||
|
SDL_Event event;
|
||||||
|
while (SDL_PollEvent(&event)) {
|
||||||
|
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||||
|
|
||||||
|
SDL_bool ctrl, shift, alt;
|
||||||
|
|
||||||
|
alt = SDL_GetModState() & KMOD_ALT ? SDL_TRUE : SDL_FALSE;
|
||||||
|
ctrl = SDL_GetModState() & KMOD_CTRL ? SDL_TRUE : SDL_FALSE;
|
||||||
|
shift = SDL_GetModState() & KMOD_SHIFT ? SDL_TRUE : SDL_FALSE;
|
||||||
|
paddles->PB0 = alt ? 0xFF : 0x00; // update push button 0, Open Apple
|
||||||
|
paddles->PB1 = ctrl ? 0xFF : 0x00; // update push button 1, Solid Apple or option
|
||||||
|
paddles->PB2 = shift ? 0xFF : 0x00; // update push button 2, single-wire Shift-key mod
|
||||||
|
|
||||||
|
|
||||||
|
if (event.type == SDL_QUIT) running = false; // WM sent TERM signal
|
||||||
|
|
||||||
|
if (event.type == SDL_DROPFILE) { // user dropped a file
|
||||||
|
char *filename = event.drop.file; // get full pathname
|
||||||
|
if (!disk->load(filename, alt)) // if ALT : drv 1 else drv 0
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Load", "Not a valid nib file", NULL);
|
||||||
|
SDL_free(filename); // free filename memory
|
||||||
|
paused = false; // might already be the case
|
||||||
|
if (!(alt || ctrl)) { // unless ALT or CTRL were
|
||||||
|
mmu->init();
|
||||||
|
mmu->writeMem(0x3F4,0); // unset the Power-UP byte
|
||||||
|
cpu->RST(); // do a cold reset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CRT_is_focused) { // if (!io.WantCaptureKeyboard) {
|
||||||
|
if (event.type == SDL_KEYDOWN) { // a key has been pressed
|
||||||
|
switch (event.key.keysym.sym) {
|
||||||
|
|
||||||
|
// EMULATOR CONTROLS :
|
||||||
|
|
||||||
|
case SDLK_F3: // PASTE text from clipboard
|
||||||
|
if (SDL_HasClipboardText()) {
|
||||||
|
char *clipboardText = SDL_GetClipboardText();
|
||||||
|
int c = 0;
|
||||||
|
while (clipboardText[c]) { // all chars until ascii NUL
|
||||||
|
mmu->KBD = clipboardText[c++] | 0x80; // set bit7
|
||||||
|
if (mmu->KBD == 0x8A) mmu->KBD = 0x8D; // translate Line Feed to Carriage Ret
|
||||||
|
cpu->exec(400000); // give cpu (and applesoft) some cycles to process each char
|
||||||
|
}
|
||||||
|
SDL_free(clipboardText); // release the ressource
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_F4: // VOLUME
|
||||||
|
if (shift) speaker->setVolume(volume+10); // increase volume
|
||||||
|
if (ctrl) speaker->setVolume(volume-10); // decrease volume
|
||||||
|
if (!ctrl && !shift) speaker->toggleMute(); // toggle mute / unmute
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_F5: // JOYSTICK Release Speed
|
||||||
|
if (shift && (paddles->GCReleaseSpeed < 127)) paddles->GCReleaseSpeed += 2; // increase Release Speed
|
||||||
|
if (ctrl && (paddles->GCReleaseSpeed > 1)) paddles->GCReleaseSpeed -= 2; // decrease Release Speed
|
||||||
|
if (!ctrl && !shift) paddles->GCReleaseSpeed = 8; // reset Release Speed to 8
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_F6: // JOYSTICK Action Speed
|
||||||
|
if (shift && (paddles->GCActionSpeed < 127)) paddles->GCActionSpeed += 2; // increase Action Speed
|
||||||
|
if (ctrl && (paddles->GCActionSpeed > 1)) paddles->GCActionSpeed -= 2; // decrease Action Speed
|
||||||
|
if (!ctrl && !shift) paddles->GCActionSpeed = 8; // reset Action Speed to 8
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_F7: // ZOOM
|
||||||
|
if (shift && (screenScale <= 3.9f)) screenScale+=.1f; // zoom in
|
||||||
|
if (ctrl && (screenScale > 1.0f)) screenScale-=.1f; // zoom out
|
||||||
|
if (!ctrl && !shift) screenScale = 2.0f; // reset zoom to 2
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_F10: paused = !paused; break; // toggle pause
|
||||||
|
|
||||||
|
case SDLK_F11: {
|
||||||
|
paused = true;
|
||||||
|
cpu->state = step;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case SDLK_F12: cpu->RST(); break; // reset
|
||||||
|
|
||||||
|
// EMULATED KEYS :
|
||||||
|
|
||||||
|
case SDLK_a: mmu->KBD = ctrl ? 0x81: 0xC1; break; // a
|
||||||
|
case SDLK_b: mmu->KBD = ctrl ? 0x82: 0xC2; break; // b STX
|
||||||
|
case SDLK_c: mmu->KBD = ctrl ? 0x83: 0xC3; break; // c ETX
|
||||||
|
case SDLK_d: mmu->KBD = ctrl ? 0x84: 0xC4; break; // d EOT
|
||||||
|
case SDLK_e: mmu->KBD = ctrl ? 0x85: 0xC5; break; // e
|
||||||
|
case SDLK_f: mmu->KBD = ctrl ? 0x86: 0xC6; break; // f ACK
|
||||||
|
case SDLK_g: mmu->KBD = ctrl ? 0x87: 0xC7; break; // g BELL
|
||||||
|
case SDLK_h: mmu->KBD = ctrl ? 0x88: 0xC8; break; // h BS
|
||||||
|
case SDLK_i: mmu->KBD = ctrl ? 0x89: 0xC9; break; // i HTAB
|
||||||
|
case SDLK_j: mmu->KBD = ctrl ? 0x8A: 0xCA; break; // j LF
|
||||||
|
case SDLK_k: mmu->KBD = ctrl ? 0x8B: 0xCB; break; // k VTAB
|
||||||
|
case SDLK_l: mmu->KBD = ctrl ? 0x8C: 0xCC; break; // l FF
|
||||||
|
case SDLK_m: mmu->KBD = ctrl ? shift ? 0x9D:0x8D:0xCD; break;// m CR ]
|
||||||
|
case SDLK_n: mmu->KBD = ctrl ? shift ? 0x9E:0x8E:0xCE; break;// n ^
|
||||||
|
case SDLK_o: mmu->KBD = ctrl ? 0x8F: 0xCF; break; // o
|
||||||
|
case SDLK_p: mmu->KBD = ctrl ? shift ? 0x80:0x90:0xD0; break; // p @
|
||||||
|
case SDLK_q: mmu->KBD = ctrl ? 0x91: 0xD1; break; // q
|
||||||
|
case SDLK_r: mmu->KBD = ctrl ? 0x92: 0xD2; break; // r
|
||||||
|
case SDLK_s: mmu->KBD = ctrl ? 0x93: 0xD3; break; // s ESC
|
||||||
|
case SDLK_t: mmu->KBD = ctrl ? 0x94: 0xD4; break; // t
|
||||||
|
case SDLK_u: mmu->KBD = ctrl ? 0x95: 0xD5; break; // u NAK
|
||||||
|
case SDLK_v: mmu->KBD = ctrl ? 0x96: 0xD6; break; // v
|
||||||
|
case SDLK_w: mmu->KBD = ctrl ? 0x97: 0xD7; break; // w
|
||||||
|
case SDLK_x: mmu->KBD = ctrl ? 0x98: 0xD8; break; // x CANCEL
|
||||||
|
case SDLK_y: mmu->KBD = ctrl ? 0x99: 0xD9; break; // y
|
||||||
|
case SDLK_z: mmu->KBD = ctrl ? 0x9A: 0xDA; break; // z
|
||||||
|
case SDLK_LEFTBRACKET: mmu->KBD = ctrl ? 0x9B: 0xDB; break; // [ {
|
||||||
|
case SDLK_BACKSLASH: mmu->KBD = ctrl ? 0x9C: 0xDC; break; // \ |
|
||||||
|
case SDLK_RIGHTBRACKET: mmu->KBD = ctrl ? 0x9D: 0xDD; break; // ] }
|
||||||
|
case SDLK_BACKSPACE: mmu->KBD = ctrl ? 0xDF: 0x88; break; // BS
|
||||||
|
case SDLK_0: mmu->KBD = shift? 0xA9: 0xB0; break; // 0 )
|
||||||
|
case SDLK_1: mmu->KBD = shift? 0xA1: 0xB1; break; // 1 !
|
||||||
|
case SDLK_2: mmu->KBD = shift? 0xC0: 0xB2; break; // 2
|
||||||
|
case SDLK_3: mmu->KBD = shift? 0xA3: 0xB3; break; // 3 #
|
||||||
|
case SDLK_4: mmu->KBD = shift? 0xA4: 0xB4; break; // 4 $
|
||||||
|
case SDLK_5: mmu->KBD = shift? 0xA5: 0xB5; break; // 5 %
|
||||||
|
case SDLK_6: mmu->KBD = shift? 0xDE: 0xB6; break; // 6 ^
|
||||||
|
case SDLK_7: mmu->KBD = shift? 0xA6: 0xB7; break; // 7 &
|
||||||
|
case SDLK_8: mmu->KBD = shift? 0xAA: 0xB8; break; // 8 *
|
||||||
|
case SDLK_9: mmu->KBD = shift? 0xA8: 0xB9; break; // 9 (
|
||||||
|
case SDLK_QUOTE: mmu->KBD = shift? 0xA2: 0xA7; break; // ' "
|
||||||
|
case SDLK_EQUALS: mmu->KBD = shift? 0xAB: 0xBD; break; // = +
|
||||||
|
case SDLK_SEMICOLON: mmu->KBD = shift? 0xBA: 0xBB; break; // ; :
|
||||||
|
case SDLK_COMMA: mmu->KBD = shift? 0xBC: 0xAC; break; // , <
|
||||||
|
case SDLK_PERIOD: mmu->KBD = shift? 0xBE: 0xAE; break; // . >
|
||||||
|
case SDLK_SLASH: mmu->KBD = shift? 0xBF: 0xAF; break; // / ?
|
||||||
|
case SDLK_MINUS: mmu->KBD = shift? 0xDF: 0xAD; break; // - _
|
||||||
|
case SDLK_BACKQUOTE: mmu->KBD = shift? 0xFE: 0xE0; break; // ` ~
|
||||||
|
case SDLK_LEFT: mmu->KBD = 0x88; break; // BS
|
||||||
|
case SDLK_RIGHT: mmu->KBD = 0x95; break; // NAK
|
||||||
|
case SDLK_DOWN: mmu->KBD = 0x8A; break; // LF
|
||||||
|
case SDLK_UP: mmu->KBD = 0x8B; break; // VTAB
|
||||||
|
case SDLK_SPACE: mmu->KBD = 0xA0; break;
|
||||||
|
case SDLK_ESCAPE: mmu->KBD = 0x9B; break; // ESC
|
||||||
|
case SDLK_RETURN: mmu->KBD = 0x8D; break; // CR
|
||||||
|
case SDLK_TAB: mmu->KBD = 0x89; break; // HTAB
|
||||||
|
|
||||||
|
// EMULATED JOYSTICK :
|
||||||
|
|
||||||
|
case SDLK_KP_1: paddles->GCD[0] = -1; paddles->GCA[0] = 1; break; // pdl0 <-
|
||||||
|
case SDLK_KP_3: paddles->GCD[0] = 1; paddles->GCA[0] = 1; break; // pdl0 ->
|
||||||
|
case SDLK_KP_5: paddles->GCD[1] = -1; paddles->GCA[1] = 1; break; // pdl1 <-
|
||||||
|
case SDLK_KP_2: paddles->GCD[1] = 1; paddles->GCA[1] = 1; break; // pdl1 ->
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == SDL_KEYUP) {
|
||||||
|
switch (event.key.keysym.sym) {
|
||||||
|
case SDLK_KP_1: paddles->GCD[0] = 1; paddles->GCA[0] = 0; break; // pdl0 ->
|
||||||
|
case SDLK_KP_3: paddles->GCD[0] = -1; paddles->GCA[0] = 0; break; // pdl0 <-
|
||||||
|
case SDLK_KP_5: paddles->GCD[1] = 1; paddles->GCA[1] = 0; break; // pdl1 ->
|
||||||
|
case SDLK_KP_2: paddles->GCD[1] = -1; paddles->GCA[1] = 0; break; // pdl1 <-
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int Gui::update() {
|
||||||
|
|
||||||
|
if (ImGui::BeginMainMenuBar()) {
|
||||||
|
if (ImGui::BeginMenu("File")) {
|
||||||
|
if (ImGui::MenuItem("New", "Ctrl+N")) {
|
||||||
|
// void editor.SetText(const std::string& aText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Open", "Ctrl+O")) {
|
||||||
|
// void SetText(const std::string& aText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Save", "Ctrl+S")) {
|
||||||
|
// std::string textToSave = editor.GetText();
|
||||||
|
// std::ifstream t(fileToEdit);
|
||||||
|
// if (t.good()) {
|
||||||
|
// std::string str((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
|
||||||
|
// editor.SetText(str);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Save As..")) {
|
||||||
|
// TBD
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Quit", "CTRL+Q")) {
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu("Edit")) {
|
||||||
|
bool ro = editor.IsReadOnly();
|
||||||
|
if (ImGui::MenuItem("Read-only mode", nullptr, &ro))
|
||||||
|
editor.SetReadOnly(ro);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
if (ImGui::MenuItem("Undo", "CTRL+Z", nullptr, !ro && editor.CanUndo()))
|
||||||
|
editor.Undo();
|
||||||
|
if (ImGui::MenuItem("Redo", "CTRL+Y", nullptr, !ro && editor.CanRedo()))
|
||||||
|
editor.Redo();
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
if (ImGui::MenuItem("Copy", "Ctrl-C", nullptr, editor.HasSelection()))
|
||||||
|
editor.Copy();
|
||||||
|
if (ImGui::MenuItem("Cut", "Ctrl-X", nullptr, !ro && editor.HasSelection()))
|
||||||
|
editor.Cut();
|
||||||
|
if (ImGui::MenuItem("Delete", "Del", nullptr, !ro && editor.HasSelection()))
|
||||||
|
editor.Delete();
|
||||||
|
if (ImGui::MenuItem("Paste", "Ctrl-V", nullptr, !ro && ImGui::GetClipboardText() != nullptr))
|
||||||
|
editor.Paste();
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
if (ImGui::MenuItem("Select all", nullptr, nullptr))
|
||||||
|
editor.SetSelection(TextEditor::Coordinates(), TextEditor::Coordinates(editor.GetTotalLines(), 0));
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
if (ImGui::MenuItem("Dark palette"))
|
||||||
|
editor.SetPalette(TextEditor::GetDarkPalette());
|
||||||
|
if (ImGui::MenuItem("Light palette"))
|
||||||
|
editor.SetPalette(TextEditor::GetLightPalette());
|
||||||
|
if (ImGui::MenuItem("Retro blue palette"))
|
||||||
|
editor.SetPalette(TextEditor::GetRetroBluePalette());
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu("View")) {
|
||||||
|
ImGui::MenuItem("CRT", NULL, &show_crt_window);
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::MenuItem("Page Zero", NULL, &show_pageZero_window);
|
||||||
|
ImGui::MenuItem("Stack", NULL, &show_stack_window);
|
||||||
|
ImGui::MenuItem("Main RAM", NULL, &show_ram_window);
|
||||||
|
ImGui::MenuItem("Aux RAM", NULL, &show_aux_window);
|
||||||
|
ImGui::MenuItem("ROM", NULL, &show_rom_window);
|
||||||
|
ImGui::MenuItem("RAM Heatmap", NULL, &show_ramHeatmap_window);
|
||||||
|
ImGui::MenuItem("AUX Heatmap", NULL, &show_auxHeatmap_window);
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::MenuItem("Controls", NULL, &show_control_window);
|
||||||
|
ImGui::MenuItem("CPU", NULL, &show_cpu_window);
|
||||||
|
ImGui::MenuItem("Code", NULL, &show_code_window);
|
||||||
|
ImGui::MenuItem("Disk", NULL, &show_disks_window);
|
||||||
|
ImGui::MenuItem("Info", NULL, &show_info_window);
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::MenuItem("Editor", NULL, &show_editor_window);
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu("Help")) {
|
||||||
|
ImGui::MenuItem("Help", NULL, &show_help_window);
|
||||||
|
ImGui::MenuItem("About", NULL, &show_about_window);
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
ImGui::EndMainMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemoryEditor mem_edit_stack;
|
||||||
|
if (show_stack_window) {
|
||||||
|
mem_edit_stack.DrawWindow("STACK", mmu->ram+256, 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemoryEditor mem_edit_pageZero;
|
||||||
|
if (show_pageZero_window) {
|
||||||
|
mem_edit_pageZero.DrawWindow("PAGE ZERO", mmu->ram, 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemoryEditor mem_edit_ram;
|
||||||
|
if (show_ram_window) {
|
||||||
|
mem_edit_ram.DrawWindow("RAM", mmu->ram, RAMSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemoryEditor mem_edit_rom;
|
||||||
|
if (show_rom_window) {
|
||||||
|
mem_edit_rom.DrawWindow("ROM", mmu->rom, ROMSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemoryEditor mem_edit_aux;
|
||||||
|
if (show_aux_window) {
|
||||||
|
mem_edit_aux.DrawWindow("AUX", mmu->aux, AUXSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_about_window) {
|
||||||
|
if (ImGui::Begin("ABOUT", &show_about_window, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||||
|
ImGui::Text("Reinette 2021 Arthur Ferreira " );
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("version : %s", VERSION);
|
||||||
|
ImGui::Text("https://github.com/ArthurFerreira2");
|
||||||
|
ImGui::Text("\nReinette is licensed under the MIT License\nsee LICENSE for more information.\n");
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_help_window) {
|
||||||
|
if (ImGui::Begin("HELP", &show_help_window, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||||
|
ImGui::Text("Reinette v%s", VERSION);
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text( "\nctrl F1 writes the changes of the floppy in drive 0"
|
||||||
|
"\nalt F1 writes the changes of the floppy in drive 1"
|
||||||
|
"\n"
|
||||||
|
"\nF3 paste text from clipboard"
|
||||||
|
"\n"
|
||||||
|
"\nF4 mute / un-mute sound"
|
||||||
|
"\nshift F4 increase volume"
|
||||||
|
"\nctrl F4 decrease volume"
|
||||||
|
"\n"
|
||||||
|
"\nF5 reset joystick release speed"
|
||||||
|
"\nshift F5 increase joystick release speed"
|
||||||
|
"\ncrtl F5 decrease joystick release speed"
|
||||||
|
"\n"
|
||||||
|
"\nF6 reset joystick action speed"
|
||||||
|
"\nshift F6 increase joystick action speed"
|
||||||
|
"\ncrtl F6 decrease joystick action speed"
|
||||||
|
"\n"
|
||||||
|
"\nF7 reset the zoom to 2:1"
|
||||||
|
"\nshift F7 increase zoom up to 4:1 max"
|
||||||
|
"\nctrl F7 decrease zoom down to 1:1 pixels"
|
||||||
|
"\n"
|
||||||
|
"\nF8 monochrome / color display (only in HGR)"
|
||||||
|
"\nF9 pause / un-pause the emulator"
|
||||||
|
"\nF10 Not implemented"
|
||||||
|
"\nF11 reset");
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_ramHeatmap_window) {
|
||||||
|
ImGui::Begin("RAM HEATMAP", &show_ramHeatmap_window);
|
||||||
|
// Adjust the image to the window
|
||||||
|
auto window_size = ImGui::GetWindowSize();
|
||||||
|
auto image_size = ImVec2(window_size.x - 15, window_size.y - 50);
|
||||||
|
// Draw image
|
||||||
|
ImGui::Image((void*)((intptr_t)ramHeatmapTexture), image_size, ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(0,0,0,0));
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_auxHeatmap_window) {
|
||||||
|
ImGui::Begin("AUX HEATMAP", &show_auxHeatmap_window);
|
||||||
|
// Adjust the image to the window
|
||||||
|
auto window_size = ImGui::GetWindowSize();
|
||||||
|
auto image_size = ImVec2(window_size.x - 15, window_size.y - 50);
|
||||||
|
// Draw image
|
||||||
|
ImGui::Image((void*)((intptr_t)auxHeatmapTexture), image_size, ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(0,0,0,0));
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_control_window) {
|
||||||
|
ImGui::Begin("CONTROLS", &show_control_window);
|
||||||
|
ImGui::SliderInt("GC ACTION", &paddles->GCActionSpeed, 0, 128); // JOYSTICK Action Speed
|
||||||
|
ImGui::SliderInt("GC RELEASE", &paddles->GCReleaseSpeed, 0, 128); // JOYSTICK Release Speed
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::SliderFloat("SCALE", &screenScale, 1, 4, "%.1f");
|
||||||
|
if (ImGui::SliderInt("VOLUME", &volume, 0, 127)) speaker->setVolume(volume);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Checkbox("MUTE", &muted)) speaker->toggleMute();
|
||||||
|
ImGui::Separator();
|
||||||
|
if (ImGui::SliderFloat("SPEED", &speed, .0f, 200, "%.4f MHz", ImGuiSliderFlags_Logarithmic));
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("NORMAL")) speed = 1.023f;
|
||||||
|
ImGui::Checkbox("PAUSE", &paused);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("STEP")) {
|
||||||
|
paused = true;
|
||||||
|
cpu->state = step;
|
||||||
|
}
|
||||||
|
ImGui::Separator();
|
||||||
|
if (ImGui::Button("RESET"))
|
||||||
|
cpu->RST();
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("POWER CYCLE")) {
|
||||||
|
cpu->RST(); // do a cold reset
|
||||||
|
mmu->init();
|
||||||
|
mmu->ram[0x3F4] = 0; // unset the Power-UP byte
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string floppy1="", floppy2="";
|
||||||
|
|
||||||
|
fileDialog1.Display();
|
||||||
|
if (fileDialog1.HasSelected()) {
|
||||||
|
floppy1 = fileDialog1.GetSelected().filename().string();
|
||||||
|
disk->load((char*)fileDialog1.GetSelected().string().c_str(), 0);
|
||||||
|
fileDialog1.ClearSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
fileDialog2.Display();
|
||||||
|
if (fileDialog2.HasSelected()) {
|
||||||
|
floppy2 = fileDialog2.GetSelected().filename().string();
|
||||||
|
disk->load((char*)fileDialog2.GetSelected().string().c_str(), 1);
|
||||||
|
fileDialog2.ClearSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_disks_window) {
|
||||||
|
ImGui::Begin("DISK ][", &show_disks_window);
|
||||||
|
|
||||||
|
if (ImGui::Button("LOAD FLOPPY #1")) {
|
||||||
|
fileDialog1.SetTitle("Insert floppy into drive #1");
|
||||||
|
fileDialog1.SetTypeFilters({ ".nib", ".dsk", ".woz" });
|
||||||
|
fileDialog1.Open();
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("SAVE FLOPPY #1")) {
|
||||||
|
disk->save(0);
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("EJECT FLOPPY #1")) {
|
||||||
|
disk->eject(0);
|
||||||
|
}
|
||||||
|
ImGui::Text("Floppy #1 : %s", disk->unit[0].fileName);
|
||||||
|
ImGui::Text("Read %s", disk->unit[0].readOnly ? "Only" : "and Write");
|
||||||
|
ImGui::Text("Status : ");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (disk->unit[0].motorOn) {
|
||||||
|
if (disk->unit[0].writeMode)
|
||||||
|
ImGui::Text("writting");
|
||||||
|
else
|
||||||
|
ImGui::Text("reading");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ImGui::Text("idle");
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if (ImGui::Button("LOAD FLOPPY #2")) {
|
||||||
|
fileDialog2.SetTitle("Insert floppy into drive #2");
|
||||||
|
fileDialog2.SetTypeFilters({ ".nib", ".dsk", ".woz" });
|
||||||
|
fileDialog2.Open();
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("SAVE FLOPPY #2")) {
|
||||||
|
disk->save(1);
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("EJECT FLOPPY #2")) {
|
||||||
|
disk->eject(1);
|
||||||
|
}
|
||||||
|
ImGui::Text("Floppy #2 : %s", disk->unit[1].fileName);
|
||||||
|
ImGui::Text("Read %s", disk->unit[1].readOnly ? "Only" : "and Write");
|
||||||
|
ImGui::Text("Status : ");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (disk->unit[1].motorOn) {
|
||||||
|
if (disk->unit[1].writeMode)
|
||||||
|
ImGui::Text("writting");
|
||||||
|
else
|
||||||
|
ImGui::Text("reading");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ImGui::Text("idle");
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_info_window) {
|
||||||
|
ImGui::Begin("INFO", &show_info_window);
|
||||||
|
// Display FPS
|
||||||
|
ImGui::Text("%.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("KEY : %02X", mmu->KBD);
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Checkbox("TEXT", &mmu->TEXT);
|
||||||
|
ImGui::Checkbox("MIXED", &mmu->MIXED);
|
||||||
|
ImGui::Checkbox("PAGE2", &mmu->PAGE2);
|
||||||
|
ImGui::Checkbox("HIRES", &mmu->HIRES);
|
||||||
|
ImGui::Checkbox("DHIRES", &mmu->DHIRES);
|
||||||
|
ImGui::Checkbox("COL80", &mmu->COL80);
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Language Card readable : %s", mmu->LCRD ? "True" : "False");
|
||||||
|
ImGui::Text("Language Card writable : %s", mmu->LCWR ? "True" : "False");
|
||||||
|
ImGui::Text("Language Card bank 2 : %s", mmu->LCBK2 ? "Enabled" : "Disabled");
|
||||||
|
ImGui::Text("Language Card prewrite : %s", mmu->LCWFF ? "On" : "Off");
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("RAMRD : %s", mmu->RAMRD ? "On" : "Off");
|
||||||
|
ImGui::Text("RAMWRT : %s", mmu->RAMWRT ? "On" : "Off");
|
||||||
|
ImGui::Text("ALTZP : %s", mmu->ALTZP ? "On" : "Off");
|
||||||
|
ImGui::Text("STORE80 : %s", mmu->STORE80 ? "On" : "Off");
|
||||||
|
ImGui::Text("ALTCHARSET : %s", mmu->ALTCHARSET ? "On" : "Off");
|
||||||
|
ImGui::Text("INTCXROM : %s", mmu->INTCXROM ? "On" : "Off");
|
||||||
|
ImGui::Text("SLOTC3ROM : %s", mmu->SLOTC3ROM ? "On" : "Off");
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("VERTBLANK : %s", mmu->VERTBLANK ? "On" : "Off");
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_cpu_window) {
|
||||||
|
char buffer[1000];
|
||||||
|
cpu->getRegs(buffer);
|
||||||
|
ImGui::Begin("REGISTERS", &show_cpu_window);
|
||||||
|
ImGui::Text("%s", buffer);
|
||||||
|
// ImGui::Text("TICK : %lld", ticks);
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
static char buffer[2000];
|
||||||
|
static char addressString[5];
|
||||||
|
static unsigned long int address = 0xFF00;
|
||||||
|
static bool followPC = true;
|
||||||
|
|
||||||
|
if (show_code_window) {
|
||||||
|
ImGui::Begin("CODE", &show_code_window);
|
||||||
|
if( ImGui::InputTextWithHint("", "address in hex", addressString, IM_ARRAYSIZE(addressString))) {
|
||||||
|
address = strtoul(addressString, NULL, 16);
|
||||||
|
cpu->getCode(address, buffer, 2000, 20);
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Checkbox("PC", &followPC);
|
||||||
|
if (followPC)
|
||||||
|
cpu->getCode(cpu->getPC(), buffer, 2000, 20);
|
||||||
|
ImGui::Text("%s", buffer);
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_editor_window) {
|
||||||
|
ImGui::Begin("EDITOR", &show_editor_window, ImGuiWindowFlags_HorizontalScrollbar);
|
||||||
|
ImGui::SetWindowSize(ImVec2(100, 200), ImGuiCond_FirstUseEver);
|
||||||
|
ImGui::Separator();
|
||||||
|
if (ImGui::Button("NEW & RUN SELECTION")) {
|
||||||
|
if (editor.HasSelection()) {
|
||||||
|
std::string program = "NEW\n";
|
||||||
|
program += editor.GetSelectedText();
|
||||||
|
program += "\nRUN\n";
|
||||||
|
int c = 0;
|
||||||
|
while (program[c]) { // all chars until ascii NUL
|
||||||
|
mmu->KBD = program[c++] | 0x80; // set bit7
|
||||||
|
if (mmu->KBD == 0x8A) mmu->KBD = 0x8D; // translate Line Feed to Carriage Ret
|
||||||
|
cpu->exec(500000); // give cpu (and applesoft) some cycles to process each char
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("PASTE SELECTION")) {
|
||||||
|
if (editor.HasSelection()) {
|
||||||
|
std::string program = "\n";
|
||||||
|
program += editor.GetSelectedText();
|
||||||
|
program += "\n";
|
||||||
|
int c = 0;
|
||||||
|
while (program[c]) { // all chars until ascii NUL
|
||||||
|
mmu->KBD = program[c++] | 0x80; // set bit7
|
||||||
|
if (mmu->KBD == 0x8A) mmu->KBD = 0x8D; // translate Line Feed to Carriage Ret
|
||||||
|
cpu->exec(500000); // give cpu (and applesoft) some cycles to process each char
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("SEND RESET"))
|
||||||
|
cpu->RST();
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
auto cpos = editor.GetCursorPosition();
|
||||||
|
ImGui::Text("%4d/%-4d %4d lines | %s | %s | %s | %s",
|
||||||
|
cpos.mLine + 1,
|
||||||
|
cpos.mColumn + 1,
|
||||||
|
editor.GetTotalLines(),
|
||||||
|
editor.IsOverwrite() ? "Ovr" : "Ins",
|
||||||
|
editor.CanUndo() ? "*" : " ",
|
||||||
|
editor.GetLanguageDefinition().mName.c_str(),
|
||||||
|
fileToEdit.c_str());
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
editor.Render("TextEditor");
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_crt_window) {
|
||||||
|
ImGui::Begin("CRT", &show_crt_window);
|
||||||
|
// Adjust the window to the image
|
||||||
|
auto image_size = ImVec2(280 * screenScale, 192 * screenScale);
|
||||||
|
ImGui::SetWindowSize(ImVec2(280 * screenScale + 16, 192 * screenScale + 50));
|
||||||
|
// Draw image
|
||||||
|
ImGui::Image((void*)((intptr_t)screenTexture), image_size, ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(0,0,0,0));
|
||||||
|
// get inputs
|
||||||
|
CRT_is_focused = ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows);
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Gui::render() {
|
||||||
|
// crt
|
||||||
|
if (video->gfxmode == 80) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, screenTexture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 560, 384, 0, GL_RGBA, GL_UNSIGNED_BYTE, video->screenPixels80);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, screenTexture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 280, 192, 0, GL_RGBA, GL_UNSIGNED_BYTE, video->screenPixels);
|
||||||
|
}
|
||||||
|
// RAM heatmap
|
||||||
|
glBindTexture(GL_TEXTURE_2D, ramHeatmapTexture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, video->ramHeatmap);
|
||||||
|
|
||||||
|
// AUX heatmap
|
||||||
|
glBindTexture(GL_TEXTURE_2D, auxHeatmapTexture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, video->auxHeatmap);
|
||||||
|
|
||||||
|
// Rendering
|
||||||
|
ImGui::Render();
|
||||||
|
|
||||||
|
glViewport(0, 0, (int)ImGui::GetIO().DisplaySize.x, (int)ImGui::GetIO().DisplaySize.y);
|
||||||
|
|
||||||
|
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
SDL_GL_SwapWindow(wdo);
|
||||||
|
|
||||||
|
if (++frameNumber >= 60) frameNumber = 0; // reset to zero every second
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Gui::~Gui() {
|
||||||
|
ImGui_ImplOpenGL2_Shutdown();
|
||||||
|
ImGui_ImplSDL2_Shutdown();
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
SDL_GL_DeleteContext(gl_context);
|
||||||
|
SDL_DestroyWindow(wdo);
|
||||||
|
SDL_AudioQuit();
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
91
gui.h
Normal file
91
gui.h
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GUI_H
|
||||||
|
#define _GUI_H
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_impl_sdl.h"
|
||||||
|
#include "imgui_impl_opengl2.h"
|
||||||
|
#include "imfilebrowser.h"
|
||||||
|
#include "imgui_memory_editor.h"
|
||||||
|
#include "TextEditor.h"
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <SDL_opengl.h>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
class Gui {
|
||||||
|
public:
|
||||||
|
int fps;
|
||||||
|
unsigned int frameNumber;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool show_about_window;
|
||||||
|
bool show_help_window;
|
||||||
|
bool CRT_is_focused;
|
||||||
|
bool show_crt_window;
|
||||||
|
bool show_control_window;
|
||||||
|
bool show_disks_window;
|
||||||
|
bool show_info_window;
|
||||||
|
bool show_cpu_window;
|
||||||
|
bool show_code_window;
|
||||||
|
bool show_pageZero_window;
|
||||||
|
bool show_stack_window;
|
||||||
|
bool show_ram_window;
|
||||||
|
bool show_aux_window;
|
||||||
|
bool show_rom_window;
|
||||||
|
bool show_editor_window;
|
||||||
|
bool show_ramHeatmap_window;
|
||||||
|
bool show_auxHeatmap_window;
|
||||||
|
|
||||||
|
ImVec4 clear_color;
|
||||||
|
uint32_t screenTexture;
|
||||||
|
uint32_t ramHeatmapTexture;
|
||||||
|
uint32_t auxHeatmapTexture;
|
||||||
|
|
||||||
|
SDL_Window* wdo;
|
||||||
|
float screenScale;
|
||||||
|
SDL_GLContext gl_context;
|
||||||
|
|
||||||
|
TextEditor editor;
|
||||||
|
std::string fileToEdit;
|
||||||
|
ImGui::FileBrowser fileDialog1;
|
||||||
|
ImGui::FileBrowser fileDialog2;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Gui();
|
||||||
|
~Gui();
|
||||||
|
void getInputs();
|
||||||
|
int update();
|
||||||
|
int newFrame();
|
||||||
|
int render();
|
||||||
|
int release();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
95
imgui.ini
Normal file
95
imgui.ini
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
[Window][Debug##Default]
|
||||||
|
Pos=579,238
|
||||||
|
Size=476,315
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][RAM]
|
||||||
|
Pos=8,424
|
||||||
|
Size=546,155
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][ROM]
|
||||||
|
Pos=8,741
|
||||||
|
Size=546,150
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][AUX]
|
||||||
|
Pos=8,583
|
||||||
|
Size=546,153
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][STACK]
|
||||||
|
Pos=8,140
|
||||||
|
Size=512,278
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][PAGE ZERO]
|
||||||
|
Pos=39,24
|
||||||
|
Size=513,278
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][INFO]
|
||||||
|
Pos=859,464
|
||||||
|
Size=247,427
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][REGISTERS]
|
||||||
|
Pos=1111,492
|
||||||
|
Size=216,71
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][CODE]
|
||||||
|
Pos=1112,571
|
||||||
|
Size=218,320
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][HELP]
|
||||||
|
Pos=319,106
|
||||||
|
Size=444,407
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][ABOUT]
|
||||||
|
Pos=234,380
|
||||||
|
Size=311,129
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][CRT]
|
||||||
|
Pos=561,23
|
||||||
|
Size=576,434
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][RAM HEATMAP]
|
||||||
|
Pos=561,466
|
||||||
|
Size=289,203
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][AUX HEATMAP]
|
||||||
|
Pos=559,681
|
||||||
|
Size=295,210
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][EDITOR]
|
||||||
|
Pos=1142,23
|
||||||
|
Size=550,461
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][CONTROLS]
|
||||||
|
Pos=1334,492
|
||||||
|
Size=359,206
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][DISK ][]
|
||||||
|
Pos=1334,708
|
||||||
|
Size=357,183
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][Insert floppy into drive #2##filebrowser_2012684434080]
|
||||||
|
Pos=500,225
|
||||||
|
Size=700,450
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][Insert floppy into drive #1##filebrowser_2012684433760]
|
||||||
|
Pos=501,225
|
||||||
|
Size=700,450
|
||||||
|
Collapsed=0
|
||||||
|
|
54
imguiTheme.h
Normal file
54
imguiTheme.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Setup Dear ImGui style
|
||||||
|
// ImGui::StyleColorsDark();
|
||||||
|
// or create your own :
|
||||||
|
|
||||||
|
ImGuiStyle& style = ImGui::GetStyle();
|
||||||
|
style.Colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_ChildBg] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_PopupBg] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
|
||||||
|
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||||
|
style.Colors[ImGuiCol_FrameBg] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.38f, 0.38f, 0.38f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.67f, 0.67f, 0.67f, 0.39f);
|
||||||
|
style.Colors[ImGuiCol_TitleBg] = ImVec4(0.08f, 0.08f, 0.09f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.28f, 0.28f, 0.29f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
|
||||||
|
style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
|
||||||
|
style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_CheckMark] = ImVec4(0.11f, 0.64f, 0.92f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.11f, 0.64f, 0.92f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.08f, 0.50f, 0.72f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_Button] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.38f, 0.38f, 0.38f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.67f, 0.67f, 0.67f, 0.39f);
|
||||||
|
style.Colors[ImGuiCol_Header] = ImVec4(0.22f, 0.22f, 0.22f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.67f, 0.67f, 0.67f, 0.39f);
|
||||||
|
style.Colors[ImGuiCol_Separator] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
|
||||||
|
style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.41f, 0.42f, 0.44f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_SeparatorActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
||||||
|
style.Colors[ImGuiCol_ResizeGrip] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||||
|
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.29f, 0.30f, 0.31f, 0.67f);
|
||||||
|
style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
||||||
|
style.Colors[ImGuiCol_Tab] = ImVec4(0.08f, 0.08f, 0.09f, 0.83f);
|
||||||
|
style.Colors[ImGuiCol_TabHovered] = ImVec4(0.33f, 0.34f, 0.36f, 0.83f);
|
||||||
|
style.Colors[ImGuiCol_TabActive] = ImVec4(0.23f, 0.23f, 0.24f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_TabUnfocused] = ImVec4(0.08f, 0.08f, 0.09f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
|
||||||
|
style.Colors[ImGuiCol_DragDropTarget] = ImVec4(0.11f, 0.64f, 0.92f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
|
||||||
|
style.Colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
|
||||||
|
style.Colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
|
||||||
|
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
|
||||||
|
style.GrabRounding = style.FrameRounding = 2.0f;
|
83
main.cpp
Normal file
83
main.cpp
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "reinette.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// global variables - TODO create a config file and make changes persistant
|
||||||
|
bool muted = false;
|
||||||
|
int volume = 10;
|
||||||
|
bool running = true;
|
||||||
|
bool paused = false;
|
||||||
|
float speed = 1.023f;
|
||||||
|
|
||||||
|
// instanciate all objects, calling their respective constructors
|
||||||
|
Mmu* mmu = new Mmu();
|
||||||
|
puce65c02* cpu = new puce65c02();
|
||||||
|
Video* video = new Video();
|
||||||
|
Disk* disk = new Disk();
|
||||||
|
Speaker* speaker = new Speaker();
|
||||||
|
Paddles* paddles = new Paddles();
|
||||||
|
Gui* gui = new Gui();
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
cpu->RST();
|
||||||
|
if (argc > 1) disk->load(argv[1], 0); // load .nib in parameter into drive 0
|
||||||
|
uint8_t tries = 0; // for disk ][ speed-up
|
||||||
|
|
||||||
|
// main loop
|
||||||
|
while (running) {
|
||||||
|
|
||||||
|
gui->getInputs();
|
||||||
|
paddles->update();
|
||||||
|
gui->newFrame();
|
||||||
|
|
||||||
|
if (!paused) {
|
||||||
|
// dirty hack - fix soon TODO - a better VERTBLANK ... - won't work when stepping through instructions
|
||||||
|
mmu->VERTBLANK = true;
|
||||||
|
cpu->exec((unsigned long long int)(1000000.0 * speed / gui->fps*0.1f)); // the apple II is clocked at 1023000.0 Hhz
|
||||||
|
mmu->VERTBLANK = false;
|
||||||
|
cpu->exec((unsigned long long int)(1000000.0 * speed / gui->fps*0.9f)); // the apple II is clocked at 1023000.0 Hhz
|
||||||
|
|
||||||
|
while (disk->unit[disk->curDrv].motorOn && ++tries) // until motor is off or i reaches 255+1=0
|
||||||
|
cpu->exec(5000); // speed up drive access artificially
|
||||||
|
video->update(); // won't update the video if paused
|
||||||
|
}
|
||||||
|
else if (cpu->state == step) { // paused and user pressed debugNumber
|
||||||
|
cpu->exec(1);
|
||||||
|
cpu->state = run; // still paused
|
||||||
|
video->update(); // update the video after each instruction ...
|
||||||
|
}
|
||||||
|
|
||||||
|
gui->update();
|
||||||
|
gui->render();
|
||||||
|
|
||||||
|
} // while (running)
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
// at this point all destructors were called, properly closing open files and releasing other ressources
|
||||||
|
}
|
620
mmu.cpp
Normal file
620
mmu.cpp
Normal file
@ -0,0 +1,620 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// code is not iso compliant : abuse of range expressions in switch statements
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "reinette.h"
|
||||||
|
|
||||||
|
//========================================== MEMORY MAPPED SOFT SWITCHES HANDLER
|
||||||
|
|
||||||
|
uint8_t Mmu::softSwitches(uint16_t address, uint8_t value, bool WRT) {
|
||||||
|
static uint8_t dLatch = 0; // disk ][ I/O register
|
||||||
|
|
||||||
|
switch (address) {
|
||||||
|
|
||||||
|
// MEMORY MANAGEMENT (and KEYBOARD)
|
||||||
|
case 0xC000: if (WRT) STORE80 = false; else return KBD; break; // cause PAGE2 on to select AUX -- KEYBOARD return key code - if hi-bit is set the key code (7 lo-bits) is valid
|
||||||
|
case 0xC001: if (WRT) STORE80 = true; break; // allow PAGE2 to switch MAIN / AUX
|
||||||
|
case 0xC002: if (WRT) RAMRD = false; break; // read from MAIN
|
||||||
|
case 0xC003: if (WRT) RAMRD = true; break; // read from AUX
|
||||||
|
case 0xC004: if (WRT) RAMWRT = false; break; // write to MAIN
|
||||||
|
case 0xC005: if (WRT) RAMWRT = true; break; // write to AUX
|
||||||
|
case 0xC006: if (WRT) INTCXROM = false; break; // set peripheral roms for peripherals ($C100-$CFFF)
|
||||||
|
case 0xC007: if (WRT) INTCXROM = true; break; // set internal rom for peripherals ($C100-$CFFF)
|
||||||
|
case 0xC008: if (WRT) ALTZP = false; break; // MAIN stack & rero page
|
||||||
|
case 0xC009: if (WRT) ALTZP = true; break; // AUX stack & rero page
|
||||||
|
case 0xC00A: if (WRT) SLOTC3ROM = false; break; // ROM in Slot 3
|
||||||
|
case 0xC00B: if (WRT) SLOTC3ROM = true; break; // ROM in AUX Slot
|
||||||
|
case 0xC00C: if (WRT) COL80 = false; break; // 80 COL OFF -> 40 COL
|
||||||
|
case 0xC00D: if (WRT) COL80 = true; break; // 80 COL ON
|
||||||
|
case 0xC00E: if (WRT) ALTCHARSET = false; break; // primary character set
|
||||||
|
case 0xC00F: if (WRT) ALTCHARSET = true; break; // alternate character set
|
||||||
|
case 0xC010: KBD &= 0x7F; return KBD; // KBDSTROBE, clear hi-bit and return key code
|
||||||
|
|
||||||
|
// SOFT SWITCH STATUS FLAGS
|
||||||
|
case 0xC011: return (0x80 * LCBK2);
|
||||||
|
case 0xC012: return (0x80 * LCRD);
|
||||||
|
case 0xC013: return (0x80 * RAMRD); // 0x80 if reads from AUX
|
||||||
|
case 0xC014: return (0x80 * RAMWRT); // 0x80 if writes from AUX
|
||||||
|
case 0xC015: return (0x80 * INTCXROM);
|
||||||
|
case 0xC016: return (0x80 * ALTZP); // 0x80 if using stack and zero page from AUX
|
||||||
|
case 0xC017: return (0x80 * SLOTC3ROM);
|
||||||
|
case 0xC018: return (0x80 * STORE80); // do we store 80 col page 2 on MAIN or AUX
|
||||||
|
case 0xC019: return (0x80 * VERTBLANK);
|
||||||
|
|
||||||
|
case 0xC01A: return (0x80 * TEXT); // read text switch
|
||||||
|
case 0xC01B: return (0x80 * MIXED); // read mixed switch
|
||||||
|
case 0xC01C: return (0x80 * PAGE2); // read page 2 switch
|
||||||
|
case 0xC01D: return (0x80 * HIRES); // read HiRes switch
|
||||||
|
case 0xC01E: return (0x80 * ALTCHARSET); // alternate character set ?
|
||||||
|
case 0xC01F: return (0x80 * COL80); // 80 columns on ?
|
||||||
|
|
||||||
|
// SOUND
|
||||||
|
case 0xC020: // TAPEOUT (shall we listen it ? - try SAVE from applesoft)
|
||||||
|
case 0xC030: // SPEAKER
|
||||||
|
case 0xC033: speaker->play(); break; // apple invader uses $C033 to output sound !
|
||||||
|
|
||||||
|
// GAME I/O STROBE OUT
|
||||||
|
case 0xC040: break;
|
||||||
|
|
||||||
|
// VIDEO MODES
|
||||||
|
case 0xC050: TEXT = false; video->clearCache(); break; // set Graphics
|
||||||
|
case 0xC051: TEXT = true; video->clearCache(); break; // set Text
|
||||||
|
case 0xC052: MIXED = false; video->clearCache(); break; // set Mixed to off
|
||||||
|
case 0xC053: MIXED = true; video->clearCache(); break; // set Mixed to on
|
||||||
|
case 0xC054: PAGE2 = false; video->clearCache(); break; // select page 1
|
||||||
|
case 0xC055: PAGE2 = true; video->clearCache(); break; // select page 2
|
||||||
|
case 0xC056: HIRES = false; video->clearCache(); break; // set HiRes to off
|
||||||
|
case 0xC057: HIRES = true; video->clearCache(); break; // set HiRes to on
|
||||||
|
|
||||||
|
// ANNUNCIATORS
|
||||||
|
case 0xC058: if (!IOUDIS) AN0 = false; break; // If IOUDIS off: Annunciator 0 Off
|
||||||
|
case 0xC059: if (!IOUDIS) AN0 = true; break; // If IOUDIS off: Annunciator 0 On
|
||||||
|
case 0xC05A: if (!IOUDIS) AN1 = false; break; // If IOUDIS off: Annunciator 1 Off
|
||||||
|
case 0xC05B: if (!IOUDIS) AN1 = true; break; // If IOUDIS off: Annunciator 1 On
|
||||||
|
case 0xC05C: if (!IOUDIS) AN2 = false; break; // If IOUDIS off: Annunciator 2 Off
|
||||||
|
case 0xC05D: if (!IOUDIS) AN2 = true; break; // If IOUDIS off: Annunciator 2 On
|
||||||
|
case 0xC05E: if (!IOUDIS) AN3 = false; DHIRES = true; break; // If IOUDIS off: Annunciator 3 Off
|
||||||
|
case 0xC05F: if (!IOUDIS) AN3 = true; DHIRES = false; break; // If IOUDIS off: Annunciator 2 On
|
||||||
|
|
||||||
|
// TAPE
|
||||||
|
case 0xC060: break; // TAPE IN
|
||||||
|
|
||||||
|
// PADDLES
|
||||||
|
case 0xC061: return paddles->PB0; // Push Button 0 / Open Apple
|
||||||
|
case 0xC062: return paddles->PB1; // Push Button 1 / Solid Apple
|
||||||
|
case 0xC063: return paddles->PB2; // Push Button 2 / Shift
|
||||||
|
case 0xC064: return paddles->read(0); // Paddle 0
|
||||||
|
case 0xC065: return paddles->read(1); // Paddle 1
|
||||||
|
case 0xC066: return paddles->read(2); // Paddle 2
|
||||||
|
case 0xC067: return paddles->read(3); // Paddle 3
|
||||||
|
case 0xC070: paddles->reset(); break; // paddles timer reset
|
||||||
|
|
||||||
|
// IOUDIS
|
||||||
|
case 0xC07E: if (WRT) IOUDIS = false; else return (0x80 * IOUDIS); break;
|
||||||
|
case 0xC07F: if (WRT) IOUDIS = true; else return (0x80 * DHIRES); break;
|
||||||
|
|
||||||
|
// LANGUAGE CARD (used with MAIN and AUX)
|
||||||
|
case 0xC080:
|
||||||
|
case 0xC084: LCBK2 = 1; LCRD = 1; LCWR = 0; LCWFF = 0; break; // LC2RD
|
||||||
|
case 0xC081:
|
||||||
|
case 0xC085: LCBK2 = 1; LCRD = 0; LCWR |= LCWFF; LCWFF = !WRT; break; // LC2WR
|
||||||
|
case 0xC082:
|
||||||
|
case 0xC086: LCBK2 = 1; LCRD = 0; LCWR = 0; LCWFF = 0; break; // ROMONLY2
|
||||||
|
case 0xC083:
|
||||||
|
case 0xC087: LCBK2 = 1; LCRD = 1; LCWR |= LCWFF; LCWFF = !WRT; break; // LC2RW
|
||||||
|
case 0xC088:
|
||||||
|
case 0xC08C: LCBK2 = 0; LCRD = 1; LCWR = 0; LCWFF = 0; break; // LC1RD
|
||||||
|
case 0xC089:
|
||||||
|
case 0xC08D: LCBK2 = 0; LCRD = 0; LCWR |= LCWFF; LCWFF = !WRT; break; // LC1WR
|
||||||
|
case 0xC08A:
|
||||||
|
case 0xC08E: LCBK2 = 0; LCRD = 0; LCWR = 0; LCWFF = 0; break; // ROMONLY1
|
||||||
|
case 0xC08B:
|
||||||
|
case 0xC08F: LCBK2 = 0; LCRD = 1; LCWR |= LCWFF; LCWFF = !WRT; break; // LC1RW
|
||||||
|
|
||||||
|
// SLOT 1
|
||||||
|
case 0xC090 ... 0xC09F: break;
|
||||||
|
|
||||||
|
// SLOT 2
|
||||||
|
case 0xC0A0 ... 0xC0AF: break;
|
||||||
|
|
||||||
|
// SLOT 3
|
||||||
|
case 0xC0B0 ... 0xC0BF: break;
|
||||||
|
|
||||||
|
// SLOT 4
|
||||||
|
case 0xC0C0 ... 0xC0CF: break;
|
||||||
|
|
||||||
|
// SLOT 5
|
||||||
|
case 0xC0D0 ... 0xC0DF: break;
|
||||||
|
|
||||||
|
// SLOT 6 DISK ][
|
||||||
|
case 0xC0E0 ... 0xC0E7: disk->stepMotor(address); break; // MOVE DRIVE HEAD
|
||||||
|
case 0xC0E8: disk->unit[disk->curDrv].motorOn = false; break; // MOTOROFF
|
||||||
|
case 0xC0E9: disk->unit[disk->curDrv].motorOn = true; break; // MOTORON
|
||||||
|
case 0xC0EA: disk->setDrv(0); break; // DRIVE0EN
|
||||||
|
case 0xC0EB: disk->setDrv(1); break; // DRIVE1EN
|
||||||
|
case 0xC0EC: // Shift Data Latch
|
||||||
|
if (disk->unit[disk->curDrv].writeMode) // writting
|
||||||
|
disk->unit[disk->curDrv].data[disk->unit[disk->curDrv].track * 0x1A00 + disk->unit[disk->curDrv].nibble] = dLatch; // good luck gcc
|
||||||
|
else // reading
|
||||||
|
dLatch = disk->unit[disk->curDrv].data[disk->unit[disk->curDrv].track * 0x1A00 + disk->unit[disk->curDrv].nibble]; // easy peasy
|
||||||
|
disk->unit[disk->curDrv].nibble = (disk->unit[disk->curDrv].nibble + 1) % 0x1A00; // turn floppy of 1 nibble
|
||||||
|
return dLatch;
|
||||||
|
case 0xC0ED: dLatch = value; break; // Load Data Latch
|
||||||
|
case 0xC0EE: // latch for READ
|
||||||
|
disk->unit[disk->curDrv].writeMode = false;
|
||||||
|
return disk->unit[disk->curDrv].readOnly ? 0x80 : 0; // check protection
|
||||||
|
case 0xC0EF: disk->unit[disk->curDrv].writeMode = true; break; // latch for WRITE
|
||||||
|
|
||||||
|
// SLOT 7
|
||||||
|
case 0xC0F0 ... 0xC0FF: break;
|
||||||
|
|
||||||
|
}
|
||||||
|
return cpu->ticks%256; // catch all, gives a floating value
|
||||||
|
}
|
||||||
|
|
||||||
|
//================================================================== MEMORY READ
|
||||||
|
|
||||||
|
uint8_t Mmu::readMem(uint16_t address) {
|
||||||
|
|
||||||
|
switch (address) {
|
||||||
|
case 0x0000 ... 0x01FF: // STACK and Zero Page in AUX or MAIN
|
||||||
|
if (ALTZP) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return aux[address];
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return ram[address];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0200 ... 0x03FF: // MAIN or AUX
|
||||||
|
if (RAMRD) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return aux[address];
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return ram[address];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0400 ... 0x07FF: // TEXT PAGE 1 in AUX or MAIN
|
||||||
|
if (STORE80) {
|
||||||
|
if (PAGE2) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return aux[address];
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return ram[address];
|
||||||
|
}
|
||||||
|
if (RAMRD) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return aux[address];
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return ram[address];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0800 ... 0x0BFF: // TEXT PAGE 2 in AUX or MAIN
|
||||||
|
if (RAMRD) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return aux[address];
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return ram[address];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0C00 ... 0x1FFF: // AUX or MAIN
|
||||||
|
if (RAMRD) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return aux[address];
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return ram[address];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x2000 ... 0x3FFF: // HIRES PAGE 1
|
||||||
|
if (STORE80) {
|
||||||
|
if (PAGE2 && HIRES) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return aux[address];
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return ram[address];
|
||||||
|
}
|
||||||
|
if (RAMRD) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return aux[address];
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return ram[address];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x4000 ... 0x5FFF: // HIRES PAGE 2 in AUX or MAIN
|
||||||
|
if (RAMRD) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return aux[address];
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return ram[address];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x6000 ... 0xBFFF: // AUX or MAIN
|
||||||
|
if (RAMRD) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return aux[address];
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return ram[address];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC000 ... 0xC0FF: // SOFT SWITCHES
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return softSwitches(address, 0, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC100 ... 0xC1FF: // SLOT 1 ROM or ROM
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
if (INTCXROM) {
|
||||||
|
return rom[address - ROMSTART];
|
||||||
|
}
|
||||||
|
return sl1[address - SL1START];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC200 ... 0xC2FF: // SLOT 2 ROM or ROM
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
if (INTCXROM) {
|
||||||
|
return rom[address - ROMSTART];
|
||||||
|
}
|
||||||
|
return sl2[address - SL2START];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC300 ... 0xC3FF: // SLOT 3 ROM or ROM : video
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
if (INTCXROM || !SLOTC3ROM) {
|
||||||
|
return rom[address - ROMSTART];
|
||||||
|
}
|
||||||
|
return sl3[address - SL3START];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC400 ... 0xC4FF: // SLOT 4 ROM or ROM
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
if (INTCXROM) {
|
||||||
|
return rom[address - ROMSTART];
|
||||||
|
}
|
||||||
|
return sl4[address - SL4START];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC500 ... 0xC5FF: // SLOT 5 ROM or ROM
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
if (INTCXROM) {
|
||||||
|
return rom[address - ROMSTART];
|
||||||
|
}
|
||||||
|
return sl5[address - SL5START];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC600 ... 0xC6FF: // SLOT 6 ROM : DISK ][ or ROM
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
if (INTCXROM) {
|
||||||
|
return rom[address - ROMSTART];
|
||||||
|
}
|
||||||
|
return sl6[address - SL6START];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC700 ... 0xC7FF: // SLOT 7 ROM or ROM
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
if (INTCXROM) {
|
||||||
|
return rom[address - ROMSTART];
|
||||||
|
}
|
||||||
|
return sl7[address - SL7START];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC800 ... 0xCFFE: // SHARED EXANSION SLOTS ROM AREA or ROM
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
if (INTCXROM || !SLOTC3ROM) {
|
||||||
|
return rom[address - ROMSTART];
|
||||||
|
}
|
||||||
|
return slrom[(address & 0x0F00) >> 2 & 0xF][address - SLROMSTART];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCFFF: // turn off all slots expansion ROMs - TODO : NEEDS REWORK
|
||||||
|
disk->unit[disk->curDrv].motorOn = false;
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xD000 ... 0xDFFF: // ROM, MAIN-BK1, RAM-BK2, AUX-BK1 or AUX-BK2
|
||||||
|
if (LCRD) {
|
||||||
|
if (LCBK2) {
|
||||||
|
if (ALTZP) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return auxbk2[address - BK2START]; // AUX Bank 2
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return rambk2[address - BK2START]; // MAIN Bank 2
|
||||||
|
}
|
||||||
|
if (ALTZP) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return auxlgc[address - LGCSTART]; // AUX Bank 1
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return ramlgc[address - LGCSTART]; // MAIN Bank 1
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return rom[address - ROMSTART]; // ROM
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE000 ... 0xFFFF: // ROM, MAIN-BK1 or AUX-BK1
|
||||||
|
if (LCRD) {
|
||||||
|
if (ALTZP) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return auxlgc[address - LGCSTART]; // AUX Bank 1
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return ramlgc[address - LGCSTART]; // MAIN Bank 1
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF00FF00;
|
||||||
|
return rom[address - ROMSTART]; // ROM
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return cpu->ticks%256; // returns a floating value
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//================================================================= MEMORY WRITE
|
||||||
|
|
||||||
|
void Mmu::writeMem(uint16_t address, uint8_t value) {
|
||||||
|
|
||||||
|
switch (address) {
|
||||||
|
case 0x0000 ... 0x01FF: // STACK and Zero Page in AUX or MAIN
|
||||||
|
if (ALTZP) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF0000FF;
|
||||||
|
aux[address] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
ram[address] = value;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0200 ... 0x03FF: // MAIN or AUX
|
||||||
|
if (RAMWRT) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF0000FF;
|
||||||
|
aux[address] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
ram[address] = value;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0400 ... 0x07FF: // TEXT PAGE 1 in AUX or MAIN
|
||||||
|
if (STORE80) {
|
||||||
|
if (PAGE2) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF0000FF;
|
||||||
|
aux[address] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
ram[address] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (RAMWRT) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF0000FF;
|
||||||
|
aux[address] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
ram[address] = value;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0800 ... 0x0BFF: // TEXT PAGE 2 in AUX or MAIN
|
||||||
|
if (RAMWRT) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF0000FF;
|
||||||
|
aux[address] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
ram[address] = value;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0C00 ... 0x1FFF: // MAIN or AUX
|
||||||
|
if (RAMWRT) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF0000FF;
|
||||||
|
aux[address] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
ram[address] = value;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x2000 ... 0x3FFF: // HIRES PAGE 1
|
||||||
|
if (STORE80) {
|
||||||
|
if (PAGE2 && HIRES) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF0000FF;
|
||||||
|
aux[address] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
ram[address] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (RAMWRT) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF0000FF;
|
||||||
|
aux[address] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
ram[address] = value;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x4000 ... 0x5FFF: // HIRES PAGE 2 in AUX or MAIN
|
||||||
|
if (RAMWRT) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF0000FF;
|
||||||
|
aux[address] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
ram[address] = value;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x6000 ... 0xBFFF: // AUX or MAIN
|
||||||
|
if (RAMWRT) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF0000FF;
|
||||||
|
aux[address] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
ram[address] = value;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC000 ... 0xC0FF: // softSwitches
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
softSwitches(address, 0, true);
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC100 ... 0xCFFE: // readonly area
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCFFF: // turn off all slots expansion ROMs - NEEDS REWORK soft switch ?
|
||||||
|
disk->unit[disk->curDrv].motorOn = false;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xD000 ... 0xDFFF: // ROM, MAIN-BK1, RAM-BK2, AUX-BK1 or AUX-BK2
|
||||||
|
if (LCWR) {
|
||||||
|
if (LCBK2) {
|
||||||
|
if (ALTZP) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF0000FF;
|
||||||
|
auxbk2[address - BK2START] = value; // AUX Bank 2
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
rambk2[address - BK2START] = value; // MAIN Bank 2
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ALTZP) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF0000FF;
|
||||||
|
auxlgc[address - LGCSTART] = value; // AUX Bank 1
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
ramlgc[address - LGCSTART] = value; // MAIN Bank 1
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE000 ... 0xFFFF: // ROM, MAIN-BK1 or AUX-BK1
|
||||||
|
if (LCWR) {
|
||||||
|
if (ALTZP) {
|
||||||
|
video->auxHeatmap[address] |= 0xFF0000FF;
|
||||||
|
auxlgc[address - LGCSTART] = value; // AUX Bank 1
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
ramlgc[address - LGCSTART] = value; // MAIN Bank 1
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video->ramHeatmap[address] |= 0xFF0000FF;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Mmu::Mmu() {
|
||||||
|
// TODO : give user the choice of the rom version
|
||||||
|
|
||||||
|
// pick one ROM file
|
||||||
|
// FILE* f = fopen("rom/appleII.rom", "rb"); // load the Apple II ROM
|
||||||
|
// FILE* f = fopen("rom/appleII+.rom", "rb"); // load the Apple II+ ROM
|
||||||
|
// FILE* f = fopen("rom/appleIIe.rom", "rb"); // load the Apple IIe ROM
|
||||||
|
FILE* f = fopen("rom/appleIIee.rom", "rb"); // load the Apple IIee ROM
|
||||||
|
fread(rom, 1, ROMSIZE, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
// load DISK][ PROM
|
||||||
|
f = fopen("rom/diskII.rom", "rb"); // load the P5A disk ][ PROM
|
||||||
|
fread(sl6, 1, 256, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Mmu::~Mmu() {
|
||||||
|
// release the memory arrays ?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mmu::init() {
|
||||||
|
KBD = 0; // $C000, $C010 ascii value of keyboard input
|
||||||
|
PAGE2 = false; // $C054 PAGE1 / $C055 PAGE2
|
||||||
|
TEXT = true; // $C050 CLRTEXT / $C051 SETTEXT
|
||||||
|
MIXED = false; // $C052 CLRMIXED / $C053 SETMIXED
|
||||||
|
HIRES = false; // $C056 GR / $C057 HGR
|
||||||
|
DHIRES = false; // 0xC05E / 0xC05F DOUBLE HIRES
|
||||||
|
COL80 = false; // 80 COLUMNS
|
||||||
|
ALTCHARSET = false;
|
||||||
|
LCWR = true; // Language Card writable
|
||||||
|
LCRD = false; // Language Card readable
|
||||||
|
LCBK2 = true; // Language Card bank 2 enabled
|
||||||
|
LCWFF = false; // Language Card pre-write flip flop
|
||||||
|
AN0 = false;
|
||||||
|
AN1 = false;
|
||||||
|
AN2 = true;
|
||||||
|
AN3 = true;
|
||||||
|
|
||||||
|
RAMRD = false;
|
||||||
|
RAMWRT = false;
|
||||||
|
ALTZP = false;
|
||||||
|
STORE80 = false;
|
||||||
|
|
||||||
|
INTCXROM = false; // use slots roms
|
||||||
|
SLOTC3ROM = false; // use AUX Slot rom
|
||||||
|
|
||||||
|
IOUDIS = false;
|
||||||
|
VERTBLANK = true;
|
||||||
|
|
||||||
|
memset(ram, 0, sizeof(ram)); // 48K of MAIN in $000-$BFFF
|
||||||
|
memset(aux, 0, sizeof(aux)); // 48K of AUX memory
|
||||||
|
memset(ramlgc, 0, sizeof(ramlgc)); // MAIN Language Card 12K in $D000-$FFFF
|
||||||
|
memset(rambk2, 0, sizeof(rambk2)); // MAIN bank 2 of Language Card 4K in $D000-$DFFF
|
||||||
|
memset(auxlgc, 0, sizeof(auxlgc)); // AUX Language Card 12K in $D000-$FFFF
|
||||||
|
memset(auxbk2, 0, sizeof(auxbk2)); // AUX bank 2 of Language Card 4K in $D000-$DFFF
|
||||||
|
|
||||||
|
// dirty hacks - fix when I know why
|
||||||
|
ram[0x4D] = 0xAA; // Joust won't work if this memory location equals zero
|
||||||
|
ram[0xD0] = 0xAA; // Planetoids won't work if this memory location equals zero
|
||||||
|
}
|
135
mmu.h
Normal file
135
mmu.h
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MEMORY_H
|
||||||
|
#define _MEMORY_H
|
||||||
|
|
||||||
|
// memory layout
|
||||||
|
#define RAMSIZE 0xC000 // 48K
|
||||||
|
#define AUXSIZE 0xC000 // 48K
|
||||||
|
|
||||||
|
// Apple II and II+
|
||||||
|
// #define ROMSTART 0xD000
|
||||||
|
// #define ROMSIZE 0x3000 // 12K
|
||||||
|
|
||||||
|
// Apple IIe and IIee
|
||||||
|
#define ROMSTART 0xC000
|
||||||
|
#define ROMSIZE 0x4000 // 16K
|
||||||
|
|
||||||
|
// language card
|
||||||
|
#define LGCSTART 0xD000
|
||||||
|
#define LGCSIZE 0x3000
|
||||||
|
#define BK2START 0xD000
|
||||||
|
#define BK2SIZE 0x1000
|
||||||
|
|
||||||
|
// slot 1,
|
||||||
|
#define SL1START 0xC100
|
||||||
|
#define SL1SIZE 0x0100
|
||||||
|
// slot 2
|
||||||
|
#define SL2START 0xC200
|
||||||
|
#define SL2SIZE 0x0100
|
||||||
|
// slot 3
|
||||||
|
#define SL3START 0xC300
|
||||||
|
#define SL3SIZE 0x0100
|
||||||
|
// slot 4
|
||||||
|
#define SL4START 0xC400
|
||||||
|
#define SL4SIZE 0x0100
|
||||||
|
// slot 5
|
||||||
|
#define SL5START 0xC500
|
||||||
|
#define SL5SIZE 0x0100
|
||||||
|
// slot 6, diskII
|
||||||
|
#define SL6START 0xC600
|
||||||
|
#define SL6SIZE 0x0100
|
||||||
|
// slot 7
|
||||||
|
#define SL7START 0xC700
|
||||||
|
#define SL7SIZE 0x0100
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define SLROMSTART 0xC800 // peripheral-card expansion ROMs -
|
||||||
|
#define SLROMSIZE 0xC800
|
||||||
|
|
||||||
|
|
||||||
|
class Mmu {
|
||||||
|
public:
|
||||||
|
uint8_t ram[RAMSIZE]; // 48K of MAIN in $000-$BFFF
|
||||||
|
uint8_t ramlgc[LGCSIZE]; // MAIN Language Card 12K in $D000-$FFFF
|
||||||
|
uint8_t rambk2[BK2SIZE]; // MAIN bank 2 of Language Card 4K in $D000-$DFFF
|
||||||
|
|
||||||
|
uint8_t aux[AUXSIZE]; // 48K of AUX memory
|
||||||
|
uint8_t auxlgc[LGCSIZE]; // AUX Language Card 12K in $D000-$FFFF
|
||||||
|
uint8_t auxbk2[BK2SIZE]; // AUX bank 2 of Language Card 4K in $D000-$DFFF
|
||||||
|
|
||||||
|
uint8_t rom[ROMSIZE]; // 16K of rom in $C000-$FFFF
|
||||||
|
|
||||||
|
uint8_t sl1[SL1SIZE];
|
||||||
|
uint8_t sl2[SL2SIZE];
|
||||||
|
uint8_t sl3[SL3SIZE];
|
||||||
|
uint8_t sl5[SL5SIZE];
|
||||||
|
uint8_t sl4[SL4SIZE];
|
||||||
|
uint8_t sl6[SL6SIZE]; // P5A disk ][ PROM in slot 6
|
||||||
|
uint8_t sl7[SL7SIZE];
|
||||||
|
uint8_t slrom[8][SLROMSIZE]; // 7x peripheral-card expansion ROMs ( index 0 is not used)
|
||||||
|
|
||||||
|
uint8_t KBD; // $C000, $C010 ascii value of keyboard input
|
||||||
|
|
||||||
|
bool PAGE2; // $C054 PAGE1 / $C055 PAGE2
|
||||||
|
bool TEXT; // $C050 CLRTEXT / $C051 SETTEXT
|
||||||
|
bool MIXED; // $C052 CLRMIXED / $C053 SETMIXED
|
||||||
|
bool HIRES; // $C056 GR / $C057 HGR
|
||||||
|
bool DHIRES; // 0xC05E / 0xC05F DOUBLE HIRES
|
||||||
|
bool COL80; // 80 COLUMNS
|
||||||
|
bool ALTCHARSET;
|
||||||
|
|
||||||
|
bool LCWR ; // Language Card writable
|
||||||
|
bool LCRD ; // Language Card readable
|
||||||
|
bool LCBK2; // Language Card bank 2 enabled
|
||||||
|
bool LCWFF; // Language Card pre-write flip flop
|
||||||
|
|
||||||
|
bool AN0;
|
||||||
|
bool AN1;
|
||||||
|
bool AN2;
|
||||||
|
bool AN3;
|
||||||
|
|
||||||
|
bool RAMRD;
|
||||||
|
bool RAMWRT;
|
||||||
|
bool ALTZP;
|
||||||
|
bool STORE80;
|
||||||
|
bool INTCXROM;
|
||||||
|
bool SLOTC3ROM;
|
||||||
|
bool IOUDIS;
|
||||||
|
bool VERTBLANK;
|
||||||
|
|
||||||
|
Mmu();
|
||||||
|
~Mmu();
|
||||||
|
void init();
|
||||||
|
uint8_t readMem(uint16_t address);
|
||||||
|
void writeMem(uint16_t address, uint8_t value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t softSwitches(uint16_t address, uint8_t value, bool WRT);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
1
nib/128K/Bad Dudes (1988)(Data East - Quicksilver Software)(Disk 1 of 2).nib
generated
Normal file
1
nib/128K/Bad Dudes (1988)(Data East - Quicksilver Software)(Disk 1 of 2).nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/128K/Death Sword (19xx)(Palace)[cr].nib
generated
Normal file
1
nib/128K/Death Sword (19xx)(Palace)[cr].nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/128K/Renegade (1989)(Novalogic)(Disk 1 of 2).nib
generated
Normal file
1
nib/128K/Renegade (1989)(Novalogic)(Disk 1 of 2).nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/128K/Robocop (1988)(Data East)(Disk 1 of 2).nib
generated
Normal file
1
nib/128K/Robocop (1988)(Data East)(Disk 1 of 2).nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/Lode Runner (Changable Params).nib
generated
Normal file
1
nib/Lode Runner (Changable Params).nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/Ms. Pac-Man.nib
generated
Normal file
1
nib/Ms. Pac-Man.nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/demo/appleii-megademo.nib
generated
Normal file
1
nib/demo/appleii-megademo.nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/demo/fakepal128.nib
generated
Normal file
1
nib/demo/fakepal128.nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/demo/oldskool.nib
generated
Normal file
1
nib/demo/oldskool.nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/demo/outline2021.nib
generated
Normal file
1
nib/demo/outline2021.nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/demo/sierzoom128.nib
generated
Normal file
1
nib/demo/sierzoom128.nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/diag/A2eDiagnostics_v2.1.nib
generated
Normal file
1
nib/diag/A2eDiagnostics_v2.1.nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/dolores/DLAMPCORE11.1.nib
generated
Normal file
1
nib/dolores/DLAMPCORE11.1.nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/dolores/DOLORES12_0_beta.nib
generated
Normal file
1
nib/dolores/DOLORES12_0_beta.nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/dolores/LODELO33.nib
generated
Normal file
1
nib/dolores/LODELO33.nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/dos/DOS3.3 Blank.nib
generated
Normal file
1
nib/dos/DOS3.3 Blank.nib
generated
Normal file
File diff suppressed because one or more lines are too long
1
nib/dos/PRODOS-8 v4.0.2 System.nib
generated
Normal file
1
nib/dos/PRODOS-8 v4.0.2 System.nib
generated
Normal file
File diff suppressed because one or more lines are too long
BIN
nib/dos/ProDOS 1.0.1 User's Disk (1983).nib
generated
Normal file
BIN
nib/dos/ProDOS 1.0.1 User's Disk (1983).nib
generated
Normal file
Binary file not shown.
69
paddles.cpp
Normal file
69
paddles.cpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "reinette.h"
|
||||||
|
|
||||||
|
Paddles::Paddles() {
|
||||||
|
PB0 = 0; // $C061 Push Button 0 (bit 7) / Open Apple
|
||||||
|
PB1 = 0; // $C062 Push Button 1 (bit 7) / Solid Apple
|
||||||
|
PB2 = 0; // $C063 Push Button 2 (bit 7) / shift mod !!!
|
||||||
|
GCActionSpeed = 8; // Game Controller speed at which it goes to the edges
|
||||||
|
GCReleaseSpeed = 8; // Game Controller speed at which it returns to center
|
||||||
|
GCCrigger = 0; // $C070 the tick at which the GCs were reseted
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Paddles::reset() {
|
||||||
|
GCC[0] = GCP[0] * GCP[0]; // initialize the countdown for both paddles
|
||||||
|
GCC[1] = GCP[1] * GCP[1]; // to the square of their actuall values (positions)
|
||||||
|
GCC[2] = GCP[2] * GCP[2]; // to the square of their actuall values (positions)
|
||||||
|
GCC[3] = GCP[3] * GCP[3]; // to the square of their actuall values (positions)
|
||||||
|
GCCrigger = cpu->ticks; // records the time this was done
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t Paddles::read(int pdl) {
|
||||||
|
const float GCFreq = 6.6; // the speed at which the GC values decrease
|
||||||
|
|
||||||
|
GCC[pdl] -= (cpu->ticks - GCCrigger) / GCFreq; // decreases the countdown
|
||||||
|
if (GCC[pdl] <= 0) // timeout
|
||||||
|
return GCC[pdl] = 0; // returns 0
|
||||||
|
return 0x80; // not timeout, return something with the MSB set
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Paddles::update() {
|
||||||
|
for (int pdl = 0; pdl < 4; pdl++) { // update the two paddles positions
|
||||||
|
if (GCA[pdl]) { // actively pushing the stick
|
||||||
|
GCP[pdl] += GCD[pdl] * GCActionSpeed;
|
||||||
|
if (GCP[pdl] > 255) GCP[pdl] = 255;
|
||||||
|
if (GCP[pdl] < 0) GCP[pdl] = 0;
|
||||||
|
} else { // the stick returns back to center
|
||||||
|
GCP[pdl] += GCD[pdl] * GCReleaseSpeed;
|
||||||
|
if (GCD[pdl] == 1 && GCP[pdl] > 127) GCP[pdl] = 127;
|
||||||
|
if (GCD[pdl] == -1 && GCP[pdl] < 127) GCP[pdl] = 127;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
paddles.h
Normal file
53
paddles.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PADDLES_H__
|
||||||
|
#define __PADDLES_H__
|
||||||
|
|
||||||
|
class Paddles {
|
||||||
|
public:
|
||||||
|
uint8_t PB0; // $C061 Push Button 0 (bit 7) / Open Apple
|
||||||
|
uint8_t PB1; // $C062 Push Button 1 (bit 7) / Solid Apple
|
||||||
|
uint8_t PB2; // $C063 Push Button 2 (bit 7) / shift mod !!!
|
||||||
|
|
||||||
|
float GCP[4] = { 127.0f, 127.0f, 127.0f, 127.0f }; // GC Position ranging from 0 (left) to 255 right
|
||||||
|
float GCC[4] = { 0.0f }; // $C064 (GC0) and $C065 (GC1) Countdowns
|
||||||
|
|
||||||
|
int GCD[4] = { 0 }; // GC0 and GC1 Directions (left/down or right/up)
|
||||||
|
int GCA[4] = { 0 }; // GC0 and GC1 Action (push or release)
|
||||||
|
|
||||||
|
int GCActionSpeed; // Game Controller speed at which it goes to the edges
|
||||||
|
int GCReleaseSpeed; // Game Controller speed at which it returns to center
|
||||||
|
long long int GCCrigger; // $C070 the tick at which the GCs were reseted
|
||||||
|
|
||||||
|
Paddles();
|
||||||
|
~Paddles();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
void update();
|
||||||
|
uint8_t read(int pdl);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
2639
puce65c02.cpp
Normal file
2639
puce65c02.cpp
Normal file
File diff suppressed because it is too large
Load Diff
90
puce65c02.h
Normal file
90
puce65c02.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
puce65c02, a WDC 65c02 cpu emulator, based on puce6502 by the same author
|
||||||
|
|
||||||
|
Last modified 1st of July 2021
|
||||||
|
|
||||||
|
Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This version is slightly modified for reinette IIe, a french Apple IIe
|
||||||
|
emulator using SDL2 (https://github.com/ArthurFerreira2/reinette-IIe).
|
||||||
|
Please download the latest version from
|
||||||
|
https://github.com/ArthurFerreira2/puce65c02
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _PUCE65C02_H
|
||||||
|
#define _PUCE65C02_H
|
||||||
|
|
||||||
|
typedef enum {run, step, stop, wait} status;
|
||||||
|
|
||||||
|
#define CARRY 0x01
|
||||||
|
#define ZERO 0x02
|
||||||
|
#define INTR 0x04
|
||||||
|
#define DECIM 0x08
|
||||||
|
#define BREAK 0x10
|
||||||
|
#define UNDEF 0x20
|
||||||
|
#define OFLOW 0x40
|
||||||
|
#define SIGN 0x80
|
||||||
|
|
||||||
|
typedef struct Pbits_t {
|
||||||
|
uint8_t C : 1; // Carry
|
||||||
|
uint8_t Z : 1; // Zero
|
||||||
|
uint8_t I : 1; // Interupt disabled
|
||||||
|
uint8_t D : 1; // Decimal
|
||||||
|
uint8_t B : 1; // Break
|
||||||
|
uint8_t U : 1; // Undefined
|
||||||
|
uint8_t V : 1; // Overflow
|
||||||
|
uint8_t S : 1; // Sign
|
||||||
|
} Pbits;
|
||||||
|
|
||||||
|
|
||||||
|
class puce65c02 {
|
||||||
|
private:
|
||||||
|
uint16_t PC; // Program Counter
|
||||||
|
uint8_t A, X, Y, SP; // Accumulator, X and y indexes and Stack Pointer
|
||||||
|
union {
|
||||||
|
uint8_t byte;
|
||||||
|
Pbits bits;
|
||||||
|
} P; // Processor Status
|
||||||
|
|
||||||
|
public:
|
||||||
|
unsigned long long int ticks;
|
||||||
|
|
||||||
|
status state;
|
||||||
|
|
||||||
|
puce65c02();
|
||||||
|
~puce65c02();
|
||||||
|
|
||||||
|
void RST();
|
||||||
|
void IRQ();
|
||||||
|
void NMI();
|
||||||
|
uint16_t exec(unsigned long long int cycleCount);
|
||||||
|
|
||||||
|
uint16_t getPC();
|
||||||
|
void setPC(uint16_t address);
|
||||||
|
|
||||||
|
int getRegs(char* buffer);
|
||||||
|
int getCode(uint16_t address, char* buffer, int size, int numLines);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
56
reinette.h
Normal file
56
reinette.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __REINETTE_H__
|
||||||
|
#define __REINETTE_H__
|
||||||
|
|
||||||
|
#define VERSION "0.8.1"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "puce65c02.h"
|
||||||
|
#include "mmu.h"
|
||||||
|
#include "disk.h"
|
||||||
|
#include "video.h"
|
||||||
|
#include "speaker.h"
|
||||||
|
#include "paddles.h"
|
||||||
|
#include "gui.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern bool muted;
|
||||||
|
extern int volume;
|
||||||
|
extern bool running; // the entire application
|
||||||
|
extern bool paused; // the virtual machine
|
||||||
|
extern float speed;
|
||||||
|
|
||||||
|
extern puce65c02* cpu;
|
||||||
|
extern Mmu* mmu;
|
||||||
|
extern Disk* disk;
|
||||||
|
extern Video* video;
|
||||||
|
extern Speaker* speaker;
|
||||||
|
extern Paddles* paddles;
|
||||||
|
extern Gui* gui;
|
||||||
|
|
||||||
|
#endif
|
BIN
reinette.ico
Normal file
BIN
reinette.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
24
reinette.rc
Normal file
24
reinette.rc
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
1 ICON "reinette.ico"
|
||||||
|
1 VERSIONINFO
|
||||||
|
FILEVERSION 0,7,1,0
|
||||||
|
PRODUCTVERSION 0,7,0,0
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904E4"
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", "Arthur Ferreira"
|
||||||
|
VALUE "FileDescription", "Apple II emulator"
|
||||||
|
VALUE "FileVersion", "0.7.1.0"
|
||||||
|
VALUE "InternalName", "reinette"
|
||||||
|
VALUE "LegalCopyright", "Arthur Ferreira"
|
||||||
|
VALUE "OriginalFilename", "reinette.exe"
|
||||||
|
VALUE "ProductName", "reinette"
|
||||||
|
VALUE "ProductVersion", "0.7"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1252
|
||||||
|
END
|
||||||
|
END
|
BIN
rom/appleII+.rom
Normal file
BIN
rom/appleII+.rom
Normal file
Binary file not shown.
BIN
rom/appleII.rom
Normal file
BIN
rom/appleII.rom
Normal file
Binary file not shown.
BIN
rom/appleIIe.rom
Normal file
BIN
rom/appleIIe.rom
Normal file
Binary file not shown.
BIN
rom/appleIIee.rom
Normal file
BIN
rom/appleIIee.rom
Normal file
Binary file not shown.
BIN
rom/diskII.rom
Normal file
BIN
rom/diskII.rom
Normal file
Binary file not shown.
655
scratch.cpp
Normal file
655
scratch.cpp
Normal file
@ -0,0 +1,655 @@
|
|||||||
|
notes
|
||||||
|
|
||||||
|
CALL -151
|
||||||
|
|
||||||
|
Emulating an enhanced Apple //e with an Apple IIe Extended 80-Column Text Card, with 64K of additional RAM and a disk ][ interface card in slot 6 with two floppy drives
|
||||||
|
|
||||||
|
|
||||||
|
Problems and bugs :
|
||||||
|
inverted space is normal ....
|
||||||
|
|
||||||
|
|
||||||
|
# Color Bit Pattern
|
||||||
|
|
||||||
|
01 Black 0xFF000000,
|
||||||
|
02 Dark blue 0xFFCD741C,
|
||||||
|
09 Magenta Dk red 0xFF5639E2,
|
||||||
|
Violet purple 0xFFAD6E7E,
|
||||||
|
04 Light blue 0xFFDFB290,
|
||||||
|
05 Brown 0xFF225897,
|
||||||
|
Dark green 0xFF80811F,
|
||||||
|
Gray1 0xFF7A8289,
|
||||||
|
Medium blue 0xFFE4A856,
|
||||||
|
10 Pink 0xFFF0CEFF,
|
||||||
|
Gray2 0xFF8F979E,
|
||||||
|
green 0xFF31C090,
|
||||||
|
13 Orange 0xFF156CEA,
|
||||||
|
Aqua Lt green 0xFFD5D29F,
|
||||||
|
15 Yellow 0xFFA6FDFF,
|
||||||
|
16 White 0xFFFFFFFF
|
||||||
|
|
||||||
|
|
||||||
|
GOOD:
|
||||||
|
const uint32_t dhcolor[16] = {
|
||||||
|
0xFF000000, // 01 Black
|
||||||
|
0xFFCD741C, // 02 Dark blue
|
||||||
|
0xFF80811F, // 03 Dark green
|
||||||
|
0xFFDFB290, // 04 Light blue
|
||||||
|
0xFF225897, // 05 Brown
|
||||||
|
0xFF7A8289, // Gray1
|
||||||
|
0xFF31C090, // green
|
||||||
|
0xFFE4A856, // Medium blue
|
||||||
|
0xFF5639E2, // 09 Magenta Dk red
|
||||||
|
0xFFAD6E7E, // Violet purple
|
||||||
|
0xFF8F979E, // Gray2
|
||||||
|
0xFFD5D29F, // Aqua Lt green
|
||||||
|
0xFF156CEA, // 13 Orange
|
||||||
|
0xFFF0CEFF, // 10 Pink
|
||||||
|
0xFFA6FDFF, // 15 Yellow
|
||||||
|
0xFFFFFFFF // 16 White
|
||||||
|
};
|
||||||
|
|
||||||
|
GOOD:
|
||||||
|
const uint32_t dlcolor[16] = {
|
||||||
|
0xFF000000, // 01 Black
|
||||||
|
0xFFCD741C, // 02 Dark blue
|
||||||
|
0xFF80811F, // 03 Dark green
|
||||||
|
0xFFDFB290, // 04 Light blue
|
||||||
|
0xFF225897, // 05 Brown
|
||||||
|
0xFF7A8289, // Gray1
|
||||||
|
0xFF31C090, // green
|
||||||
|
0xFFE4A856, // Medium blue
|
||||||
|
0xFF5639E2, // 09 Magenta Dk red
|
||||||
|
0xFFAD6E7E, // Violet purple
|
||||||
|
0xFF8F979E, // Gray2
|
||||||
|
0xFFD5D29F, // Aqua Lt green
|
||||||
|
0xFF156CEA, // 13 Orange
|
||||||
|
0xFFF0CEFF, // 10 Pink
|
||||||
|
0xFFA6FDFF, // 15 Yellow
|
||||||
|
0xFFFFFFFF // 16 White
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Color Bit Pattern
|
||||||
|
|
||||||
|
1 Black 0000 #121315 0xFF131512, #000000
|
||||||
|
9 Brown 0001 #874912 0xFF491287,
|
||||||
|
5 Dark green 0010 #238681 0xFF868123,
|
||||||
|
13 green 0011 #94C434 0xFFC43494,
|
||||||
|
3 Dark blue 0100 #1E79D2 0xFF79D21E,
|
||||||
|
11 Gray2 0101 #9D9690 0xFF96909D,
|
||||||
|
7 Medium blue 0110 #6BBDF9 0xFFBDF96B,
|
||||||
|
15 Aqua Lt green 0111 #99CDCB 0xFFCDCB99,
|
||||||
|
2 Magenta Dk Red 1000 #E73C5C 0xFF3C5CE7,
|
||||||
|
10 Orange 1001 #EE7420 0xFF7420EE,
|
||||||
|
6 Gray1 1010 #9C9791 0xFF97919C,
|
||||||
|
14 Yellow 1011 #FEFCA5 0xFFFCA5FE,
|
||||||
|
4 Violet purple 1100 #9384C2 0xFF84C293,
|
||||||
|
12 Pink 1101 #F7B5D8 0xFFB5D8F7,
|
||||||
|
8 Light blue 1110 #A2C4F2 0xFFC4F2A2,
|
||||||
|
16 White 1111 #FFFFFF 0xFFFFFFFF
|
||||||
|
|
||||||
|
const uint32_t dhcolor[16] = {
|
||||||
|
0xFF000000, 0xFF5639E2, 0xFFCD741C, 0xFFAD6E7E,
|
||||||
|
0xFF80811F, 0xFF7A8289, 0xFFE4A856, 0xFFDFB290,
|
||||||
|
0xFF225897, 0xFF156CEA, 0xFF8F979E, 0xFFF0CEFF,
|
||||||
|
0xFF31C090, 0xFFA6FDFF, 0xFFD5D29F, 0xFFFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
from aIIinPC
|
||||||
|
const uint32_t hdcolor[16] = {
|
||||||
|
0xFF131512,
|
||||||
|
0xFF3C5CE7,
|
||||||
|
0xFF79D21E,
|
||||||
|
0xFF84C293,
|
||||||
|
0xFF868123,
|
||||||
|
0xFF97919C,
|
||||||
|
0xFFBDF96B,
|
||||||
|
0xFFC4F2A2,
|
||||||
|
0xFF491287,
|
||||||
|
0xFF7420EE,
|
||||||
|
0xFF96909D,
|
||||||
|
0xFFB5D8F7,
|
||||||
|
0xFFC43494,
|
||||||
|
0xFFFCA5FE,
|
||||||
|
0xFFCDCB99,
|
||||||
|
0xFFFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
BAD :
|
||||||
|
const uint32_t color[16] = {
|
||||||
|
0xFF000000, 0xFF5639E2, 0xFF225897, 0xFF156CEA,
|
||||||
|
0xFF80811F, 0xFF7A8289, 0xFF31C090, 0xFFA6FDFF,
|
||||||
|
0xFFCD741C, 0xFFAD6E7E, 0xFF8F979E, 0xFFF0CEFF,
|
||||||
|
0xFFE4A856, 0xFFDFB290, 0xFFD5D29F, 0xFFFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
BAD :
|
||||||
|
const uint32_t dhcolor[16] = {
|
||||||
|
0xFF000000, 0xFF225897, 0xFF80811F, 0xFF31C090,
|
||||||
|
0xFFCD741C, 0xFF8F979E, 0xFFE4A856, 0xFFD5D29F,
|
||||||
|
0xFF5639E2, 0xFF156CEA, 0xFF7A8289, 0xFFA6FDFF,
|
||||||
|
0xFFAD6E7E, 0xFFF0CEFF, 0xFFDFB290, 0xFFFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
BAD :
|
||||||
|
const uint32_t dhcolor[16] = {
|
||||||
|
0xFFFFFFFF,
|
||||||
|
0xFFDFB290,
|
||||||
|
0xFFF0CEFF,
|
||||||
|
0xFFAD6E7E,
|
||||||
|
0xFFA6FDFF,
|
||||||
|
0xFF7A8289,
|
||||||
|
0xFF156CEA,
|
||||||
|
0xFF5639E2,
|
||||||
|
0xFFD5D29F,
|
||||||
|
0xFFE4A856,
|
||||||
|
0xFF8F979E,
|
||||||
|
0xFFCD741C,
|
||||||
|
0xFF31C090,
|
||||||
|
0xFF80811F,
|
||||||
|
0xFF225897,
|
||||||
|
0xFF000000
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ROMS : https://comp.sys.apple2.narkive.com/yOkYv09h/rom-identification
|
||||||
|
|
||||||
|
Apple IIe
|
||||||
|
|
||||||
|
342-0134-A EF
|
||||||
|
342-0135-A CD
|
||||||
|
341-0150-A Keyboard (UK)
|
||||||
|
341-0151-A Keyboard (DE)
|
||||||
|
342-0160 Video (UK)
|
||||||
|
|
||||||
|
Apple //e Enhanced
|
||||||
|
|
||||||
|
342-0303 EF
|
||||||
|
342-0304 CD
|
||||||
|
342-0265 Video (Mousetext US)
|
||||||
|
|
||||||
|
Apple //e Platinum
|
||||||
|
|
||||||
|
342-0349-A CF
|
||||||
|
342-0150-A Keyboard (UK)
|
||||||
|
342-0273-A Video (Mousetext UK)
|
||||||
|
342-0275-A Video (Mousetext DE)
|
||||||
|
|
||||||
|
|
||||||
|
//e and //ee :
|
||||||
|
|
||||||
|
KEYBOARD :
|
||||||
|
|
||||||
|
Three special keys-Control, Shift, and Caps Lock-change the
|
||||||
|
codes generated by the other keys. The Control key is similar to the
|
||||||
|
ASCII CTRL key.
|
||||||
|
Three other keys have special functions: the Reset key, and two keys
|
||||||
|
marked with apples, one outlined (Open Apple) and one solid
|
||||||
|
(Solid Apple). Pressing the Reset key with the Control key depressed
|
||||||
|
resets the Apple Ile, as described in Chapter 4. The Apple keys are
|
||||||
|
connected to the one-bit game inputs, described later in this
|
||||||
|
chapter.
|
||||||
|
On the extended keyboard lie the Solid Apple key Is labeled
|
||||||
|
Option: the Solid Apple and Option keys are functionally
|
||||||
|
Identical. Also note that manuals accompanying products with
|
||||||
|
the Solid Apple labeled as Option may refer to the Open Apple
|
||||||
|
key as simply the Apple key
|
||||||
|
|
||||||
|
$COOO Keyboard data and strobe
|
||||||
|
$C010 Any-key-down flag and dear-strobe switch
|
||||||
|
|
||||||
|
Your program can find out whether any key is down, except the
|
||||||
|
Reset, Control, Shift, Caps Lock, Open Apple, and Solid Apple (or
|
||||||
|
Option, on the extended keyboard Ile) keys, by reading from
|
||||||
|
location $COOO
|
||||||
|
|
||||||
|
The Open Apple and Solid Apple keys are connected to switches 0
|
||||||
|
and 1 of the game I/0 connector inputs. If OA is pressed, switch 0 is
|
||||||
|
"pressed," and if Solid Apple is pressed, switch 1 is "pressed."
|
||||||
|
|
||||||
|
On the extended keyboard lie, the Shift key Is connected to
|
||||||
|
switch 2 of the game 1/0 ports via the X6 jumper (single-wire
|
||||||
|
Shift-key mod jumper).
|
||||||
|
|
||||||
|
Two more special keys are the Apple keys, Open Apple and Solid
|
||||||
|
Apple, located on either side of the Space bar. These keys are
|
||||||
|
connected to the one-bit game inputs, which are described later in
|
||||||
|
this chapter in the section •switch Inputs." Pressing them in
|
||||||
|
combination with the Control and Reset keys causes the built-in
|
||||||
|
firmware to perform special reset and self-test cycles, described
|
||||||
|
with the reset routine in Chapter 4.
|
||||||
|
|
||||||
|
|
||||||
|
VIDEO :
|
||||||
|
composite video compatible with the standard set by the NTSC
|
||||||
|
For a clear 80-column display, you must use a high-resolution video monitor
|
||||||
|
with a bandwidth of 14 MHz or greater.
|
||||||
|
|
||||||
|
When you turn on power or reset the Apple Ile, the 80-column
|
||||||
|
firmware is inactive and the Apple IIe displays the primary
|
||||||
|
character set, even if an 80-column text card is installed. When you
|
||||||
|
activate the 80-column firmware, it switches to the alternate
|
||||||
|
character set.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
There are actually two versions of 40-column text mode sup-
|
||||||
|
ported by the //e. The "standard" 40-column mode is the one that
|
||||||
|
is usually in effect and is easily identified by its characteristic
|
||||||
|
"checkerboard" cursor that is displayed whenever keyboard in-
|
||||||
|
formation is being requested. The other version is the "special"
|
||||||
|
40-column mode that is available when the //e's 80-column firm-
|
||||||
|
ware is being used; in this mode the cursor is an inverse block that
|
||||||
|
does not flash
|
||||||
|
Once you are in 80-column mode, you can switch between the
|
||||||
|
80-column mode and the special 40-column mode whenever key-
|
||||||
|
board information is being requested by using the two special
|
||||||
|
escape sequences discussed in Chapter 6: ESC 4 and ESC 8. For
|
||||||
|
example, if you are in 80-column mode and you want to enter the
|
||||||
|
special 40-column mode, enter the sequence
|
||||||
|
ESC 4
|
||||||
|
If you want to go in the opposite direction, enter the sequence
|
||||||
|
ESC 8
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TODO : implement double hi-res :
|
||||||
|
// high-resolution graphics, 140 by 192, in 6 colors
|
||||||
|
// high-resolution graphics, 280 by 192, in black and white
|
||||||
|
// double high-resolution graphics, 140 by 192, in 16 colors (with optional 64K text card)
|
||||||
|
// double high-resolution graphics, 560 by 192, in black and white (with optional 64K text card)
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
integration is Dear IMGUI
|
||||||
|
|
||||||
|
show :
|
||||||
|
|
||||||
|
- registers
|
||||||
|
- live disassembly
|
||||||
|
- memory dump one window per page ?
|
||||||
|
- video memory, page 1, page 2
|
||||||
|
- sound shape
|
||||||
|
- disassembler
|
||||||
|
- joystick setup / live view
|
||||||
|
- live callstack view with support for imported symbols
|
||||||
|
- stepping by cycle / frame
|
||||||
|
- VRAM viewer - HIRES page 1, page 2
|
||||||
|
- audio buffer viewer, with pretty waveform plots
|
||||||
|
- savestate support in the most hacky way possible
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
void GUI::renderHoverText(const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::TextV(fmt, args);
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
float fps = ImGui::GetIO().Framerate;
|
||||||
|
ImGui::Text("FPS: %.1f (%.1fx speed)", fps, fps / 61.0f);
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
ImGui::Text("Save state: ");
|
||||||
|
ImGui::PushID(0);
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
if (i > 0)
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::SmallButton(std::to_string(i).c_str())) {
|
||||||
|
emu->saveState(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
ImGui::Checkbox("Fast forward", &emu->cpu.fastForward);
|
||||||
|
ImGui::Checkbox("Step mode", &emu->cpu.stepMode);
|
||||||
|
if (ImGui::Button("Step instruction (space)")) {
|
||||||
|
emu->cpu.stepInst = true;
|
||||||
|
}
|
||||||
|
if (ImGui::Button("Step frame (f)")) {
|
||||||
|
emu->cpu.stepFrame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
ImGui::Text("cycle: %d", emu->cpu.c); // ticks
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
if (ImGui::CollapsingHeader("Disassembly @ PC", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
char buf[25 * 20];
|
||||||
|
buf[0] = '\0';
|
||||||
|
emu->cpu.disassemble(emu->cpu.r.pc, 20, buf);
|
||||||
|
ImGui::Text("%s", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
case SDLK_F1: // SAVES
|
||||||
|
if (ctrl) {
|
||||||
|
if (saveFloppy(0))
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "Save", "\nDisk 1 saved back to file\n", NULL);
|
||||||
|
else
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Save", "\nTError while saving Disk 1\n", NULL);
|
||||||
|
} else if (alt) {
|
||||||
|
if (saveFloppy(1))
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "Save", "\nDisk 2 saved back to file\n", NULL);
|
||||||
|
else
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Save", "\nError while saving Disk 2\n", NULL);
|
||||||
|
} else {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "Save", "CTRL-F1 to save D1\nALT-F1 to save D2\n", NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
case SDLK_F2: { // SCREENSHOTS
|
||||||
|
sshot = SDL_GetWindowSurface(wdo);
|
||||||
|
SDL_RenderReadPixels(rdr, NULL, SDL_GetWindowPixelFormat(wdo), sshot->pixels, sshot->pitch);
|
||||||
|
workDir[workDirSize] = 0;
|
||||||
|
int i = -1, a = 0, b = 0;
|
||||||
|
while (disk[0].filename[++i] != '\0') {
|
||||||
|
if (disk[0].filename[i] == '\\') a = i;
|
||||||
|
if (disk[0].filename[i] == '.') b = i;
|
||||||
|
}
|
||||||
|
strncat(workDir, "screenshots\\", 14);
|
||||||
|
if (a != b) strncat(workDir, disk[0].filename + a, b - a);
|
||||||
|
else strncat(workDir, "no disk", 10);
|
||||||
|
strncat(workDir, ".bmp", 5);
|
||||||
|
SDL_SaveBMP(sshot, workDir);
|
||||||
|
SDL_FreeSurface(sshot);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
if (opened_popup) {
|
||||||
|
ImGui::SetKeyboardFocusHere();
|
||||||
|
}
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
ImGui::Begin("RAM", &show_ram_window);
|
||||||
|
if (ImGui::Button("SEARCH")) {};
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("DISASSEMBLE")) {};
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("SET PC")) {};
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
===
|
||||||
|
----------------------------------------------------------------
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| Rockwell |
|
||||||
|
| |
|
||||||
|
| 666 5555555 CCCC 000 22222 |
|
||||||
|
| 6 5 C C 0 0 2 2 |
|
||||||
|
| 6 5 C 0 0 0 2 |
|
||||||
|
| 666666 555555 C 0 0 0 222 |
|
||||||
|
| 6 6 5 C 0 0 0 2 |
|
||||||
|
| 6 6 5 C C 0 0 2 |
|
||||||
|
| 66666 555555 CCCC 000 2222222 |
|
||||||
|
| |
|
||||||
|
| 65C02 CMOS MICROPROCESSOR Instruction Set Summary |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| _________ _________ |
|
||||||
|
| _| \__/ |_ ___ |
|
||||||
|
| Vss |_|1 40|_| RES <-- |
|
||||||
|
| _| |_ |
|
||||||
|
| --> RDY |_|2 39|_| CLK2 --> |
|
||||||
|
| _| |_ |
|
||||||
|
| <-- CLK1 |_|3 38|_| NC |
|
||||||
|
| ___ _| |_ |
|
||||||
|
| --> IRQ |_|4 37|_| CLK0 <-- |
|
||||||
|
| _| |_ |
|
||||||
|
| NC |_|5 36|_| NC |
|
||||||
|
| ___ _| |_ |
|
||||||
|
| --> NMI |_|6 35|_| NC |
|
||||||
|
| _| |_ _ |
|
||||||
|
| --> SYNC |_|7 34|_| R/W --> |
|
||||||
|
| _| |_ |
|
||||||
|
| Vcc |_|8 33|_| DB7 <--> |
|
||||||
|
| _| |_ |
|
||||||
|
| <-- A0 |_|9 32|_| DB6 <--> |
|
||||||
|
| _| |_ |
|
||||||
|
| <-- A1 |_|10 65C02 31|_| DB5 <--> |
|
||||||
|
| _| |_ |
|
||||||
|
| <-- A2 |_|11 30|_| DB4 <--> |
|
||||||
|
| _| |_ |
|
||||||
|
| <-- A3 |_|12 29|_| DB3 <--> |
|
||||||
|
| _| |_ |
|
||||||
|
| <-- A4 |_|13 28|_| DB2 <--> |
|
||||||
|
| _| |_ |
|
||||||
|
| <-- A5 |_|14 27|_| DB1 <--> |
|
||||||
|
| _| |_ |
|
||||||
|
| <-- A6 |_|15 26|_| DB0 <--> |
|
||||||
|
| _| |_ |
|
||||||
|
| <-- A7 |_|16 25|_| A15 --> |
|
||||||
|
| _| |_ |
|
||||||
|
| <-- A8 |_|17 24|_| A14 --> |
|
||||||
|
| _| |_ |
|
||||||
|
| <-- A9 |_|18 23|_| A13 --> |
|
||||||
|
| _| |_ |
|
||||||
|
| <-- A10 |_|19 22|_| A12 --> |
|
||||||
|
| _| |_ |
|
||||||
|
| <-- A11 |_|20 21|_| Vss |
|
||||||
|
| |______________________| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
|Written by Jonathan Bowen |
|
||||||
|
| Programming Research Group |
|
||||||
|
| Oxford University Computing Laboratory |
|
||||||
|
| 8-11 Keble Road |
|
||||||
|
| Oxford OX1 3QD |
|
||||||
|
| England |
|
||||||
|
| |
|
||||||
|
| Tel +44-865-273840 |
|
||||||
|
| |
|
||||||
|
|Created November 1984 |
|
||||||
|
|Updated April 1985 |
|
||||||
|
|Issue 1.1 Copyright (C) J.P.Bowen 1985|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|Mnem. |Op|NVBDIZC|A#ZBIRX@|~|Description |Notes |
|
||||||
|
|------+--+-------+--------+-+---------------------+-----------|
|
||||||
|
|ADC s|6D|**---**| XxX XX|4|Add with Carry |A=A+s+C %|
|
||||||
|
|AND s|2D|*----*-| XxX XX|4|Logical AND |A=A&s %|
|
||||||
|
|ASL d|0E|*----**| xx |6|Arith. Shift Left |d={C,d,0}<-|
|
||||||
|
|ASLA |0A|*----**|X |2|Arith. Shift Left |A={C,d,0}<-|
|
||||||
|
|BBRb z|0F|-------| * X |2|Branch if Bit Reset |If s<b>=0 |
|
||||||
|
|BBSb z|8F|-------| * X |2|Branch if Bit Set |If s<b>=1 |
|
||||||
|
|BCC a|90|-------| X |2|Branch if Carry Clear|If C=0(4~)%|
|
||||||
|
|BCS a|B0|-------| X |2|Branch if Carry Set |If C=1(4~)%|
|
||||||
|
|BEQ a|F0|-------| X |2|Branch if Equal |If Z=1(4~)%|
|
||||||
|
|BIT s|2C|**---*-| Xxx |4|Bit Test |A&s $|
|
||||||
|
|BMI a|30|-------| X |2|Branch if Minus |If N=1(4~)%|
|
||||||
|
|BNE a|D0|-------| X |2|Branch if Not Equal |If Z=0(4~)%|
|
||||||
|
|BPL a|10|-------| X |2|Branch if Plus |If N=0(4~)%|
|
||||||
|
|BRA a|80|-------| X |2|Branch Always |PC=a (4~)%|
|
||||||
|
|BRK |00|--+-1--| X |7|Break(-[S]={PC+2,P}) |PC=[FFFEH] |
|
||||||
|
|BVC a|50|-------| X |2|Branch if Overflw Clr|If V=0(4~)%|
|
||||||
|
|BVS a|70|-------| X |2|Branch if Overflw Set|If V=1(4~)%|
|
||||||
|
|CLC |18|------0| X |2|Clear Carry flag |C=0 |
|
||||||
|
|CLD |D8|---0---| X |2|Clear Decimal mode |D=0 |
|
||||||
|
|CLI |58|----0--| X |2|Clear Int. disable |I=0 |
|
||||||
|
|CLV |B8|-0-----| X |2|Clear Overflow flag |V=0 |
|
||||||
|
|CMP s|CD|*----**| XxX XX|4|Compare |A-s |
|
||||||
|
|CPX s|EC|*----**| X** |4|Compare index reg. |X-s |
|
||||||
|
|CPY s|CC|*----**| X** |4|Compare index reg. |Y-s |
|
||||||
|
|DEC d|CE|*----*-| xx |6|Decrement |d=d-1 |
|
||||||
|
|DECA |3A|*----*-|X |6|Decrement Acc. |A=A-1 |
|
||||||
|
|DEX |CA|*----*-| X |2|Decrement index reg. |X=X-1 |
|
||||||
|
|DEY |88|*----*-| X |2|Decrement index reg. |Y=Y-1 |
|
||||||
|
|EOR s|4D|*----*-| XxX XX|4|Logical Exclusive OR |A=Axs %|
|
||||||
|
|INC d|EE|*----*-| xx |6|Increment |d=d+1 |
|
||||||
|
|INCA |1A|*----*-|X |6|Increment Acc. |A=A+1 |
|
||||||
|
|INX |E8|*----*-| X |2|Increment index reg. |X=X+1 |
|
||||||
|
|INY |C8|*----*-| X |2|Increment index reg. |Y=Y+1 |
|
||||||
|
|JMP s|4C|-------| * X|3|Jump |PC=s $|
|
||||||
|
|JSR s|20|-------| * |6|Jump to Subroutine |-[S]=PC+2=s|
|
||||||
|
|LDA s|AD|*----*-| XxX XX|4|Load Accumulator |A=s %|
|
||||||
|
|LDX s|AE|*----*-| Xyy |4|Load index register |X=s $%|
|
||||||
|
|LDY s|AC|*----*-| Xxx |4|Load index register |Y=s %|
|
||||||
|
|LSR d|4E|0----**| xx |6|Logical Shift Right |d=->{0,d,C}|
|
||||||
|
|LSRA |4A|0----**|X |2|Logical Shift Right |A=->{0,A,C}|
|
||||||
|
|NOP |EA|-------| X |2|No Operation | |
|
||||||
|
|ORA s|0D|*----*-| XxX XX|4|Logical Inclusive OR |A=Avs |
|
||||||
|
|PHA |48|-------| X |3|Push Accumulator |-[S]=A |
|
||||||
|
|PHP |08|-------| X |3|Push status register |-[S]=P |
|
||||||
|
|PHX |DA|-------| X |2|Push index register |-[S]=X |
|
||||||
|
|PHY |5A|-------| X |2|Push index register |-[S]=Y |
|
||||||
|
|PLA |68|-------| X |4|Pull Accumulator |A=[S]+ |
|
||||||
|
|PLP |28|*******| X |4|Pull status register |P=[S]+ |
|
||||||
|
|PLX |FA|-------| X |2|Pull index register |X=[S]+ |
|
||||||
|
|PLY |7A|-------| X |2|Pull index register |Y=[S]+ |
|
||||||
|
|RMBb d|07|-------| * |5|Reset Memory Bit |d<b>=0 |
|
||||||
|
|ROL d|2E|*----**| xx |6|Rotate Left |d={C,d}<- |
|
||||||
|
|ROLA |2A|*----**|X |2|Rotate Left Acc. |A={C,A}<- |
|
||||||
|
|ROR d|6E|*----**| xx |6|Rotate Right |d=->{C,d} |
|
||||||
|
|RORA |6A|*----**|X |2|Rotate Right Acc. |A=->{C,A} |
|
||||||
|
|RTI |40|*******| X |6|Return from Interrupt|{PC,P}=[S]+|
|
||||||
|
|RTS |60|-------| X |6|Return from Subr. |PC={[S]+}+1|
|
||||||
|
|SBC s|ED|*----**| XxX XX|4|Subtract with Carry |A=A-s-C %|
|
||||||
|
|SEC |38|------1| X |2|Set Carry flag |C=1 |
|
||||||
|
|SED |F8|---1---| X |2|Set Decimal mode |D=1 |
|
||||||
|
|SEI |78|----1--| X |2|Set Interrupt disable|I=1 |
|
||||||
|
|SMBb d|87|-------| * |5|Set Memory Bit |d<b>=1 |
|
||||||
|
|STA d|8D|-------| xX XX|4|Store Accumulator |d=A |
|
||||||
|
|STX d|8E|-------| y* |4|Store index register |d=X |
|
||||||
|
|STY d|8C|-------| x* |4|Store index register |d=Y |
|
||||||
|
|STZ d|9C|-------| xx |4|Store Zero |d=0 $|
|
||||||
|
|TAX |AA|*----*-| X |2|Transfer Accumulator |X=A |
|
||||||
|
|TAY |A8|*----*-| X |2|Transfer Accumulator |Y=A |
|
||||||
|
|TRB d|1C|**---*-| ** |2|Test and Reset Bits |d=~A&d |
|
||||||
|
|TSB d|0C|**---*-| ** |2|Test and Set Bits |d=Avd |
|
||||||
|
|TSX |BA|*----*-| X |2|Transfer Stack ptr |X=S |
|
||||||
|
|TXA |8A|*----*-| X |2|Transfer index reg. |A=X |
|
||||||
|
|TXS |9A|-------| X |2|Transfer index reg. |S=X |
|
||||||
|
|TYA |98|*----*-| X |2|Transfer index reg. |A=Y |
|
||||||
|
|------+--+-------+--------+-+---------------------------------|
|
||||||
|
| |XX| | |X|Hexadecimal opcode/no. of cycles |
|
||||||
|
----------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|Mnemonic |NVBDIZC|A#ZBIRX@|Description |
|
||||||
|
|---------+-------+--------+-----------------------------------|
|
||||||
|
| P |-*01+ | |Unaff/affected/reset/set/stack set |
|
||||||
|
| N |N | |Negative status (Bit 7) |
|
||||||
|
| V | V | |Overflow status (Bit 6) |
|
||||||
|
| B | B | |Break command indicator (Bit 4) |
|
||||||
|
| D | D | |Decimal mode control (Bit 3) |
|
||||||
|
| I | I | |Interrupt disable control (Bit 2) |
|
||||||
|
| Z | Z | |Zero status (Bit 1) |
|
||||||
|
| C | C| |Carry status (Bit 0) |
|
||||||
|
|------------------+--------+----------------------------------|
|
||||||
|
| |* |Only non-indexed mode valid |
|
||||||
|
| |x |X and non-indexed mode valid |
|
||||||
|
| |y |Y and non-indexed mode valid |
|
||||||
|
| |X |All modes valid |
|
||||||
|
|-----------------+--------+-----------------------------------|
|
||||||
|
| | |Add XXH to opcode |+XXH| |
|
||||||
|
| | |Subtract XXH from opcode |-XXH| |
|
||||||
|
| | |Add X to number of cycles | |+X|
|
||||||
|
| | |Subtract X from cycles | |-X|
|
||||||
|
|-----------------+--------+---------------------------+----+--|
|
||||||
|
| b | |Bit number (b=0-7) |+b0H| |
|
||||||
|
| A |A |Accumulator | | |
|
||||||
|
| #n | # |Immediate |-0CH|-2|
|
||||||
|
| #n | # | ditto (opcode = XDH) | X9H| 2|
|
||||||
|
| BIT #n | # | ditto (special case) | 89H| 2|
|
||||||
|
| <n | Z |Zero page |-08H|-1|
|
||||||
|
| STZ n | Z | ditto (special case) | 64H| 3|
|
||||||
|
| n | * |Zero page (direct mode) |-08H|-1|
|
||||||
|
| n,X | x |Zero page indexed (X) |+08H|+0|
|
||||||
|
| n,Y | y |Zero Page indexed (Y) |+08H|+0|
|
||||||
|
| >nn | B |Absolute |+00H|+0|
|
||||||
|
| nn | * |Absolute (extended mode) |+00H|+0|
|
||||||
|
| nn,X | x |Absolute indexed (X) |+10H|+0|
|
||||||
|
| nn,Y | y |Absolute indexed (Y) |+0CH|+0|
|
||||||
|
| LDX nn,Y | y | ditto (special case) | BEH| 4|
|
||||||
|
| | I |Implicit | | |
|
||||||
|
| a | R |Relative (PC=PC+1+offset) | |+2|
|
||||||
|
| [nn,X] | x |Indexed indirect (X) |-0CH|+2|
|
||||||
|
| [nn],Y | y |Indirect indexed (Y) |+04H|+1|
|
||||||
|
| [nn] | @|Absolute indirect |+05H|+1|
|
||||||
|
| JMP [nn] | @| ditto (special case) | 6CH| 5|
|
||||||
|
|--------------------------+-----------------------------------|
|
||||||
|
| A |Accumulator (8-bit) |
|
||||||
|
| P |Processor status register (8-bit) |
|
||||||
|
| PC |Program Counter (16-bit) |
|
||||||
|
| S |Stack pointer (9-bit, MSB=1) |
|
||||||
|
| X |Index register X (8-bit) |
|
||||||
|
| Y |Index register Y (8-bit) |
|
||||||
|
|--------------------------+-----------------------------------|
|
||||||
|
| a |Relative address (-128 to +127) |
|
||||||
|
| b |Bit number (0 to 7) |
|
||||||
|
| d |Destination |
|
||||||
|
| n |8-bit expression (0 to 255) |
|
||||||
|
| nn |16-bit expression (0 to 65535) |
|
||||||
|
| s |Source |
|
||||||
|
| z |Zero page, relative address (n,a) |
|
||||||
|
|--------------------------+-----------------------------------|
|
||||||
|
| + - |Arithmetic addition/subtraction |
|
||||||
|
| * / |Arithmetic multiplication/division |
|
||||||
|
| & ~ |Logical AND/NOT |
|
||||||
|
| v x |Logical inclusive/exclusive OR |
|
||||||
|
| <- -> |Rotate left/right |
|
||||||
|
| [ ] |Indirect addressing |
|
||||||
|
| [ ]+ |Post-increment indirect addressing |
|
||||||
|
| -[ ] |Pre-decrement indirect addressing |
|
||||||
|
| { } |Combination of operands |
|
||||||
|
| < > |Bit number |
|
||||||
|
| $ |Special case for addressing mode |
|
||||||
|
| % |~s=~s+1 if crossing page boundary |
|
||||||
|
|--------------------------+-----------------------------------|
|
||||||
|
|0000H to 00FFH |Page 0 (see zero page addressing) |
|
||||||
|
|0100H to 01FFH |Page 1 (stack area, 01FFH = start) |
|
||||||
|
|XX00H to XXFFH |Page n (where n=XXH) |
|
||||||
|
|FFFAH to FFFBH |Non maskable interrupt vector(NMI) |
|
||||||
|
|FFFCH to FFFDH |Reset (RES) vector |
|
||||||
|
|FFFEH to FFFFH |Interrupt Request vector (IRQ) |
|
||||||
|
|FFFEH to FFFFH |Break command vector (see BRK) |
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
|
||||||
|
===
|
79
speaker.cpp
Normal file
79
speaker.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "reinette.h"
|
||||||
|
|
||||||
|
Speaker::Speaker() {
|
||||||
|
if (SDL_Init(SDL_INIT_AUDIO) != 0) {
|
||||||
|
printf("Error: %s\n", SDL_GetError());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
SDL_AudioSpec desired = { 96000, AUDIO_S8, 1, 0, 512, 0, 0, NULL, NULL };
|
||||||
|
audioDevice = SDL_OpenAudioDevice(NULL, 0, &desired, NULL, SDL_FALSE); // get the audio device ID
|
||||||
|
setVolume(volume);
|
||||||
|
SDL_PauseAudioDevice(audioDevice, muted); // unmute it (muted is false)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Speaker::play() {
|
||||||
|
static unsigned long long int lastTick = 0LL;
|
||||||
|
static bool SPKR = false; // $C030 Speaker toggle
|
||||||
|
|
||||||
|
SPKR = !SPKR; // toggle speaker state
|
||||||
|
Uint32 length = (int)((double)(cpu->ticks - lastTick) / 10.42f / speed); // 1000000Hz / 96000Hz = 10.4166
|
||||||
|
lastTick = cpu->ticks;
|
||||||
|
if (!muted) {
|
||||||
|
if (length > audioBufferSize)
|
||||||
|
SDL_QueueAudio(audioDevice, audioBuffer[2], audioBufferSize); // silence
|
||||||
|
else
|
||||||
|
SDL_QueueAudio(audioDevice, audioBuffer[SPKR], length | 1); // | 1 TO HEAR HIGH FREQ SOUNDS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Speaker::toggleMute() {
|
||||||
|
SDL_PauseAudioDevice(audioDevice, muted);
|
||||||
|
SDL_ClearQueuedAudio(audioDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Speaker::setVolume(int newVolume) {
|
||||||
|
if (muted) {
|
||||||
|
muted = false;
|
||||||
|
toggleMute();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newVolume > 127)
|
||||||
|
volume = 127;
|
||||||
|
else if (newVolume < 0)
|
||||||
|
volume = 0;
|
||||||
|
else volume = newVolume;
|
||||||
|
|
||||||
|
for (int i = 0; i < audioBufferSize; i++) { // two audio buffers,
|
||||||
|
audioBuffer[true][i] = (int8_t)volume; // one used when SPKR is true
|
||||||
|
audioBuffer[false][i] = (int8_t)-volume; // the other when SPKR is false
|
||||||
|
audioBuffer[2][i] = 0; // silence
|
||||||
|
}
|
||||||
|
}
|
45
speaker.h
Normal file
45
speaker.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SOUND_H__
|
||||||
|
#define __SOUND_H__
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
#define audioBufferSize 32768
|
||||||
|
|
||||||
|
class Speaker {
|
||||||
|
public:
|
||||||
|
Speaker();
|
||||||
|
void play();
|
||||||
|
void toggleMute();
|
||||||
|
void setVolume(int newVolume);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int8_t audioBuffer[3][audioBufferSize];
|
||||||
|
SDL_AudioDeviceID audioDevice;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
561
video.cpp
Normal file
561
video.cpp
Normal file
@ -0,0 +1,561 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "reinette.h"
|
||||||
|
|
||||||
|
|
||||||
|
Video::Video() {
|
||||||
|
memset(ramHeatmap, 0xFF000000, sizeof(ramHeatmap));
|
||||||
|
memset(auxHeatmap, 0xFF000000, sizeof(auxHeatmap));
|
||||||
|
|
||||||
|
// array from https://github.com/Michaelangel007/apple2_hgr_font_tutorial/
|
||||||
|
const char FONT[] = {
|
||||||
|
0x10, 0x08, 0x36, 0x7F, 0x3F, 0x3F, 0x7E, 0x36, // 0x00 ^@
|
||||||
|
0x10, 0x08, 0x36, 0x41, 0x21, 0x21, 0x4A, 0x36, // 0x01 ^A
|
||||||
|
0x00, 0x00, 0x02, 0x06, 0x0E, 0x1E, 0x36, 0x42, // 0x02 ^B
|
||||||
|
0x7F, 0x22, 0x14, 0x08, 0x08, 0x14, 0x2A, 0x7F, // 0x03 ^C
|
||||||
|
0x00, 0x40, 0x20, 0x11, 0x0A, 0x04, 0x04, 0x00, // 0x04 ^D
|
||||||
|
0x7F, 0x3F, 0x5F, 0x6C, 0x75, 0x7B, 0x7B, 0x7F, // 0x05 ^E
|
||||||
|
0x70, 0x60, 0x7E, 0x31, 0x79, 0x30, 0x3F, 0x02, // 0x06 ^F
|
||||||
|
0x00, 0x18, 0x07, 0x00, 0x07, 0x0C, 0x08, 0x70, // 0x07 ^G
|
||||||
|
0x08, 0x04, 0x02, 0x7F, 0x02, 0x04, 0x08, 0x00, // 0x08 ^H
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, // 0x09 ^I
|
||||||
|
0x08, 0x08, 0x08, 0x08, 0x49, 0x2A, 0x1C, 0x08, // 0x0A ^J
|
||||||
|
0x08, 0x1C, 0x2A, 0x49, 0x08, 0x08, 0x08, 0x08, // 0x0B ^K
|
||||||
|
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0C ^L
|
||||||
|
0x40, 0x40, 0x40, 0x44, 0x46, 0x7F, 0x06, 0x04, // 0x0D ^M
|
||||||
|
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, // 0x0E ^N
|
||||||
|
0x13, 0x18, 0x1C, 0x7E, 0x1C, 0x18, 0x10, 0x6F, // 0x0F ^O
|
||||||
|
0x64, 0x0C, 0x1C, 0x3F, 0x1C, 0x0C, 0x04, 0x7B, // 0x10 ^P
|
||||||
|
0x40, 0x48, 0x08, 0x7F, 0x3E, 0x1C, 0x48, 0x40, // 0x11 ^Q
|
||||||
|
0x40, 0x48, 0x1C, 0x3E, 0x7E, 0x08, 0x48, 0x40, // 0x12 ^R
|
||||||
|
0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, // 0x13 ^S
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7F, // 0x14 ^T
|
||||||
|
0x08, 0x10, 0x20, 0x7F, 0x20, 0x10, 0x08, 0x00, // 0x15 ^U
|
||||||
|
0x2A, 0x55, 0x2A, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 0x16 ^V
|
||||||
|
0x55, 0x2A, 0x55, 0x2A, 0x55, 0x2A, 0x55, 0x2A, // 0x17 ^W
|
||||||
|
0x00, 0x3E, 0x41, 0x01, 0x01, 0x01, 0x7F, 0x00, // 0x18 ^X
|
||||||
|
0x00, 0x00, 0x3F, 0x40, 0x40, 0x40, 0x7F, 0x00, // 0x19 ^Y
|
||||||
|
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x1A ^Z
|
||||||
|
0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, 0x00, // 0x1B ^[
|
||||||
|
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, // 0x1C ^
|
||||||
|
0x14, 0x14, 0x77, 0x00, 0x77, 0x14, 0x14, 0x00, // 0x1D ^]
|
||||||
|
0x7F, 0x40, 0x40, 0x4C, 0x4C, 0x40, 0x40, 0x7F, // 0x1E ^^
|
||||||
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x1F ^_
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 space
|
||||||
|
0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, // 0x21 !
|
||||||
|
0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x22 "
|
||||||
|
0x14, 0x14, 0x3E, 0x14, 0x3E, 0x14, 0x14, 0x00, // 0x23 #
|
||||||
|
0x08, 0x3C, 0x0A, 0x1C, 0x28, 0x1E, 0x08, 0x00, // 0x24 $
|
||||||
|
0x06, 0x26, 0x10, 0x08, 0x04, 0x32, 0x30, 0x00, // 0x25 %
|
||||||
|
0x04, 0x0A, 0x0A, 0x04, 0x2A, 0x12, 0x2C, 0x00, // 0x26 &
|
||||||
|
0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x27 '
|
||||||
|
0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, // 0x28 (
|
||||||
|
0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, // 0x29 )
|
||||||
|
0x08, 0x2A, 0x1C, 0x08, 0x1C, 0x2A, 0x08, 0x00, // 0x2A *
|
||||||
|
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, // 0x2B +
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x04, 0x00, // 0x2C ,
|
||||||
|
0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, // 0x2D -
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, // 0x2E .
|
||||||
|
0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, // 0x2F /
|
||||||
|
0x1C, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x1C, 0x00, // 0x30 0
|
||||||
|
0x08, 0x0C, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, // 0x31 1
|
||||||
|
0x1C, 0x22, 0x20, 0x18, 0x04, 0x02, 0x3E, 0x00, // 0x32 2
|
||||||
|
0x3E, 0x20, 0x10, 0x18, 0x20, 0x22, 0x1C, 0x00, // 0x33 3
|
||||||
|
0x10, 0x18, 0x14, 0x12, 0x3E, 0x10, 0x10, 0x00, // 0x34 4
|
||||||
|
0x3E, 0x02, 0x1E, 0x20, 0x20, 0x22, 0x1C, 0x00, // 0x35 5
|
||||||
|
0x38, 0x04, 0x02, 0x1E, 0x22, 0x22, 0x1C, 0x00, // 0x36 6
|
||||||
|
0x3E, 0x20, 0x10, 0x08, 0x04, 0x04, 0x04, 0x00, // 0x37 7
|
||||||
|
0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, // 0x38 8
|
||||||
|
0x1C, 0x22, 0x22, 0x3C, 0x20, 0x10, 0x0E, 0x00, // 0x39 9
|
||||||
|
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, // 0x3A :
|
||||||
|
0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x04, 0x00, // 0x3B ;
|
||||||
|
0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, // 0x3C <
|
||||||
|
0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, // 0x3D =
|
||||||
|
0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, // 0x3E >
|
||||||
|
0x1C, 0x22, 0x10, 0x08, 0x08, 0x00, 0x08, 0x00, // 0x3F ?
|
||||||
|
0x1C, 0x22, 0x2A, 0x3A, 0x1A, 0x02, 0x3C, 0x00, // 0x40 @
|
||||||
|
0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, // 0x41 A
|
||||||
|
0x1E, 0x22, 0x22, 0x1E, 0x22, 0x22, 0x1E, 0x00, // 0x42 B
|
||||||
|
0x1C, 0x22, 0x02, 0x02, 0x02, 0x22, 0x1C, 0x00, // 0x43 C
|
||||||
|
0x1E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x00, // 0x44 D
|
||||||
|
0x3E, 0x02, 0x02, 0x1E, 0x02, 0x02, 0x3E, 0x00, // 0x45 E
|
||||||
|
0x3E, 0x02, 0x02, 0x1E, 0x02, 0x02, 0x02, 0x00, // 0x46 F
|
||||||
|
0x3C, 0x02, 0x02, 0x02, 0x32, 0x22, 0x3C, 0x00, // 0x47 G
|
||||||
|
0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, // 0x48 H
|
||||||
|
0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, // 0x49 I
|
||||||
|
0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, // 0x4A J
|
||||||
|
0x22, 0x12, 0x0A, 0x06, 0x0A, 0x12, 0x22, 0x00, // 0x4B K
|
||||||
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x3E, 0x00, // 0x4C L
|
||||||
|
0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, // 0x4D M
|
||||||
|
0x22, 0x22, 0x26, 0x2A, 0x32, 0x22, 0x22, 0x00, // 0x4E N
|
||||||
|
0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, // 0x4F O
|
||||||
|
0x1E, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x02, 0x00, // 0x50 P
|
||||||
|
0x1C, 0x22, 0x22, 0x22, 0x2A, 0x12, 0x2C, 0x00, // 0x51 Q
|
||||||
|
0x1E, 0x22, 0x22, 0x1E, 0x0A, 0x12, 0x22, 0x00, // 0x52 R
|
||||||
|
0x1C, 0x22, 0x02, 0x1C, 0x20, 0x22, 0x1C, 0x00, // 0x53 S
|
||||||
|
0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, // 0x54 T
|
||||||
|
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, // 0x55 U
|
||||||
|
0x22, 0x22, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, // 0x56 V
|
||||||
|
0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, // 0x57 W
|
||||||
|
0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, // 0x58 X
|
||||||
|
0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, // 0x59 Y
|
||||||
|
0x3E, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3E, 0x00, // 0x5A Z
|
||||||
|
0x3E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3E, 0x00, // 0x5B [
|
||||||
|
0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, // 0x5C back slash
|
||||||
|
0x3E, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3E, 0x00, // 0x5D ]
|
||||||
|
0x00, 0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, // 0x5E ^
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, // 0x5F _
|
||||||
|
0x04, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 `
|
||||||
|
0x00, 0x00, 0x1C, 0x20, 0x3C, 0x22, 0x3C, 0x00, // 0x61 a
|
||||||
|
0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, // 0x62 b
|
||||||
|
0x00, 0x00, 0x3C, 0x02, 0x02, 0x02, 0x3C, 0x00, // 0x63 c
|
||||||
|
0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, // 0x64 d
|
||||||
|
0x00, 0x00, 0x1C, 0x22, 0x3E, 0x02, 0x3C, 0x00, // 0x65 e
|
||||||
|
0x18, 0x24, 0x04, 0x1E, 0x04, 0x04, 0x04, 0x00, // 0x66 f
|
||||||
|
0x00, 0x00, 0x1C, 0x22, 0x22, 0x3C, 0x20, 0x1C, // 0x67 g
|
||||||
|
0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x22, 0x00, // 0x68 h
|
||||||
|
0x08, 0x00, 0x0C, 0x08, 0x08, 0x08, 0x1C, 0x00, // 0x69 i
|
||||||
|
0x10, 0x00, 0x18, 0x10, 0x10, 0x10, 0x12, 0x0C, // 0x6A j
|
||||||
|
0x02, 0x02, 0x22, 0x12, 0x0E, 0x12, 0x22, 0x00, // 0x6B k
|
||||||
|
0x0C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, // 0x6C l
|
||||||
|
0x00, 0x00, 0x36, 0x2A, 0x2A, 0x2A, 0x22, 0x00, // 0x6D m
|
||||||
|
0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x22, 0x00, // 0x6E n
|
||||||
|
0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, // 0x6F o
|
||||||
|
0x00, 0x00, 0x1E, 0x22, 0x22, 0x1E, 0x02, 0x02, // 0x70 p
|
||||||
|
0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, // 0x71 q
|
||||||
|
0x00, 0x00, 0x3A, 0x06, 0x02, 0x02, 0x02, 0x00, // 0x72 r
|
||||||
|
0x00, 0x00, 0x3C, 0x02, 0x1C, 0x20, 0x1E, 0x00, // 0x73 s
|
||||||
|
0x04, 0x04, 0x1E, 0x04, 0x04, 0x24, 0x18, 0x00, // 0x74 t
|
||||||
|
0x00, 0x00, 0x22, 0x22, 0x22, 0x32, 0x2C, 0x00, // 0x75 u
|
||||||
|
0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, // 0x76 v
|
||||||
|
0x00, 0x00, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x00, // 0x77 w
|
||||||
|
0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, // 0x78 x
|
||||||
|
0x00, 0x00, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x1C, // 0x79 y
|
||||||
|
0x00, 0x00, 0x3E, 0x10, 0x08, 0x04, 0x3E, 0x00, // 0x7A z
|
||||||
|
0x38, 0x0C, 0x0C, 0x06, 0x0C, 0x0C, 0x38, 0x00, // 0x7B {
|
||||||
|
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // 0x7C |
|
||||||
|
0x0E, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0E, 0x00, // 0x7D }
|
||||||
|
0x2C, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x7E ~
|
||||||
|
0x00, 0x2A, 0x14, 0x2A, 0x14, 0x2A, 0x00, 0x00 // 0x7F DEL
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate the font arrays from the above array
|
||||||
|
int raw;
|
||||||
|
for (int c=0; c<128; c++) {
|
||||||
|
for (int y=0; y<8; y++) {
|
||||||
|
raw = FONT[c*8 + y];
|
||||||
|
for (int x=0; x<7; x++) {
|
||||||
|
if (raw & (1<<x)) {
|
||||||
|
fontInverse[c][y][x]= 0xFF000000;
|
||||||
|
fontNormal[c][y][x]= 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fontInverse[c][y][x]= 0xFFFFFFFF;
|
||||||
|
fontNormal[c][y][x]= 0xFF000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Video::~Video() {
|
||||||
|
// delete[] fontInverse;
|
||||||
|
// delete[] fontNormal;
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Video::clearCache() {
|
||||||
|
memset(previousDots, -2, sizeof(previousDots));
|
||||||
|
memset(previousBlocks, -2, sizeof(previousBlocks));
|
||||||
|
memset(previousChars, -2, sizeof(previousChars));
|
||||||
|
memset(previousChars80,-2, sizeof(previousChars80));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Video::update() {
|
||||||
|
|
||||||
|
// Note: Colors may vary, depending upon the controls on the monitor or TV set
|
||||||
|
const uint32_t lcolor[16] = { // the 16 low res colors
|
||||||
|
0xFF000000, 0xFF5639E2, 0xFFCD741C, 0xFFAD6E7E,
|
||||||
|
0xFF80811F, 0xFF7A8289, 0xFFE4A856, 0xFFDFB290,
|
||||||
|
0xFF225897, 0xFF156CEA, 0xFF8F979E, 0xFFF0CEFF,
|
||||||
|
0xFF31C090, 0xFFA6FDFF, 0xFFD5D29F, 0xFFFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t hcolor[16] = { // the high res colors (light & dark levels)
|
||||||
|
0xFF000000, 0xFF31C090, 0xFFAD6E7E, 0xFFFFFFFF,
|
||||||
|
0xFF000000, 0xFF156CEA, 0xFFE4A856, 0xFFFFFFFF,
|
||||||
|
0xFF000000, 0xFF56373f, 0xFF196048, 0xFFFFFFFF,
|
||||||
|
0xFF000000, 0xFF72542B, 0xFF0A3675, 0xFFFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t dhcolor[16] = {
|
||||||
|
0xFF000000, 0xFFCD741C, 0xFF80811F, 0xFFDFB290,
|
||||||
|
0xFF225897, 0xFF7A8289, 0xFF31C090, 0xFFE4A856,
|
||||||
|
0xFF5639E2, 0xFFAD6E7E, 0xFF8F979E, 0xFFD5D29F,
|
||||||
|
0xFF156CEA, 0xFFF0CEFF, 0xFFA6FDFF, 0xFFFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint16_t offsetGR[24] = { // base addresses for each line in TEXT or GR
|
||||||
|
0x000, 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, // lines 0-7
|
||||||
|
0x028, 0x0A8, 0x128, 0x1A8, 0x228, 0x2A8, 0x328, 0x3A8, // lines 8-15
|
||||||
|
0x050, 0x0D0, 0x150, 0x1D0, 0x250, 0x2D0, 0x350, 0x3D0 // lines 16-23
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint16_t offsetHGR[192] = { // base addresses for each line in HGR
|
||||||
|
0x0000, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00, // lines 0-7
|
||||||
|
0x0080, 0x0480, 0x0880, 0x0C80, 0x1080, 0x1480, 0x1880, 0x1C80, // lines 8-15
|
||||||
|
0x0100, 0x0500, 0x0900, 0x0D00, 0x1100, 0x1500, 0x1900, 0x1D00, // lines 16-23
|
||||||
|
0x0180, 0x0580, 0x0980, 0x0D80, 0x1180, 0x1580, 0x1980, 0x1D80,
|
||||||
|
0x0200, 0x0600, 0x0A00, 0x0E00, 0x1200, 0x1600, 0x1A00, 0x1E00,
|
||||||
|
0x0280, 0x0680, 0x0A80, 0x0E80, 0x1280, 0x1680, 0x1A80, 0x1E80,
|
||||||
|
0x0300, 0x0700, 0x0B00, 0x0F00, 0x1300, 0x1700, 0x1B00, 0x1F00,
|
||||||
|
0x0380, 0x0780, 0x0B80, 0x0F80, 0x1380, 0x1780, 0x1B80, 0x1F80,
|
||||||
|
0x0028, 0x0428, 0x0828, 0x0C28, 0x1028, 0x1428, 0x1828, 0x1C28,
|
||||||
|
0x00A8, 0x04A8, 0x08A8, 0x0CA8, 0x10A8, 0x14A8, 0x18A8, 0x1CA8,
|
||||||
|
0x0128, 0x0528, 0x0928, 0x0D28, 0x1128, 0x1528, 0x1928, 0x1D28,
|
||||||
|
0x01A8, 0x05A8, 0x09A8, 0x0DA8, 0x11A8, 0x15A8, 0x19A8, 0x1DA8,
|
||||||
|
0x0228, 0x0628, 0x0A28, 0x0E28, 0x1228, 0x1628, 0x1A28, 0x1E28,
|
||||||
|
0x02A8, 0x06A8, 0x0AA8, 0x0EA8, 0x12A8, 0x16A8, 0x1AA8, 0x1EA8,
|
||||||
|
0x0328, 0x0728, 0x0B28, 0x0F28, 0x1328, 0x1728, 0x1B28, 0x1F28,
|
||||||
|
0x03A8, 0x07A8, 0x0BA8, 0x0FA8, 0x13A8, 0x17A8, 0x1BA8, 0x1FA8,
|
||||||
|
0x0050, 0x0450, 0x0850, 0x0C50, 0x1050, 0x1450, 0x1850, 0x1C50,
|
||||||
|
0x00D0, 0x04D0, 0x08D0, 0x0CD0, 0x10D0, 0x14D0, 0x18D0, 0x1CD0,
|
||||||
|
0x0150, 0x0550, 0x0950, 0x0D50, 0x1150, 0x1550, 0x1950, 0x1D50,
|
||||||
|
0x01D0, 0x05D0, 0x09D0, 0x0DD0, 0x11D0, 0x15D0, 0x19D0, 0x1DD0,
|
||||||
|
0x0250, 0x0650, 0x0A50, 0x0E50, 0x1250, 0x1650, 0x1A50, 0x1E50,
|
||||||
|
0x02D0, 0x06D0, 0x0AD0, 0x0ED0, 0x12D0, 0x16D0, 0x1AD0, 0x1ED0, // lines 168-183
|
||||||
|
0x0350, 0x0750, 0x0B50, 0x0F50, 0x1350, 0x1750, 0x1B50, 0x1F50, // lines 176-183
|
||||||
|
0x03D0, 0x07D0, 0x0BD0, 0x0FD0, 0x13D0, 0x17D0, 0x1BD0, 0x1FD0 // lines 184-191
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// HIGH RES GRAPHICS
|
||||||
|
if (!mmu->TEXT && mmu->HIRES && !mmu->DHIRES) {
|
||||||
|
gfxmode = 40;
|
||||||
|
uint8_t colorIdx; // index to the color array
|
||||||
|
uint16_t word;
|
||||||
|
uint8_t bits[16], bit, pbit, colorSet, even;
|
||||||
|
int vRamBase = 0x2000 + mmu->PAGE2 * 0x2000;
|
||||||
|
int endRaw = mmu->MIXED ? 160 : 192;
|
||||||
|
|
||||||
|
for (int line = 0; line < endRaw; line++) { // for every line
|
||||||
|
for (int col = 0; col < 40; col += 2) { // for every 7 horizontal dots
|
||||||
|
word = (uint16_t)(mmu->ram[vRamBase + offsetHGR[line] + col + 1]) << 8; // store the two next bytes into 'word'
|
||||||
|
word += mmu->ram[vRamBase + offsetHGR[line] + col]; // in reverse order
|
||||||
|
|
||||||
|
if (previousDots[line][col] != word) { // check if this group of 7 dots need a redraw
|
||||||
|
|
||||||
|
int x = col * 7;
|
||||||
|
even = 0;
|
||||||
|
|
||||||
|
for (bit = 0; bit < 16; bit++) // store all bits 'word' into 'bits'
|
||||||
|
bits[bit] = (word >> bit) & 1;
|
||||||
|
colorSet = bits[7] * 4; // select the right color set
|
||||||
|
pbit = previousBit[line][col]; // the bit value of the left dot
|
||||||
|
bit = 0; // starting at 1st bit of 1st byte
|
||||||
|
|
||||||
|
while (bit < 15) { // until we reach bit7 of 2nd byte
|
||||||
|
if (bit == 7) { // moving into the second byte
|
||||||
|
colorSet = bits[15] * 4; // update the color set
|
||||||
|
bit++; // skip bit 7
|
||||||
|
}
|
||||||
|
|
||||||
|
colorIdx = even + colorSet + (bits[bit] << 1) + (pbit);
|
||||||
|
screenPixels[line * 280 + x] = hcolor[colorIdx];
|
||||||
|
|
||||||
|
x++;
|
||||||
|
pbit = bits[bit++]; // proceed to the next pixel
|
||||||
|
even = even ? 0 : 8; // one pixel every two is darker
|
||||||
|
}
|
||||||
|
|
||||||
|
previousDots[line][col] = word; // update the video cache
|
||||||
|
if ((col < 37) && (previousBit[line][col + 2] != pbit)) { // check color franging effect on the dot after
|
||||||
|
previousBit[line][col + 2] = pbit; // set pbit and clear the
|
||||||
|
previousDots[line][col + 2] = -1; // video cache for next dot
|
||||||
|
}
|
||||||
|
} // if (previousDots[line][col] ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DOUBLE HIGH RES GRAPHICS
|
||||||
|
else if (!mmu->TEXT && mmu->HIRES && mmu->DHIRES) {
|
||||||
|
gfxmode = 80;
|
||||||
|
// int vRamBase = 0x2000 + PAGE2 * 0x2000;
|
||||||
|
int vRamBase = mmu->STORE80 ? 0x2000 : mmu->PAGE2 * 0x2000 + 0x2000; // TODO : CHECK THIS !
|
||||||
|
int endRaw = mmu->MIXED ? 160 : 192;
|
||||||
|
uint32_t color;
|
||||||
|
uint32_t dword;
|
||||||
|
|
||||||
|
for (int line = 0; line < endRaw; line++) {
|
||||||
|
for (int col = 0, x = 0; col < 39; col+=2) {
|
||||||
|
|
||||||
|
int address = vRamBase + offsetHGR[line] + col;
|
||||||
|
|
||||||
|
// combine 4 bytes of memory, from MAIN and AUX
|
||||||
|
dword = (uint32_t)(mmu->aux[address] & 0x7F);
|
||||||
|
dword |= (uint32_t)(mmu->ram[address] & 0x7F) << 7;
|
||||||
|
address++;
|
||||||
|
dword |= (uint32_t)(mmu->aux[address] & 0x7F) << 14;
|
||||||
|
dword |= (uint32_t)(mmu->ram[address] & 0x7F) << 21;
|
||||||
|
|
||||||
|
int offset1 = 560 * line * 2;
|
||||||
|
int offset2 = 560 + offset1;
|
||||||
|
|
||||||
|
for (int p=0; p<7; p++, dword >>= 4) {
|
||||||
|
color = dhcolor[dword & 0x0F];
|
||||||
|
for (int a=0; a<4; a++, x++) { // draw 4x2 pixels
|
||||||
|
screenPixels80[offset1 + x] = color;
|
||||||
|
screenPixels80[offset2 + x] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lOW RES GRAPHICS
|
||||||
|
else if (!mmu->TEXT && !mmu->HIRES && !mmu->DHIRES) { // and not in HIRES
|
||||||
|
gfxmode = 40;
|
||||||
|
int vRamBase = mmu->PAGE2 * 0x0400 + 0x400;
|
||||||
|
int endRaw = mmu->MIXED ? 20 : 24;
|
||||||
|
uint32_t color;
|
||||||
|
for (int col = 0; col < 40; col++) { // for each column
|
||||||
|
int x = col * 7;
|
||||||
|
for (int line = 0; line < endRaw; line++) { // for each row
|
||||||
|
|
||||||
|
glyph = mmu->ram[vRamBase + offsetGR[line] + col]; // read video memory
|
||||||
|
|
||||||
|
if (previousBlocks[line][col] != glyph) { // check if this block need a redraw
|
||||||
|
previousBlocks[line][col] = glyph;
|
||||||
|
|
||||||
|
int y = line * 8; // first block
|
||||||
|
color = lcolor[glyph & 0x0F]; // first nibble
|
||||||
|
for (int a=0; a<7; a++)
|
||||||
|
for (int b=0; b<4; b++)
|
||||||
|
screenPixels[(y+b) * 280 + x + a] = color;
|
||||||
|
|
||||||
|
y += 4; // second block
|
||||||
|
color = lcolor[(glyph & 0xF0) >> 4]; // second nibble
|
||||||
|
for (int a=0; a<7; a++)
|
||||||
|
for (int b=0; b<4; b++)
|
||||||
|
screenPixels[(y+b) * 280 + x + a] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DOUBLE lOW RES GRAPHICS
|
||||||
|
else if (!mmu->TEXT && !mmu->HIRES && mmu->DHIRES) {
|
||||||
|
gfxmode = 80;
|
||||||
|
int vRamBase = mmu->PAGE2 * 0x0400 + 0x400; // TODO : CHECK THIS !
|
||||||
|
int endRaw = mmu->MIXED ? 20 : 24;
|
||||||
|
int x, y;
|
||||||
|
uint32_t color;
|
||||||
|
for (int col = 0; col < 40; col++) { // for each column
|
||||||
|
x = col * 14;
|
||||||
|
for (int line = 0; line < endRaw; line++) { // for each row
|
||||||
|
y = line * 16; // first block
|
||||||
|
|
||||||
|
glyph = mmu->aux[vRamBase + offsetGR[line] + col]; // read AUX video memory
|
||||||
|
color = lcolor[glyph & 0x0F]; // first nibble
|
||||||
|
for (int a=0; a<7; a++)
|
||||||
|
for (int b=0; b<8; b++)
|
||||||
|
screenPixels80[(y+b) * 560 + (x+a)] = color;
|
||||||
|
|
||||||
|
color = lcolor[(glyph & 0xF0) >> 4]; // second nibble
|
||||||
|
for (int a=0; a<7; a++)
|
||||||
|
for (int b=8; b<16; b++)
|
||||||
|
screenPixels80[(y+b) * 560 + (x+a)] = color;
|
||||||
|
|
||||||
|
glyph = mmu->ram[vRamBase + offsetGR[line] + col]; // read MAIN video memory
|
||||||
|
color = lcolor[glyph & 0x0F]; // first nibble
|
||||||
|
for (int a=7; a<14; a++)
|
||||||
|
for (int b=0; b<8; b++)
|
||||||
|
screenPixels80[(y+b) * 560 + (x+a)] = color;
|
||||||
|
|
||||||
|
color = lcolor[(glyph & 0xF0) >> 4]; // second nibble
|
||||||
|
for (int a=7; a<14; a++)
|
||||||
|
for (int b=8; b<16; b++)
|
||||||
|
screenPixels80[(y+b) * 560 + (x+a)] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEXT 40 COLUMNS
|
||||||
|
if (!mmu->COL80 && (mmu->TEXT || mmu->MIXED)) {
|
||||||
|
gfxmode = 40;
|
||||||
|
int vRamBase = mmu->PAGE2 * 0x0400 + 0x400;
|
||||||
|
int startRaw = mmu->TEXT ? 0 : 20;
|
||||||
|
for (int col = 0; col < 40; col++) { // for each column
|
||||||
|
for (int line = startRaw; line < 24; line++) { // for each row
|
||||||
|
|
||||||
|
glyph = mmu->ram[vRamBase + offsetGR[line] + col]; // read video memory
|
||||||
|
|
||||||
|
if (glyph > 0x7F) glyphAttr = A_NORMAL; // is NORMAL ?
|
||||||
|
else if (glyph < 0x40) glyphAttr = A_INVERSE; // is INVERSE ?
|
||||||
|
else glyphAttr = A_FLASH; // it's FLASH !
|
||||||
|
|
||||||
|
if (previousChars[line][col] != (glyph <<(8*mmu->ALTCHARSET)) || glyphAttr == A_FLASH) { // check if this char need a redraw
|
||||||
|
previousChars[line][col] = (glyph <<(8*mmu->ALTCHARSET));
|
||||||
|
|
||||||
|
glyph &= 0x7F; // unset bit 7
|
||||||
|
if (glyph < 0x20) glyph |= 0x40; // shifts to match the ASCII codes
|
||||||
|
|
||||||
|
if ((!mmu->ALTCHARSET) && (glyphAttr == A_FLASH) && (glyph > 0x5F))
|
||||||
|
glyph &= 0x3F;
|
||||||
|
|
||||||
|
if (mmu->ALTCHARSET && (glyphAttr == A_FLASH)) {
|
||||||
|
if (glyph >= 0x40 && glyph < 0x60) {
|
||||||
|
glyph &= 0x3F;
|
||||||
|
glyphAttr = A_NORMAL;
|
||||||
|
}
|
||||||
|
else if (glyph >= 0x60)
|
||||||
|
glyphAttr = A_INVERSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glyphAttr == A_NORMAL || ((glyphAttr == A_FLASH) && (gui->frameNumber % 30 < 16))) {
|
||||||
|
for (int yy=0; yy<8; yy++)
|
||||||
|
for (int xx=0; xx<7; xx++)
|
||||||
|
screenPixels[(yy+line*8)*280 + (xx+(col*7))] = fontNormal[glyph][yy][xx];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int yy=0; yy<8; yy++)
|
||||||
|
for (int xx=0; xx<7; xx++)
|
||||||
|
screenPixels[(yy+line*8)*280 + (xx+(col*7))] = fontInverse[glyph][yy][xx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEXT 80 COLUMNS
|
||||||
|
else if (mmu->COL80 && (mmu->TEXT || mmu->MIXED)) {
|
||||||
|
gfxmode = 80;
|
||||||
|
int startRaw = mmu->TEXT ? 0 : 20;
|
||||||
|
int vRamBase = 0x0400; // + PAGE2 * 0x400;
|
||||||
|
|
||||||
|
for (int col = 0; col < 40; col++) { // for each column
|
||||||
|
for (int line = startRaw; line < 24; line++) { // for each row
|
||||||
|
glyph = mmu->ram[vRamBase + offsetGR[line] + col]; // read video memory in Main memory
|
||||||
|
|
||||||
|
if (glyph > 0x7F) glyphAttr = A_NORMAL; // is NORMAL ?
|
||||||
|
else if (glyph < 0x40) glyphAttr = A_INVERSE; // is INVERSE ?
|
||||||
|
else glyphAttr = A_FLASH; // it's FLASH !
|
||||||
|
|
||||||
|
if (previousChars[line][col] != (glyph <<(8*mmu->ALTCHARSET)) || glyphAttr == A_FLASH) { // check if this char need a redraw
|
||||||
|
previousChars[line][col] = (glyph <<(8*mmu->ALTCHARSET));
|
||||||
|
|
||||||
|
glyph &= 0x7F; // unset bit 7
|
||||||
|
if (glyph < 0x20) glyph |= 0x40; // shifts to match the ASCII codes
|
||||||
|
|
||||||
|
if ((!mmu->ALTCHARSET) && (glyphAttr == A_FLASH) && (glyph > 0x5F))
|
||||||
|
glyph &= 0x3F;
|
||||||
|
|
||||||
|
if (mmu->ALTCHARSET && (glyphAttr == A_FLASH)) {
|
||||||
|
if (glyph >= 0x40 && glyph < 0x60) {
|
||||||
|
glyph &= 0x3F;
|
||||||
|
glyphAttr = A_NORMAL;
|
||||||
|
}
|
||||||
|
else if (glyph >= 0x60)
|
||||||
|
glyphAttr = A_INVERSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glyphAttr == A_NORMAL || ((glyphAttr == A_FLASH) && (gui->frameNumber % 30 < 16))) {
|
||||||
|
for (int yy=0; yy<16; yy+=2)
|
||||||
|
for (int xx=0; xx<7; xx++){
|
||||||
|
screenPixels80[(yy+line*16)*560 + (xx+(((col*2)+1)*7))] = fontNormal[glyph][yy/2][xx];
|
||||||
|
screenPixels80[(1+yy+line*16)*560 + (xx+(((col*2)+1)*7))] = fontNormal[glyph][yy/2][xx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int yy=0; yy<16; yy+=2)
|
||||||
|
for (int xx=0; xx<7; xx++){
|
||||||
|
screenPixels80[(yy+line*16)*560 + (xx+(((col*2)+1)*7))] = fontInverse[glyph][yy/2][xx];
|
||||||
|
screenPixels80[(1+yy+line*16)*560 + (xx+(((col*2)+1)*7))] = fontInverse[glyph][yy/2][xx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glyph = mmu->aux[vRamBase + offsetGR[line] + col]; // read video memory in Auxiliary Memory
|
||||||
|
|
||||||
|
if (glyph > 0x7F) glyphAttr = A_NORMAL; // is NORMAL ?
|
||||||
|
else if (glyph < 0x40) glyphAttr = A_INVERSE; // is INVERSE ?
|
||||||
|
else glyphAttr = A_FLASH; // it's FLASH !
|
||||||
|
|
||||||
|
if (previousChars80[line][col] != (glyph <<(8*mmu->ALTCHARSET)) || glyphAttr == A_FLASH) { // check if this char need a redraw
|
||||||
|
previousChars80[line][col] = (glyph <<(8*mmu->ALTCHARSET));
|
||||||
|
|
||||||
|
glyph &= 0x7F; // unset bit 7
|
||||||
|
if (glyph < 0x20) glyph |= 0x40; // shifts to match the ASCII codes
|
||||||
|
|
||||||
|
if ((!mmu->ALTCHARSET) && (glyphAttr == A_FLASH) && (glyph > 0x5F))
|
||||||
|
glyph &= 0x3F;
|
||||||
|
|
||||||
|
if (mmu->ALTCHARSET && (glyphAttr == A_FLASH)) {
|
||||||
|
if (glyph >= 0x40 && glyph < 0x60) {
|
||||||
|
glyph &= 0x3F;
|
||||||
|
glyphAttr = A_NORMAL;
|
||||||
|
}
|
||||||
|
else if (glyph >= 0x60)
|
||||||
|
glyphAttr = A_INVERSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glyphAttr == A_NORMAL || ((glyphAttr == A_FLASH) && (gui->frameNumber % 30 < 16))) {
|
||||||
|
for (int yy=0; yy<16; yy+=2)
|
||||||
|
for (int xx=0; xx<7; xx++) {
|
||||||
|
screenPixels80[(yy+line*16)*560 + (xx+(col*2*7))] = fontNormal[glyph][yy/2][xx];
|
||||||
|
screenPixels80[(1+yy+line*16)*560 + (xx+(col*2*7))] = fontNormal[glyph][yy/2][xx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int yy=0; yy<16; yy+=2)
|
||||||
|
for (int xx=0; xx<7; xx++) {
|
||||||
|
screenPixels80[(yy+line*16)*560 + (xx+(col*2*7))] = fontInverse[glyph][yy/2][xx];
|
||||||
|
screenPixels80[(1+yy+line*16)*560 + (xx+(col*2*7))] = fontInverse[glyph][yy/2][xx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update ram & aux HEATMAPS (fade out green and red components)
|
||||||
|
for (int address=0; address<65536; address++){
|
||||||
|
if (ramHeatmap[address] & 0x000000FF)
|
||||||
|
ramHeatmap[address]--;
|
||||||
|
if (ramHeatmap[address] & 0x0000FF00)
|
||||||
|
ramHeatmap[address] -= 256;
|
||||||
|
|
||||||
|
if (auxHeatmap[address] & 0x000000FF)
|
||||||
|
auxHeatmap[address]--;
|
||||||
|
if (auxHeatmap[address] & 0x0000FF00)
|
||||||
|
auxHeatmap[address] -= 256;
|
||||||
|
}
|
||||||
|
}
|
56
video.h
Normal file
56
video.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* reinette, a french Apple II emulator, using SDL2
|
||||||
|
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
|
||||||
|
* Last modified 1st of July 2021
|
||||||
|
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _VIDEO_H
|
||||||
|
#define _VIDEO_H
|
||||||
|
|
||||||
|
class Video {
|
||||||
|
public:
|
||||||
|
int gfxmode;
|
||||||
|
uint8_t glyph; // a TEXT character, or 2 blocks in GR
|
||||||
|
enum characterAttribute { A_NORMAL, A_INVERSE, A_FLASH } glyphAttr; // character attribute in TEXT
|
||||||
|
uint8_t previousBit[192][40] = {0}; // the last bit value of the byte before.
|
||||||
|
|
||||||
|
int previousDots[192][40] = {0}; // check which Hi-Res 7 dots needs redraw
|
||||||
|
int previousBlocks[24][40] = {0}; // check which Lo-Res blocks or text chars needs redraw
|
||||||
|
int previousChars[24][40] = {0}; // check which Lo-Res blocks or text chars needs redraw
|
||||||
|
int previousChars80[24][40] = {0}; // check which Lo-Res blocks or text chars needs redraw
|
||||||
|
|
||||||
|
uint32_t fontNormal[128][8][7]; // normal font
|
||||||
|
uint32_t fontInverse[128][8][7]; // reversed font
|
||||||
|
|
||||||
|
uint32_t screenPixels[280*192] = {0xFF000000};
|
||||||
|
uint32_t screenPixels80[560*384] = {0xFF000000};
|
||||||
|
uint32_t ramHeatmap[256*256] = {0xFF000000};
|
||||||
|
uint32_t auxHeatmap[256*256] = {0xFF000000};
|
||||||
|
|
||||||
|
Video();
|
||||||
|
~Video();
|
||||||
|
|
||||||
|
void update();
|
||||||
|
void clearCache();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user