blob: 0ee6aa2391b949cc4a0c691a338f9378a1cf1048 [file] [log] [blame] [raw]
/*
YAPE - Yet Another Plus/4 Emulator
The program emulates the Commodore 264 family of 8 bit microcomputers
This program is free software, you are welcome to distribute it,
and/or modify it under certain conditions. For more information,
read 'Copying'.
(c) 2000, 2001, 2004, 2005, 2007, 2015 Attila Grósz
(c) 2005 VENESZ Roland
*/
#define NAME "Yape/SDL 0.70.1"
#define WINDOWX SCREENX
#define WINDOWY SCREENY
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#ifdef _WIN32
#include <SDL/SDL.h>
#else
#include <SDL2/SDL.h>
#endif
#include "keyboard.h"
#include "cpu.h"
#include "tedmem.h"
#include "tape.h"
#include "sound.h"
#include "archdep.h"
#include "iec.h"
#include "device.h"
#include "tcbm.h"
#include "diskfs.h"
#include "monitor.h"
#include "prg.h"
#include "interface.h"
#include "video.h"
#include "drive.h"
#include "FdcGcr.h"
#include "icon.h"
#include "vic2mem.h"
#include "SaveState.h"
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#endif
// function prototypes
static void frameUpdate();
// SDL stuff
static SDL_Window* sdlWindow;
static SDL_Renderer *sdlRenderer;
static SDL_Texture *sdlTexture = NULL;
// class pointer for the user interface
static UI *uinterface = NULL;
////////////////
// Supplementary
static unsigned int g_TotFrames = 0;
static TED *ted8360 = NULL;
static CPU *machine = NULL;
static CTCBM *tcbm = NULL;
static CIECInterface *iec = NULL;
static CIECDrive *fsdrive = NULL;
static CTrueDrive *drive1541 = NULL;
static FakeSerialDrive *fsd1541 = NULL;
//
static char textout[64];
static char *inipath;
static char *inifile;
static bool g_bActive = true;
static bool g_inDebug = false;
static bool g_FrameRate = true;
static bool g_50Hz = true;
static bool g_bSaveSettings = true;
static bool g_SoundOn = true;
static bool g_bUseOverlay = 0;
static unsigned int g_bWindowMultiplier = 2;
static unsigned int g_iEmulationLevel = 0;
static char lastSnapshotName[512] = "";
//-----------------------------------------------------------------------------
// Name: ShowFrameRate()
//-----------------------------------------------------------------------------
inline static unsigned int ShowFrameRate(bool show)
{
char fpstxt[80];
unsigned int fps = ad_get_fps();
if (show) {
sprintf(fpstxt, " %i FPS ", fps);
ted8360->texttoscreen(ted8360->getCyclesPerRow() - 128, 34, fpstxt);
}
return fps;
}
//-----------------------------------------------------------------------------
// Name: DebugInfo()
//-----------------------------------------------------------------------------
inline static void DebugInfo()
{
const unsigned int hpos = (ted8360->getCyclesPerRow() == 456 ? 48 : 112), vpos = 10;
sprintf(textout, "OPCODE: %02x ", machine->getcins());
ted8360->texttoscreen(hpos, vpos, textout);
ted8360->texttoscreen(hpos, vpos+8, " PC SR AC XR YR SP");
sprintf(textout, ";%04x %02x %02x %02x %02x %02x", machine->getPC(),
machine->getST(), machine->getAC(), machine->getX(), machine->getY(), machine->getSP());
ted8360->texttoscreen(hpos, vpos+16, textout);
sprintf(textout, "TAPE: %08d ", ted8360->tap->TapeSoFar);
CTrueDrive *d = CTrueDrive::Drives[0];
if (d) {
char driveText[64];
unsigned int t, s;
unsigned char ledState = d->getDriveMemHandler()->Read(0x1c00) & 8;
unsigned char motorState = d->GetFdc()->getMotorState() ? 4 : 0;
d->GetFdc()->trackSector(t, s);
sprintf(driveText, "DRIVE: T/S:%02u/%02u", t, s);
strcat(textout, driveText);
ted8360->texttoscreen(hpos, vpos+24, textout);
ted8360->showled(hpos+21*8, vpos+24, motorState);
ted8360->showled(hpos+22*8, vpos+24, ledState);
} else {
ted8360->texttoscreen(hpos, vpos+24, textout);
}
}
//-----------------------------------------------------------------------------
void machineReset(bool hardreset)
{
if (hardreset) {
ted8360->Reset(hardreset);
}
machine->Reset();
CTrueDrive::ResetAllDrives();
}
void machineDoSomeFrames(unsigned int frames)
{
ted8360->getKeys()->block(true);
while (frames--) {
ted8360->ted_process(1);
frameUpdate();
}
ted8360->getKeys()->block(false);
}
void machineEnable1551(bool enable)
{
if (enable) {
if (ted8360->getEmulationLevel() != 2) {
ted8360->HookTCBM(tcbm);
if (drive1541) {
delete drive1541;
drive1541 = NULL;
}
} else {
fsd1541 = new FakeSerialDrive(8);
}
}
else {
ted8360->HookTCBM(NULL);
if (fsd1541) {
delete fsd1541;
fsd1541 = NULL;
}
if (!drive1541) {
CSerial::InitPorts();
drive1541 = new CTrueDrive(1, 8);
drive1541->Reset();
}
}
}
bool machineIsTrueDriveEnabled(unsigned int dn = 8)
{
return drive1541 != NULL;
}
bool start_file(char *szFile )
{
char *pFileExt = strrchr(szFile, '.');
if (pFileExt) {
char *fileext = pFileExt;
do {
*pFileExt = tolower(*pFileExt);
pFileExt++;
} while (*pFileExt);
if (!strcmp(fileext,".d64") || !strcmp(fileext,".D64")) {
if (!machineIsTrueDriveEnabled()) {
machineEnable1551(false);
machineDoSomeFrames(70);
CTrueDrive::SwapDisk(szFile);
}
ted8360->copyToKbBuffer("L\317\042*\042,8,1\rRUN:\r", 15);
return true;
}
if (!strcmp(fileext,".prg") || !strcmp(fileext,".PRG")
|| !strcmp(fileext,".p00") || !strcmp(fileext,".P00")) {
PrgLoad(szFile, 0, ted8360 );
ted8360->copyToKbBuffer("RUN:\r",5);
return true;
}
if (!strcmp(fileext, ".t64") || !strcmp(fileext,".T64")) {
prgLoadFromT64(szFile, 0, ted8360);
ted8360->copyToKbBuffer("RUN:\r",5);
}
if (!strcmp(fileext,".tap") || !strcmp(fileext,".TAP")) {
ted8360->tap->detach_tap();
strcpy(ted8360->tap->tapefilename, szFile);
ted8360->tap->attach_tap();
return true;
}
if (!strcmp(fileext, ".yss")) {
return SaveState::openSnapshot(szFile, false);
}
return false;
}
return false;
}
bool autostart_file(char *szFile)
{
machineReset(true);
// do some frames
unsigned int frames = ted8360->getAutostartDelay();
machineDoSomeFrames(frames);
// and then try to load the parameter as file
return start_file(szFile);
}
/* ---------- Display functions ---------- */
static char popUpMessage[256] = "";
static unsigned int popupMessageTimeOut = 0;
static void showPopUpMessage()
{
unsigned int ix;
size_t len = strlen(popUpMessage);
unsigned int offset = ted8360->getCyclesPerRow() == 456 ? 456 : 592;
char dummy[40];
ix = (unsigned int)(len);
while( ix-->0)
dummy[ix] = 32;
dummy[len] = '\0';
int tab = offset / 2 - (int(len) << 2);
int line = 130;
ted8360->texttoscreen(tab, line, dummy);
ted8360->texttoscreen(tab, line + 8, popUpMessage);
ted8360->texttoscreen(tab, line + 16, dummy);
if(popupMessageTimeOut)
popupMessageTimeOut -= 1;
}
inline void PopupMsg(const char *msg, ...)
{
va_list args;
va_start(args, msg);
vsprintf(popUpMessage, msg, args);
va_end(args);
popupMessageTimeOut = 60; // frames
}
static unsigned int pixels[512 * SCR_VSIZE * 2];
void frameUpdate(unsigned char *src, unsigned int *target)
{
unsigned int i, j;
unsigned int *texture = target;
unsigned int pixelsPerRow = ted8360->getCyclesPerRow();
//
if (g_bUseOverlay) {
video_convert_buffer(target, pixelsPerRow, src);
} else {
unsigned int *palette = palette_get_rgb();
for(i = 0; i < SCREENY; i++) {
for(j = 0; j < SCREENX; j++) {
*target++ = palette[*src++];
}
src += (pixelsPerRow - SCREENX);
target += (pixelsPerRow - SCREENX);
}
}
//
int e = SDL_UpdateTexture(sdlTexture, NULL, texture, pixelsPerRow * sizeof (unsigned int));
e = SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
SDL_RenderPresent(sdlRenderer);
}
static void frameUpdate()
{
const unsigned int cyclesPerRow = ted8360->getCyclesPerRow();
const int offsetX = cyclesPerRow == 504 ? -72 : 8;
const int offsetY = cyclesPerRow == 504 ? 9 : 0;
if (popupMessageTimeOut)
showPopUpMessage();
frameUpdate(ted8360->getScreenData() + (cyclesPerRow - 384 - offsetX) / 2 + offsetY * cyclesPerRow, pixels);
}
/* ---------- Management of settings ---------- */
//-----------------------------------------------------------------------------
// Name: SaveSettings
//-----------------------------------------------------------------------------
bool SaveSettings(char *inifileName)
{
unsigned int i;
char tmpStr[MAX_PATH];
FILE *ini;
unsigned int rammask;
if ((ini = fopen(inifileName, "wt"))) {
fprintf(ini, "[Yape configuration file]\n");
fprintf(ini,"DisplayFrameRate = %d\n",g_FrameRate);
fprintf(ini,"DisplayQuickDebugInfo = %d\n",g_inDebug);
fprintf(ini,"50HzTimerActive = %d\n",g_50Hz);
fprintf(ini,"ActiveJoystick = %d\n",ted8360->getKeys()->activejoy);
rammask = ted8360->getRamMask();
fprintf(ini,"RamMask = %x\n",rammask);
fprintf(ini,"256KBRAM = %x\n",ted8360->bigram);
fprintf(ini,"SaveSettingsOnExit = %x\n",g_bSaveSettings);
for (i = 0; i<4; i++) {
fprintf(ini,"ROMC%dLOW = %s\n",i, ted8360->romlopath[i]);
fprintf(ini,"ROMC%dHIGH = %s\n",i, ted8360->romhighpath[i]);
}
ad_get_curr_dir(tmpStr);
fprintf(ini, "CurrentDirectory = %s\n", tmpStr);
fprintf(ini, "CRTEmulation = %u\n", g_bUseOverlay);
fprintf(ini, "WindowMultiplier = %u\n", g_bWindowMultiplier);
fprintf(ini, "EmulationLevel = %u\n", g_iEmulationLevel);
fclose(ini);
return true;
}
return false;
}
bool LoadSettings(char *inifileName)
{
FILE *ini;
unsigned int rammask;
char keyword[256], line[256], value[256];
if ((ini = fopen(inifileName, "r"))) {
fscanf(ini,"%s configuration file]\n", keyword);
if (strcmp(keyword, "[Yape"))
return false;
while(fgets(line, 255, ini)) {
strcpy(value, "");
if (sscanf(line, "%s = %[^,\n,\r]", keyword, value) ) {
int number = atoi(value);
if (!strcmp(keyword, "DisplayFrameRate")) {
g_FrameRate = !!atoi(value);
fprintf( stderr, "Display frame rate: %i\n", g_FrameRate);
} else if (!strcmp(keyword, "DisplayQuickDebugInfo"))
g_inDebug = !!atoi(value);
else if (!strcmp(keyword, "50HzTimerActive"))
g_50Hz = !!atoi(value);
else if (!strcmp(keyword, "ActiveJoystick"))
ted8360->getKeys()->activejoy = atoi(value);
else if (!strcmp(keyword, "RamMask")) {
sscanf( value, "%04x", &rammask);
ted8360->setRamMask( rammask );
}
else if (!strcmp(keyword, "256KBRAM"))
ted8360->bigram = !!atoi(value);
else if (!strcmp(keyword, "SaveSettingsOnExit"))
g_bSaveSettings = !!atoi(value);
else if (!strcmp(keyword, "ROMC0LOW"))
strcpy(ted8360->romlopath[0], value);
else if (!strcmp(keyword, "ROMC1LOW"))
strcpy(ted8360->romlopath[1], value);
else if (!strcmp(keyword, "ROMC2LOW"))
strcpy(ted8360->romlopath[2], value);
else if (!strcmp(keyword, "ROMC3LOW"))
strcpy(ted8360->romlopath[3], value);
else if (!strcmp(keyword, "ROMC0HIGH"))
strcpy(ted8360->romhighpath[0], value);
else if (!strcmp(keyword, "ROMC1HIGH"))
strcpy(ted8360->romhighpath[1], value);
else if (!strcmp(keyword, "ROMC2HIGH"))
strcpy(ted8360->romhighpath[2], value);
else if (!strcmp(keyword, "ROMC3HIGH"))
strcpy(ted8360->romhighpath[3], value);
else if (!strcmp(keyword, "CurrentDirectory"))
ad_set_curr_dir(value);
else if (!strcmp(keyword, "CRTEmulation"))
g_bUseOverlay = !!atoi(value);
else if (!strcmp(keyword, "WindowMultiplier"))
g_bWindowMultiplier = number ? (number & 3) : 1;
else if (!strcmp(keyword, "EmulationLevel"))
g_iEmulationLevel = atoi(value);
}
}
fclose(ini);
if (!g_50Hz)
g_SoundOn = false;
return true;
}
return false;
}
static bool saveScreenshotBMP(char* filepath, SDL_Window* SDLWindow, SDL_Renderer* SDLRenderer)
{
SDL_Surface* saveSurface = NULL;
SDL_Surface* infoSurface = NULL;
infoSurface = SDL_GetWindowSurface(SDLWindow);
if (infoSurface == NULL) {
return false;
} else {
unsigned char *pxls = new unsigned char[infoSurface->w * infoSurface->h * infoSurface->format->BytesPerPixel];
if (SDL_RenderReadPixels(SDLRenderer, &infoSurface->clip_rect, infoSurface->format->format, pxls, infoSurface->w * infoSurface->format->BytesPerPixel) != 0) {
pxls = NULL;
return false;
} else {
saveSurface = SDL_CreateRGBSurfaceFrom(pixels, infoSurface->w, infoSurface->h, infoSurface->format->BitsPerPixel,
infoSurface->w * infoSurface->format->BytesPerPixel, infoSurface->format->Rmask,
infoSurface->format->Gmask, infoSurface->format->Bmask, infoSurface->format->Amask);
if (saveSurface == NULL) {
return false;
}
SDL_SaveBMP(saveSurface, filepath);
SDL_FreeSurface(saveSurface);
saveSurface = NULL;
}
delete[] pxls;
SDL_FreeSurface(infoSurface);
infoSurface = NULL;
}
return true;
}
static bool getSerializedFilename(const char *name, const char *extension, char *out)
{
char dummy[512];
unsigned int i = 0;
if (!name || !extension || !out)
return false;
bool found = true;
do {
sprintf(dummy, "%s%06d.%s", name, i++, extension);
FILE *fp = fopen(dummy, "rb");
if (fp) {
fclose(fp);
} else {
found = false;
strcpy(out, dummy);
}
} while (found && i < 0x1000000);
return !found;
}
//-----------------------------------------------------------------------------
// Name: SaveBitmap()
// Desc: Saves the SDL surface to Windows bitmap file named as yapeXXXX.bmp
//-----------------------------------------------------------------------------
static int SaveBitmap()
{
char bmpname[512];
// finding the last yapeXXXX.bmp image
if (getSerializedFilename("yape", ".bmp", bmpname)) {
if (saveScreenshotBMP(bmpname, sdlWindow, sdlRenderer)) {
fprintf(stderr, "Screenshot saved: %s\n", bmpname);
return true;
}
}
return false;
}
bool mainSaveMemoryAsPrg(const char *prgname, unsigned short &beginAddr, unsigned short &endAddr)
{
char newPrgname[512];
if (!prgname) {
if (!getSerializedFilename("noname", "prg", newPrgname))
return false;
} else {
strcpy(newPrgname, prgname);
}
if (beginAddr >= endAddr)
beginAddr = endAddr = 0;
return prgSaveBasicMemory(newPrgname, ted8360, beginAddr, endAddr, beginAddr == endAddr);
}
static void doSwapJoy()
{
const char *txt[] = { "NONE", "1", "2", "BOTH" };
unsigned int active = ted8360->getKeys()->swapjoy();
sprintf(textout, " ACTIVE JOY IS : %s ", txt[active]);
printf("%s\n", textout);
PopupMsg(textout);
}
static void enterMenu()
{
sound_pause();
uinterface->enterMenu();
if (g_SoundOn && g_50Hz)
sound_resume();
}
static void toggleFullThrottle()
{
g_50Hz = !g_50Hz;
sprintf(textout, " 50 HZ TIMER IS ");
if (g_50Hz) {
sound_resume();
strcat(textout,"ON ");
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop_timing(EM_TIMING_RAF, 0);
#endif
}
else {
sound_pause();
strcat(textout, "OFF ");
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, 1);
#endif
}
PopupMsg(textout);
// restart counter
g_TotFrames = 0;
}
static void setEmulationLevel(unsigned int level)
{
unsigned char ram[RAMSIZE];
unsigned int i = ted8360->getEmulationLevel();
if (level != i) {
g_bActive = 0;
sound_pause();
// Back up RAM
memcpy(ram, ted8360->Ram, RAMSIZE);
// Back up TED
unsigned int oldCpr = ted8360->getCyclesPerRow();
unsigned int romEnabled = ram[0xff13] & 1;
for(i = 0; i < 0x20; i++) {
ram[0xFF00 + i] = ted8360->Read(0xFF00 + i);
}
unsigned char prddr = ted8360->Read(0);
unsigned char prp = ted8360->Read(1);
// destroy old TED object
if (ted8360)
delete ted8360;
if (fsd1541) {
delete fsd1541;
fsd1541 = NULL;
}
switch (level) {
case 0:
ted8360 = new TED;
break;
case 1:
ted8360 = new TEDFAST;
break;
case 2:
ted8360 = new Vic2mem;
fsd1541 = new FakeSerialDrive(8);
break;
}
uinterface->setNewMachine(ted8360);
unsigned int newCpr = ted8360->getCyclesPerRow();
//ted8360->Reset();
machine->setMem(ted8360, ted8360->getIrqReg(), &(ted8360->Ram[0x0100]));
ted8360->HookTCBM(tcbm);
ted8360->setCpuPtr(machine);
// restore RAM
memcpy(ted8360->Ram, ram, RAMSIZE);
// reload ROMs for machine type switch
ted8360->loadroms();
if (oldCpr != newCpr) {
machine->Reset();
ted8360->Reset(false);
init_palette(ted8360);
} else {
// Restore TED register state
for(i = 0; i < 0x20; i++) {
ted8360->Write(0xFF00 + i, ram[0xFF00 + i]);
}
ted8360->Write(0xFF3F - romEnabled, 0);
// processor ports
ted8360->Write(0, prddr);
ted8360->Write(1, prp & prddr);
}
//CSerial::InitPorts();
//CTrueDrive::ResetAllDrives();
//
sound_resume();
g_bActive = 1;
}
}
//-----------------------------------------------------------------------------
// Name: poll_events()
// Desc: polls SDL events if there's any in the message queue
//-----------------------------------------------------------------------------
inline static void poll_events(void)
{
SDL_Event event;
if ( SDL_PollEvent(&event) ) {
switch (event.type) {
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
frameUpdate();
}
break;
case SDL_KEYDOWN:
// printf("Keysim: %x, scancode: %x - %s key was pressed!\n",
// event.key.keysym.sym, event.key.keysym.scancode, SDL_GetKeyName(event.key.keysym.sym));
if (event.key.keysym.mod & KMOD_LALT) {
sound_pause();
switch (event.key.keysym.sym) {
default:;
break;
case SDLK_KP_PLUS:
{
static unsigned int currFrq = 0;
unsigned int frq[] = { 48000, 96000, 192000 };
currFrq = (currFrq + 1) % 3;
unsigned int rate = frq[currFrq];
sound_change_freq(rate);
PopupMsg(" AUDIO FREQUENCY: %u ", rate);
}
break;
case SDLK_1:
case SDLK_2:
case SDLK_3:
{
int mult = (event.key.keysym.sym - SDLK_0);
g_bWindowMultiplier = mult;
SDL_SetWindowSize(sdlWindow, SCREENX * mult, SCREENY * mult);
PopupMsg(" WINDOW SIZE: %ux ", mult);
}
break;
case SDLK_e:
case SDLK_l:
{
int dir = (event.key.keysym.mod & KMOD_SHIFT) ? -1 : 1;
g_iEmulationLevel = (g_iEmulationLevel + dir) % 3;
setEmulationLevel(g_iEmulationLevel);
sprintf(textout, " EMULATION : ");
switch (g_iEmulationLevel) {
default:
case 0:
strcat(textout, "ACCURATE +4 ");
break;
case 1:
strcat(textout, "FAST +4 ");
break;
case 2:
strcat(textout, "COMMODORE 64 ");
}
printf("%s.\n", textout);
}
PopupMsg(textout);
break;
case SDLK_i :
doSwapJoy();
break;
case SDLK_m :
sound_pause();
monitorEnter(machine);
sound_resume();
break;
case SDLK_p:
g_bUseOverlay = !g_bUseOverlay;
SDL_DestroyTexture(sdlTexture);
sdlTexture = SDL_CreateTexture(sdlRenderer,
g_bUseOverlay ? SDL_PIXELFORMAT_UYVY : SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
WINDOWX, WINDOWY * (g_bUseOverlay ? 2 : 1));
PopupMsg(" CRT emulation %s ", g_bUseOverlay ? "ON" : "OFF");
break;
case SDLK_r:
ted8360->Reset(false);
machineReset(false);
printf("Resetting...\n");
PopupMsg(" RESET ");
break;
case SDLK_s:
g_TotFrames = 0;
g_FrameRate = !g_FrameRate;
break;
case SDLK_w :
toggleFullThrottle();
break;
case SDLK_RETURN:
{
static bool fs = false;
fs = !fs;
SDL_SetWindowFullscreen(sdlWindow, fs ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
}
break;
case SDLK_F5:
getSerializedFilename("snapshot", "yss", lastSnapshotName);
SaveState::openSnapshot(lastSnapshotName, true);
PopupMsg(" Saving snapshot... ");
fprintf(stderr, "Saved emulator state to %s.\n", lastSnapshotName);
break;
case SDLK_F6:
if (SaveState::openSnapshot(lastSnapshotName, false))
PopupMsg(" Loading %s... ", lastSnapshotName);
break;
case SDLK_F8:
{
unsigned short d1 = 0, d2 = 0;
mainSaveMemoryAsPrg(0, d1, d2);
}
break;
};
if (g_50Hz) sound_resume();
return;
}
switch (event.key.keysym.sym) {
case SDLK_PAUSE :
PopupMsg(!g_bActive ? " RESUMING " : " PAUSED ");
g_bActive=!g_bActive;
break;
case SDLK_PAGEDOWN:
g_bActive = 0;
machineDoSomeFrames(1);
break;
case SDLK_PRINTSCREEN:
machine->triggerNmi();
break;
case SDLK_F5 :
case SDLK_F6 :
ted8360->tap->PressTapeButton(ted8360->GetClockCount());
break;
break;
case SDLK_F7:
SaveBitmap();
break;
case SDLK_ESCAPE:
case SDLK_F8:
enterMenu();
if (!g_bActive) {
PopupMsg(" PAUSED ");
frameUpdate();
}
break;
case SDLK_F9 :
g_inDebug=!g_inDebug;
break;
case SDLK_F10 :
if (SaveSettings(inifile))
fprintf( stderr, "Settings saved to %s.\n", inifile);
else
fprintf( stderr, "Oops! Could not save settings... %s\n", inifile);
break;
case SDLK_F11 :
g_bActive = false;
break;
case SDLK_F12 :
exit(0);
default :
return;
}
break;
case SDL_KEYUP:
switch (event.key.keysym.sym) {
case SDLK_PRINTSCREEN:
machine->clearNmi();
break;
case SDLK_F11 :
g_bActive = true;
if (event.key.keysym.mod & (KMOD_LSHIFT|KMOD_RSHIFT) ) {
machineReset(true);
break;
}
if (event.key.keysym.mod & (KMOD_LCTRL|KMOD_RCTRL) ) {
ted8360->Reset(false);
} else {
ted8360->Reset(false);
}
machineReset(false);
break;
default:
;
}
break;
case SDL_JOYBUTTONUP:
//printf("joy: %u, button: %u was pressed!\n", event.jbutton.which, event.jbutton.button);
if (event.jbutton.button == 5 || event.jbutton.button == 14) { // START button
enterMenu();
} else if (event.jbutton.button == 4) {
ted8360->copyToKbBuffer("RUN:\r",5);
} else if (event.jbutton.button == 11) {
doSwapJoy();
} else if (event.jbutton.button == 12) {
toggleFullThrottle();
}
break;
case SDL_QUIT:
exit(0);
}
}
}
static void machineInit()
{
// 1551 IEC
CFakeTCBM *tcbm_l = new CFakeTCBM();
CFakeIEC *iec_l = new CFakeIEC(8);
fsdrive = new CIECFSDrive(".");
iec = iec_l;
tcbm = tcbm_l;
tcbm_l->AddIECInterface((CIECInterface*)iec);
iec_l->AddIECDevice((CIECDevice*)fsdrive);
tcbm_l->Reset();
iec->Reset();
fsdrive->Reset();
//
// TED
//
ted8360 = new TED;
machine = new CPU(ted8360, ted8360->getIrqReg(), &(ted8360->Ram[0x0100]));
ted8360->HookTCBM(tcbm);
ted8360->setCpuPtr(machine);
ted8360->Reset(true);
// Serial init
CSerial::InitPorts();
// calculate and initialise palette
init_palette(ted8360);
}
void machineShutDown()
{
machineEnable1551(true);
delete fsdrive;
delete iec;
delete tcbm;
delete machine;
delete ted8360;
}
static void app_close()
{
close_audio();
// Save settings if required
if (g_bSaveSettings)
SaveSettings(inifile);
if (inifile) {
delete [] inifile;
inifile = NULL;
}
delete uinterface;
KEYS::closePcJoys();
if (sdlRenderer)
SDL_DestroyRenderer(sdlRenderer);
if (sdlTexture)
SDL_DestroyTexture(sdlTexture);
if (sdlWindow)
SDL_DestroyWindow(sdlWindow);
SDL_Quit();
}
static void setSDLIcon(SDL_Window* window)
{
// these masks are needed to tell SDL_CreateRGBSurface(From)
// to assume the data it gets is byte-wise RGB(A) data
unsigned int rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
int shift = (sdlIconPlus4.bytes_per_pixel == 3) ? 8 : 0;
rmask = 0xff000000 >> shift;
gmask = 0x00ff0000 >> shift;
bmask = 0x0000ff00 >> shift;
amask = 0x000000ff >> shift;
#else // little endian, like x86
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = (sdlIconPlus4.bytes_per_pixel == 3) ? 0 : 0xff000000;
#endif
SDL_Surface *icon = SDL_CreateRGBSurfaceFrom((void*) sdlIconPlus4.pixel_data, sdlIconPlus4.width,
sdlIconPlus4.height, sdlIconPlus4.bytes_per_pixel*8, sdlIconPlus4.bytes_per_pixel*sdlIconPlus4.width,
rmask, gmask, bmask, amask);
SDL_SetWindowIcon(window, icon);
SDL_FreeSurface(icon);
}
static void app_initialise()
{
if ( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0 ) { // SDL_INIT_AUDIO|
fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
exit(1);
}
atexit(app_close);
// check the video driver we have
fprintf(stderr, "Using video driver : %s\n", SDL_GetCurrentVideoDriver());
// create a new window
sdlWindow = SDL_CreateWindow(NAME,
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WINDOWX * g_bWindowMultiplier, WINDOWY * g_bWindowMultiplier,
SDL_WINDOW_RESIZABLE); // SDL_WINDOW_FULLSCREEN_DESKTOP
if ( !sdlWindow ) {
printf("Unable to create window: %s\n", SDL_GetError());
return;
}
setSDLIcon(sdlWindow);
sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
SDL_RenderSetLogicalSize(sdlRenderer, 768, 576);
sdlTexture = SDL_CreateTexture(sdlRenderer,
g_bUseOverlay ? SDL_PIXELFORMAT_UYVY : SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
WINDOWX, WINDOWY * (g_bUseOverlay ? 2 : 1));
init_audio();
}
static void mainLoop()
{
// hook into the emulation loop if active
if (g_bActive) {
ted8360->ted_process(1);
poll_events();
if (g_inDebug)
DebugInfo();
ShowFrameRate(g_FrameRate);
if (ad_vsync(g_50Hz))
frameUpdate();
} else {
if (SDL_WaitEvent(NULL))
poll_events();
}
}
/* ---------- MAIN ---------- */
int main(int argc, char *argv[])
{
machineInit();
uinterface = new UI(ted8360);
#ifndef __EMSCRIPTEN__
inipath = SDL_GetPrefPath("Gaia", "yapeSDL");
if (inipath) {
fprintf(stderr, "Home directory is %s\n", inipath);
} else {
inipath = SDL_GetBasePath();
fprintf(stderr, "No home directory, using application directory: %s\n", inipath);
}
inifile = new char[strlen(inipath) + 16];
strcpy(inifile, inipath);
SDL_free(inipath);
strcat(inifile, "yape.conf");
fprintf(stderr, "Config file: %s\n", inifile);
if (LoadSettings(inifile)) {
char tmpStr[512];
fprintf(stderr, "Settings loaded successfully.\n");
ad_get_curr_dir(tmpStr);
fprintf(stderr, "IEC drive path: %s\n", tmpStr);
setEmulationLevel(g_iEmulationLevel);
} else
fprintf(stderr,"Error loading settings or no .ini file present...\n");
#endif
app_initialise();
if (!g_SoundOn || !g_50Hz) sound_pause();
KEYS::initPcJoys();
machine->Reset();
/* ---------- Command line parameters ---------- */
if (argv[1]!='\0') {
printf("Parameter 1 :%s\n", argv[1]);
// and then try to load the parameter as file
autostart_file(argv[1]);
}
/* ---------- MAIN LOOP ---------- */
#ifdef __EMSCRIPTEN__
printf("Type DIRECTORY and press ENTER to see disk contents. Type DLOAD\"filename* to load a specific file!\n");
printf("Usage:\n");
printf("LALT + 1-3 : set window size\n");
printf("LALT + I : switch emulated joystick port\n");
printf("LALT + L : switch among emulators (C+4 cycle based; C+4 line based; C64 cycle based)\n");
printf("LALT + M : enter console based external monitor and disassembler (currently deadlocks!)\n");
printf("LALT + P : toggle CRT emulation\n");
printf("LALT + R : machine reset\n");
printf("LALT + S : display frame rate on/off\n");
printf("LALT + W : toggle between unlimited speed and original speed\n");
printf("LALT + ENTER : toggle full screen mode\n");
printf("LALT + F5 : save emulator snapshot\n");
printf("LALT + F6 : load emulator snapshot\n");
printf("Joystick buttons are the arrow keys and SPACE\n");
printf("Entering main loop...\n");
emscripten_set_main_loop((em_callback_func) mainLoop, 0, 1);
#else
ad_vsync_init();
for (;;) {
mainLoop();
}
#endif
return 0;
}