mirror of https://github.com/JorjBauer/aiie.git
bios rework in SDL base
This commit is contained in:
parent
16fbb37f90
commit
538898d371
858
bios.cpp
858
bios.cpp
|
@ -14,7 +14,7 @@ extern Bounce resetButtonDebouncer;
|
||||||
extern void runDebouncer();
|
extern void runDebouncer();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Experimenting with using EXTMEM to cache all the filenames in a directory
|
// using EXTMEM to cache all the filenames in a directory
|
||||||
#ifndef TEENSYDUINO
|
#ifndef TEENSYDUINO
|
||||||
#define EXTMEM
|
#define EXTMEM
|
||||||
#endif
|
#endif
|
||||||
|
@ -28,6 +28,24 @@ EXTMEM char cachedFilter[BIOS_MAXPATH] = {0};
|
||||||
EXTMEM struct _cacheEntry biosCache[BIOSCACHESIZE];
|
EXTMEM struct _cacheEntry biosCache[BIOSCACHESIZE];
|
||||||
uint16_t numCacheEntries = 0;
|
uint16_t numCacheEntries = 0;
|
||||||
|
|
||||||
|
// When selecting files...
|
||||||
|
char fileFilter[16]; // FIXME length & Strcpy -> strncpy
|
||||||
|
uint16_t fileSelectionFor; // define what the returned name is for
|
||||||
|
|
||||||
|
// menu screen enums
|
||||||
|
enum {
|
||||||
|
BIOS_AIIE = 0,
|
||||||
|
BIOS_VM = 1,
|
||||||
|
BIOS_HARDWARE = 2,
|
||||||
|
BIOS_DISKS = 3,
|
||||||
|
|
||||||
|
BIOS_ABOUT = 4,
|
||||||
|
BIOS_PADDLES = 5,
|
||||||
|
BIOS_SELECTFILE = 6,
|
||||||
|
|
||||||
|
BIOS_DONE = 99,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ACT_EXIT = 1,
|
ACT_EXIT = 1,
|
||||||
|
@ -81,7 +99,7 @@ const char *staticPathConcat(const char *rootPath, const char *filePath)
|
||||||
|
|
||||||
BIOS::BIOS()
|
BIOS::BIOS()
|
||||||
{
|
{
|
||||||
selectedMenu = 1;
|
selectedMenu = BIOS_VM;
|
||||||
selectedMenuItem = 0;
|
selectedMenuItem = 0;
|
||||||
|
|
||||||
selectedFile = -1;
|
selectedFile = -1;
|
||||||
|
@ -124,7 +142,470 @@ void BIOS::DrawMenuBar()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BIOS::loop()
|
||||||
|
{
|
||||||
|
static bool needsinit = true;
|
||||||
|
if (needsinit) {
|
||||||
|
g_filemanager->getRootPath(rootPath, sizeof(rootPath));
|
||||||
|
needsinit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool needsRedraw = true;
|
||||||
|
|
||||||
|
if (selectedMenu == BIOS_DONE) {
|
||||||
|
// We're returning to the bios a second time
|
||||||
|
selectedMenu = BIOS_VM;
|
||||||
|
needsRedraw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TEENSYDUINO
|
||||||
|
if (resetButtonDebouncer.read() == LOW) {
|
||||||
|
// wait until it's no longer pressed
|
||||||
|
while (resetButtonDebouncer.read() == LOW)
|
||||||
|
runDebouncer();
|
||||||
|
delay(100); // wait long enough for it to debounce
|
||||||
|
return BIOS_DONE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool hitReturn = false;
|
||||||
|
|
||||||
|
uint16_t rv;
|
||||||
|
if (g_keyboard->kbhit()) {
|
||||||
|
switch (g_keyboard->read()) {
|
||||||
|
case PK_DARR:
|
||||||
|
selectedMenuItem++; // modded by current action
|
||||||
|
needsRedraw = true;
|
||||||
|
break;
|
||||||
|
case PK_UARR:
|
||||||
|
selectedMenuItem--; // modded by current action
|
||||||
|
needsRedraw = true;
|
||||||
|
break;
|
||||||
|
case PK_RARR:
|
||||||
|
selectedMenu++;
|
||||||
|
selectedMenu %= NUM_TITLES;
|
||||||
|
needsRedraw = true;
|
||||||
|
break;
|
||||||
|
case PK_LARR:
|
||||||
|
selectedMenu--;
|
||||||
|
if (selectedMenu < 0) {
|
||||||
|
selectedMenu = NUM_TITLES-1;
|
||||||
|
}
|
||||||
|
needsRedraw = true;
|
||||||
|
break;
|
||||||
|
case PK_RET:
|
||||||
|
hitReturn = true;
|
||||||
|
needsRedraw = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (selectedMenu) {
|
||||||
|
case BIOS_AIIE:
|
||||||
|
rv = AiieMenuHandler(needsRedraw, hitReturn);
|
||||||
|
break;
|
||||||
|
case BIOS_VM:
|
||||||
|
rv = VmMenuHandler(needsRedraw, hitReturn);
|
||||||
|
break;
|
||||||
|
case BIOS_HARDWARE:
|
||||||
|
rv = HardwareMenuHandler(needsRedraw, hitReturn);
|
||||||
|
break;
|
||||||
|
case BIOS_DISKS:
|
||||||
|
rv = DisksMenuHandler(needsRedraw, hitReturn);
|
||||||
|
break;
|
||||||
|
case BIOS_ABOUT:
|
||||||
|
rv = AboutScreenHandler(needsRedraw, hitReturn);
|
||||||
|
break;
|
||||||
|
case BIOS_PADDLES:
|
||||||
|
rv = PaddlesScreenHandler(needsRedraw, hitReturn);
|
||||||
|
break;
|
||||||
|
case BIOS_SELECTFILE:
|
||||||
|
rv = SelectFileScreenHandler(needsRedraw, hitReturn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rv != selectedMenu) {
|
||||||
|
needsRedraw = true;
|
||||||
|
selectedMenu = rv;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
needsRedraw = false; // assume the handler drew
|
||||||
|
|
||||||
|
return ((selectedMenu == BIOS_DONE) ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t BIOS::AiieMenuHandler(bool needsRedraw, bool performAction)
|
||||||
|
{
|
||||||
|
static bool localRedraw = true;
|
||||||
|
if (selectedMenuItem < 0)
|
||||||
|
selectedMenuItem = sizeof(aiieActions)-1;
|
||||||
|
selectedMenuItem %= sizeof(aiieActions);
|
||||||
|
|
||||||
|
if (needsRedraw || localRedraw) {
|
||||||
|
g_display->clrScr();
|
||||||
|
DrawMenuBar();
|
||||||
|
DrawAiieMenu();
|
||||||
|
g_display->flush();
|
||||||
|
|
||||||
|
localRedraw = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (performAction) {
|
||||||
|
// there is only ACT_ABOUT
|
||||||
|
return BIOS_ABOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BIOS_AIIE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t BIOS::VmMenuHandler(bool needsRedraw, bool performAction)
|
||||||
|
{
|
||||||
|
static bool localRedraw = true;
|
||||||
|
|
||||||
|
if (selectedMenuItem < 0)
|
||||||
|
selectedMenuItem = sizeof(vmActions)-1;
|
||||||
|
selectedMenuItem %= sizeof(vmActions);
|
||||||
|
|
||||||
|
if (needsRedraw || localRedraw) {
|
||||||
|
g_display->clrScr();
|
||||||
|
DrawMenuBar();
|
||||||
|
DrawVMMenu();
|
||||||
|
|
||||||
|
g_display->flush();
|
||||||
|
|
||||||
|
localRedraw = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (performAction) {
|
||||||
|
if (isActionActive(vmActions[selectedMenuItem])) {
|
||||||
|
switch (vmActions[selectedMenuItem]) {
|
||||||
|
case ACT_EXIT:
|
||||||
|
return BIOS_DONE;
|
||||||
|
case ACT_RESET:
|
||||||
|
WarmReset();
|
||||||
|
return BIOS_DONE;
|
||||||
|
case ACT_COLDBOOT:
|
||||||
|
ColdReboot();
|
||||||
|
return BIOS_DONE;
|
||||||
|
case ACT_MONITOR:
|
||||||
|
((AppleVM *)g_vm)->Monitor();
|
||||||
|
return BIOS_DONE;
|
||||||
|
case ACT_DEBUG:
|
||||||
|
g_debugMode++;
|
||||||
|
g_debugMode %= 9; // FIXME: abstract max #
|
||||||
|
localRedraw = true;
|
||||||
|
return BIOS_VM;
|
||||||
|
case ACT_SUSPEND:
|
||||||
|
g_display->clrScr();
|
||||||
|
g_display->drawString(M_SELECTED, 80, 100,"Suspending VM...");
|
||||||
|
g_display->flush();
|
||||||
|
// CPU is already suspended, so this is safe...
|
||||||
|
((AppleVM *)g_vm)->Suspend("suspend.vm");
|
||||||
|
localRedraw = true;
|
||||||
|
return BIOS_VM;
|
||||||
|
case ACT_RESTORE:
|
||||||
|
g_display->clrScr();
|
||||||
|
g_display->drawString(M_SELECTED, 80, 100,"Resuming VM...");
|
||||||
|
g_display->flush();
|
||||||
|
((AppleVM *)g_vm)->Resume("suspend.vm");
|
||||||
|
return BIOS_DONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BIOS_VM;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t BIOS::HardwareMenuHandler(bool needsRedraw, bool performAction)
|
||||||
|
{
|
||||||
|
static bool localRedraw = true;
|
||||||
|
|
||||||
|
if (selectedMenuItem < 0)
|
||||||
|
selectedMenuItem = sizeof(hardwareActions)-1;
|
||||||
|
selectedMenuItem %= sizeof(hardwareActions);
|
||||||
|
|
||||||
|
if (needsRedraw || localRedraw) {
|
||||||
|
g_display->clrScr();
|
||||||
|
DrawMenuBar();
|
||||||
|
DrawHardwareMenu();
|
||||||
|
g_display->flush();
|
||||||
|
|
||||||
|
localRedraw = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (performAction) {
|
||||||
|
if (isActionActive(hardwareActions[selectedMenuItem])) {
|
||||||
|
switch (hardwareActions[selectedMenuItem]) {
|
||||||
|
case ACT_DISPLAYTYPE:
|
||||||
|
g_displayType++;
|
||||||
|
g_displayType %= 4; // FIXME: abstract max #
|
||||||
|
((AppleDisplay*)g_display)->displayTypeChanged();
|
||||||
|
localRedraw = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACT_SPEED:
|
||||||
|
currentCPUSpeedIndex++;
|
||||||
|
currentCPUSpeedIndex %= 4;
|
||||||
|
switch (currentCPUSpeedIndex) {
|
||||||
|
case CPUSPEED_HALF:
|
||||||
|
g_speed = 1023000/2;
|
||||||
|
break;
|
||||||
|
case CPUSPEED_DOUBLE:
|
||||||
|
g_speed = 1023000*2;
|
||||||
|
break;
|
||||||
|
case CPUSPEED_QUAD:
|
||||||
|
g_speed = 1023000*4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_speed = 1023000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
localRedraw = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACT_PADX_INV:
|
||||||
|
g_invertPaddleX = !g_invertPaddleX;
|
||||||
|
#ifdef TEENSYDUINO
|
||||||
|
((TeensyPaddles *)g_paddles)->setRev(g_invertPaddleX, g_invertPaddleY);
|
||||||
|
#endif
|
||||||
|
localRedraw = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACT_PADY_INV:
|
||||||
|
g_invertPaddleY = !g_invertPaddleY;
|
||||||
|
#ifdef TEENSYDUINO
|
||||||
|
((TeensyPaddles *)g_paddles)->setRev(g_invertPaddleX, g_invertPaddleY);
|
||||||
|
#endif
|
||||||
|
localRedraw = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACT_PADDLES:
|
||||||
|
return BIOS_PADDLES;
|
||||||
|
|
||||||
|
case ACT_VOLPLUS:
|
||||||
|
g_volume ++;
|
||||||
|
if (g_volume > 15) {
|
||||||
|
g_volume = 15;
|
||||||
|
}
|
||||||
|
localRedraw = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACT_VOLMINUS:
|
||||||
|
g_volume--;
|
||||||
|
if (g_volume < 0) {
|
||||||
|
g_volume = 0;
|
||||||
|
}
|
||||||
|
localRedraw = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BIOS_HARDWARE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t BIOS::DisksMenuHandler(bool needsRedraw, bool performAction)
|
||||||
|
{
|
||||||
|
static bool localRedraw = true;
|
||||||
|
|
||||||
|
if (selectedMenuItem < 0)
|
||||||
|
selectedMenuItem = sizeof(diskActions)-1;
|
||||||
|
selectedMenuItem %= sizeof(diskActions);
|
||||||
|
|
||||||
|
if (needsRedraw || localRedraw) {
|
||||||
|
g_display->clrScr();
|
||||||
|
DrawMenuBar();
|
||||||
|
DrawDisksMenu();
|
||||||
|
g_display->flush();
|
||||||
|
|
||||||
|
localRedraw = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (performAction) {
|
||||||
|
if (isActionActive(diskActions[selectedMenuItem])) {
|
||||||
|
switch (diskActions[selectedMenuItem]) {
|
||||||
|
case ACT_DISK1:
|
||||||
|
if (((AppleVM *)g_vm)->DiskName(0)[0] != '\0') {
|
||||||
|
((AppleVM *)g_vm)->ejectDisk(0);
|
||||||
|
localRedraw = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
strcpy(fileFilter, "dsk,.po,nib,woz");
|
||||||
|
fileSelectionFor = ACT_DISK1;
|
||||||
|
return BIOS_SELECTFILE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACT_DISK2:
|
||||||
|
if (((AppleVM *)g_vm)->DiskName(1)[0] != '\0') {
|
||||||
|
((AppleVM *)g_vm)->ejectDisk(1);
|
||||||
|
localRedraw = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
strcpy(fileFilter, "dsk,.po,nib,woz");
|
||||||
|
fileSelectionFor = ACT_DISK2;
|
||||||
|
return BIOS_SELECTFILE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACT_HD1:
|
||||||
|
if (((AppleVM *)g_vm)->HDName(0)[0] != '\0') {
|
||||||
|
((AppleVM *)g_vm)->ejectHD(0);
|
||||||
|
localRedraw = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
strcpy(fileFilter, "img");
|
||||||
|
fileSelectionFor = ACT_HD1;
|
||||||
|
return BIOS_SELECTFILE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACT_HD2:
|
||||||
|
if (((AppleVM *)g_vm)->HDName(1)[0] != '\0') {
|
||||||
|
((AppleVM *)g_vm)->ejectHD(1);
|
||||||
|
localRedraw = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
strcpy(fileFilter, "img");
|
||||||
|
fileSelectionFor = ACT_HD2;
|
||||||
|
return BIOS_SELECTFILE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BIOS_DISKS;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t BIOS::AboutScreenHandler(bool needsRedraw, bool performAction)
|
||||||
|
{
|
||||||
|
static bool localRedraw = true;
|
||||||
|
selectedMenuItem = 0;
|
||||||
|
|
||||||
|
if (needsRedraw || localRedraw) {
|
||||||
|
g_display->clrScr();
|
||||||
|
|
||||||
|
g_display->drawString(M_SELECTED,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
"Aiie! - an Apple //e emulator");
|
||||||
|
|
||||||
|
g_display->drawString(M_NORMAL,
|
||||||
|
15, 20,
|
||||||
|
"(c) 2017-2020 Jorj Bauer");
|
||||||
|
|
||||||
|
g_display->drawString(M_NORMAL,
|
||||||
|
15, 38,
|
||||||
|
"https://github.com/JorjBauer/aiie/");
|
||||||
|
|
||||||
|
g_display->drawString(M_NORMAL,
|
||||||
|
0,
|
||||||
|
200,
|
||||||
|
"Press return");
|
||||||
|
|
||||||
|
g_display->flush();
|
||||||
|
|
||||||
|
localRedraw = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (performAction) {
|
||||||
|
return BIOS_AIIE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BIOS_ABOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t BIOS::PaddlesScreenHandler(bool needsRedraw, bool performAction)
|
||||||
|
{
|
||||||
|
static bool localRedraw = true;
|
||||||
|
selectedMenuItem = 0;
|
||||||
|
static uint8_t lastPaddleX = g_paddles->paddle0();
|
||||||
|
static uint8_t lastPaddleY = g_paddles->paddle1();
|
||||||
|
|
||||||
|
if (g_paddles->paddle0() != lastPaddleX) {
|
||||||
|
lastPaddleX = g_paddles->paddle0();
|
||||||
|
localRedraw = true;
|
||||||
|
}
|
||||||
|
if (g_paddles->paddle1() != lastPaddleY) {
|
||||||
|
lastPaddleY = g_paddles->paddle1();
|
||||||
|
localRedraw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsRedraw || localRedraw) {
|
||||||
|
char buf[50];
|
||||||
|
g_display->clrScr();
|
||||||
|
sprintf(buf, "Paddle X: %d ", lastPaddleX);
|
||||||
|
g_display->drawString(M_NORMAL, 0, 12, buf);
|
||||||
|
sprintf(buf, "Paddle Y: %d ", lastPaddleY);
|
||||||
|
g_display->drawString(M_NORMAL, 0, 42, buf);
|
||||||
|
g_display->drawString(M_NORMAL, 0, 92, "Press return to exit");
|
||||||
|
g_display->flush();
|
||||||
|
|
||||||
|
localRedraw = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (performAction) {
|
||||||
|
return BIOS_HARDWARE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BIOS_PADDLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t BIOS::SelectFileScreenHandler(bool needsRedraw, bool performAction)
|
||||||
|
{
|
||||||
|
if (selectedMenuItem < 0)
|
||||||
|
selectedMenuItem = BIOS_MAXFILES + 1;
|
||||||
|
selectedMenuItem %= BIOS_MAXFILES + 2;
|
||||||
|
|
||||||
|
static bool localRedraw = true;
|
||||||
|
static int8_t sel = 0;
|
||||||
|
static int8_t page = 0;
|
||||||
|
static uint16_t fileCount = 0;
|
||||||
|
|
||||||
|
if (needsRedraw || localRedraw) {
|
||||||
|
fileCount = DrawDiskNames(page, sel, fileFilter);
|
||||||
|
|
||||||
|
localRedraw = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (performAction) {
|
||||||
|
if (sel == 0) {
|
||||||
|
page--;
|
||||||
|
if (page < 0) page = 0;
|
||||||
|
// else sel = BIOS_MAXFILES + 1;
|
||||||
|
localRedraw = true;
|
||||||
|
}
|
||||||
|
else if (sel == BIOS_MAXFILES+1) {
|
||||||
|
if (fileCount == BIOS_MAXFILES) { // don't let them select
|
||||||
|
// 'Next' if there were no
|
||||||
|
// files in the list or if the
|
||||||
|
// list isn't full
|
||||||
|
page++;
|
||||||
|
//sel = 0;
|
||||||
|
localRedraw = true;
|
||||||
|
}
|
||||||
|
} else if (strcmp(fileDirectory[sel-1], "../") == 0) {
|
||||||
|
// Go up a directory (strip a directory name from rootPath)
|
||||||
|
stripDirectory();
|
||||||
|
page = 0;
|
||||||
|
//sel = 0;
|
||||||
|
localRedraw = true;
|
||||||
|
} else if (fileDirectory[sel-1][strlen(fileDirectory[sel-1])-1] == '/') {
|
||||||
|
// Descend in to the directory. FIXME: file path length?
|
||||||
|
strcat(rootPath, fileDirectory[sel-1]);
|
||||||
|
sel = 0;
|
||||||
|
page = 0;
|
||||||
|
localRedraw = true;
|
||||||
|
} else {
|
||||||
|
selectedFile = sel - 1;
|
||||||
|
g_display->flush();
|
||||||
|
return BIOS_DISKS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return BIOS_SELECTFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
bool BIOS::runUntilDone()
|
bool BIOS::runUntilDone()
|
||||||
{
|
{
|
||||||
// Reset the cache
|
// Reset the cache
|
||||||
|
@ -145,129 +626,10 @@ bool BIOS::runUntilDone()
|
||||||
int8_t prevAction = ACT_EXIT;
|
int8_t prevAction = ACT_EXIT;
|
||||||
while (1) {
|
while (1) {
|
||||||
switch (prevAction = GetAction(prevAction)) {
|
switch (prevAction = GetAction(prevAction)) {
|
||||||
case ACT_EXIT:
|
|
||||||
goto done;
|
|
||||||
case ACT_COLDBOOT:
|
|
||||||
ColdReboot();
|
|
||||||
goto done;
|
|
||||||
case ACT_RESET:
|
|
||||||
WarmReset();
|
|
||||||
goto done;
|
|
||||||
case ACT_MONITOR:
|
|
||||||
((AppleVM *)g_vm)->Monitor();
|
|
||||||
goto done;
|
|
||||||
case ACT_DISPLAYTYPE:
|
|
||||||
g_displayType++;
|
|
||||||
g_displayType %= 4; // FIXME: abstract max #
|
|
||||||
((AppleDisplay*)g_display)->displayTypeChanged();
|
|
||||||
break;
|
|
||||||
case ACT_ABOUT:
|
|
||||||
showAbout();
|
|
||||||
break;
|
|
||||||
case ACT_SPEED:
|
|
||||||
currentCPUSpeedIndex++;
|
|
||||||
currentCPUSpeedIndex %= 4;
|
|
||||||
switch (currentCPUSpeedIndex) {
|
|
||||||
case CPUSPEED_HALF:
|
|
||||||
g_speed = 1023000/2;
|
|
||||||
break;
|
|
||||||
case CPUSPEED_DOUBLE:
|
|
||||||
g_speed = 1023000*2;
|
|
||||||
break;
|
|
||||||
case CPUSPEED_QUAD:
|
|
||||||
g_speed = 1023000*4;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_speed = 1023000;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ACT_DEBUG:
|
|
||||||
g_debugMode++;
|
|
||||||
g_debugMode %= 9; // FIXME: abstract max #
|
|
||||||
break;
|
|
||||||
case ACT_DISK1:
|
|
||||||
if (((AppleVM *)g_vm)->DiskName(0)[0] != '\0') {
|
|
||||||
((AppleVM *)g_vm)->ejectDisk(0);
|
|
||||||
} else {
|
|
||||||
if (SelectDiskImage("dsk,.po,nib,woz")) {
|
|
||||||
((AppleVM *)g_vm)->insertDisk(0, staticPathConcat(rootPath, fileDirectory[selectedFile]), false);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ACT_DISK2:
|
|
||||||
if (((AppleVM *)g_vm)->DiskName(1)[0] != '\0') {
|
|
||||||
((AppleVM *)g_vm)->ejectDisk(1);
|
|
||||||
} else {
|
|
||||||
if (SelectDiskImage("dsk,.po,nib,woz")) {
|
|
||||||
((AppleVM *)g_vm)->insertDisk(1, staticPathConcat(rootPath, fileDirectory[selectedFile]), false);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ACT_HD1:
|
|
||||||
if (((AppleVM *)g_vm)->HDName(0)[0] != '\0') {
|
|
||||||
((AppleVM *)g_vm)->ejectHD(0);
|
|
||||||
} else {
|
|
||||||
if (SelectDiskImage("img")) {
|
|
||||||
((AppleVM *)g_vm)->insertHD(0, staticPathConcat(rootPath, fileDirectory[selectedFile]));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ACT_HD2:
|
|
||||||
if (((AppleVM *)g_vm)->HDName(1)[0] != '\0') {
|
|
||||||
((AppleVM *)g_vm)->ejectHD(1);
|
|
||||||
} else {
|
|
||||||
if (SelectDiskImage("img")) {
|
|
||||||
((AppleVM *)g_vm)->insertHD(1, staticPathConcat(rootPath, fileDirectory[selectedFile]));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ACT_PADX_INV:
|
|
||||||
g_invertPaddleX = !g_invertPaddleX;
|
|
||||||
#ifdef TEENSYDUINO
|
|
||||||
((TeensyPaddles *)g_paddles)->setRev(g_invertPaddleX, g_invertPaddleY);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case ACT_PADY_INV:
|
|
||||||
g_invertPaddleY = !g_invertPaddleY;
|
|
||||||
#ifdef TEENSYDUINO
|
|
||||||
((TeensyPaddles *)g_paddles)->setRev(g_invertPaddleX, g_invertPaddleY);
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case ACT_PADDLES:
|
|
||||||
ConfigurePaddles();
|
|
||||||
break;
|
|
||||||
case ACT_VOLPLUS:
|
|
||||||
g_volume ++;
|
|
||||||
if (g_volume > 15) {
|
|
||||||
g_volume = 15;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ACT_VOLMINUS:
|
|
||||||
g_volume--;
|
|
||||||
if (g_volume < 0) {
|
|
||||||
g_volume = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ACT_SUSPEND:
|
***
|
||||||
g_display->clrScr();
|
// ConfigurePaddles();
|
||||||
g_display->drawString(M_SELECTED, 80, 100,"Suspending VM...");
|
***
|
||||||
g_display->flush();
|
|
||||||
// CPU is already suspended, so this is safe...
|
|
||||||
((AppleVM *)g_vm)->Suspend("suspend.vm");
|
|
||||||
break;
|
|
||||||
case ACT_RESTORE:
|
|
||||||
// CPU is already suspended, so this is safe...
|
|
||||||
g_display->clrScr();
|
|
||||||
g_display->drawString(M_SELECTED, 80, 100,"Resuming VM...");
|
|
||||||
g_display->flush();
|
|
||||||
((AppleVM *)g_vm)->Resume("suspend.vm");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,6 +642,7 @@ bool BIOS::runUntilDone()
|
||||||
// return true if any persistent setting changed that we want to store in eeprom
|
// return true if any persistent setting changed that we want to store in eeprom
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void BIOS::WarmReset()
|
void BIOS::WarmReset()
|
||||||
{
|
{
|
||||||
|
@ -292,91 +655,6 @@ void BIOS::ColdReboot()
|
||||||
g_cpu->Reset();
|
g_cpu->Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t BIOS::GetAction(int8_t selection)
|
|
||||||
{
|
|
||||||
while (1) {
|
|
||||||
DrawMainMenu();
|
|
||||||
while (!g_keyboard->kbhit()
|
|
||||||
#ifdef TEENSYDUINO
|
|
||||||
&&
|
|
||||||
(resetButtonDebouncer.read() == HIGH)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
#ifdef TEENSYDUINO
|
|
||||||
runDebouncer();
|
|
||||||
delay(10);
|
|
||||||
#else
|
|
||||||
usleep(100);
|
|
||||||
#endif
|
|
||||||
// Wait for either a keypress or the reset button to be pressed
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TEENSYDUINO
|
|
||||||
if (resetButtonDebouncer.read() == LOW) {
|
|
||||||
// wait until it's no longer pressed
|
|
||||||
while (resetButtonDebouncer.read() == LOW)
|
|
||||||
runDebouncer();
|
|
||||||
delay(100); // wait long enough for it to debounce
|
|
||||||
// then return an exit code
|
|
||||||
return ACT_EXIT;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// FIXME: look for F10 or ESC & return ACT_EXIT?
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// selectedMenuItem and selectedMenu can go out of bounds here, and that's okay;
|
|
||||||
// the current menu (and the menu bar) will re-pin it appropriately...
|
|
||||||
switch (g_keyboard->read()) {
|
|
||||||
case PK_DARR:
|
|
||||||
selectedMenuItem++;
|
|
||||||
break;
|
|
||||||
case PK_UARR:
|
|
||||||
selectedMenuItem--;
|
|
||||||
break;
|
|
||||||
case PK_RARR:
|
|
||||||
selectedMenu++;
|
|
||||||
break;
|
|
||||||
case PK_LARR:
|
|
||||||
selectedMenu--;
|
|
||||||
break;
|
|
||||||
case PK_RET:
|
|
||||||
{
|
|
||||||
int8_t activeAction = getCurrentMenuAction();
|
|
||||||
if (activeAction > 0) {
|
|
||||||
return activeAction;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int8_t BIOS::getCurrentMenuAction()
|
|
||||||
{
|
|
||||||
int8_t ret = -1;
|
|
||||||
|
|
||||||
switch (selectedMenu) {
|
|
||||||
case 0: // Aiie
|
|
||||||
if (isActionActive(aiieActions[selectedMenuItem]))
|
|
||||||
return aiieActions[selectedMenuItem];
|
|
||||||
break;
|
|
||||||
case 1: // VM
|
|
||||||
if (isActionActive(vmActions[selectedMenuItem]))
|
|
||||||
return vmActions[selectedMenuItem];
|
|
||||||
break;
|
|
||||||
case 2: // Hardware
|
|
||||||
if (isActionActive(hardwareActions[selectedMenuItem]))
|
|
||||||
return hardwareActions[selectedMenuItem];
|
|
||||||
break;
|
|
||||||
case 3: // Disks
|
|
||||||
if (isActionActive(diskActions[selectedMenuItem]))
|
|
||||||
return diskActions[selectedMenuItem];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BIOS::isActionActive(int8_t action)
|
bool BIOS::isActionActive(int8_t action)
|
||||||
{
|
{
|
||||||
// don't return true for disk events that aren't valid
|
// don't return true for disk events that aren't valid
|
||||||
|
@ -673,110 +951,6 @@ void BIOS::DrawCurrentMenu()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BIOS::DrawMainMenu()
|
|
||||||
{
|
|
||||||
g_display->clrScr();
|
|
||||||
// g_display->drawString(M_NORMAL, 0, 0, "BIOS Configuration");
|
|
||||||
|
|
||||||
DrawMenuBar();
|
|
||||||
|
|
||||||
DrawCurrentMenu();
|
|
||||||
|
|
||||||
g_display->flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BIOS::ConfigurePaddles()
|
|
||||||
{
|
|
||||||
while (1) {
|
|
||||||
bool needsUpdate = true;
|
|
||||||
uint8_t lastPaddleX = g_paddles->paddle0();
|
|
||||||
uint8_t lastPaddleY = g_paddles->paddle1();
|
|
||||||
|
|
||||||
if (g_paddles->paddle0() != lastPaddleX) {
|
|
||||||
lastPaddleX = g_paddles->paddle0();
|
|
||||||
needsUpdate = true;
|
|
||||||
}
|
|
||||||
if (g_paddles->paddle1() != lastPaddleY) {
|
|
||||||
lastPaddleY = g_paddles->paddle1();
|
|
||||||
needsUpdate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needsUpdate) {
|
|
||||||
char buf[50];
|
|
||||||
g_display->clrScr();
|
|
||||||
sprintf(buf, "Paddle X: %d ", lastPaddleX);
|
|
||||||
g_display->drawString(M_NORMAL, 0, 12, buf);
|
|
||||||
sprintf(buf, "Paddle Y: %d ", lastPaddleY);
|
|
||||||
g_display->drawString(M_NORMAL, 0, 42, buf);
|
|
||||||
g_display->drawString(M_NORMAL, 0, 92, "Exit with any key");
|
|
||||||
g_display->flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_keyboard->kbhit()) {
|
|
||||||
g_keyboard->read(); // throw out keypress
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return true if the user selects an image
|
|
||||||
// sets selectedFile (index; -1 = "nope") and fileDirectory[][] (names of up to BIOS_MAXFILES files)
|
|
||||||
bool BIOS::SelectDiskImage(const char *filter)
|
|
||||||
{
|
|
||||||
int8_t sel = 0;
|
|
||||||
int8_t page = 0;
|
|
||||||
uint16_t fileCount = 0;
|
|
||||||
while (1) {
|
|
||||||
fileCount = DrawDiskNames(page, sel, filter);
|
|
||||||
|
|
||||||
while (!g_keyboard->kbhit())
|
|
||||||
;
|
|
||||||
switch (g_keyboard->read()) {
|
|
||||||
case PK_DARR:
|
|
||||||
sel++;
|
|
||||||
sel %= BIOS_MAXFILES + 2;
|
|
||||||
break;
|
|
||||||
case PK_UARR:
|
|
||||||
sel--;
|
|
||||||
if (sel < 0)
|
|
||||||
sel = BIOS_MAXFILES + 1;
|
|
||||||
break;
|
|
||||||
case PK_ESC:
|
|
||||||
return false;
|
|
||||||
case PK_RET:
|
|
||||||
if (sel == 0) {
|
|
||||||
page--;
|
|
||||||
if (page < 0) page = 0;
|
|
||||||
// else sel = BIOS_MAXFILES + 1;
|
|
||||||
}
|
|
||||||
else if (sel == BIOS_MAXFILES+1) {
|
|
||||||
if (fileCount == BIOS_MAXFILES) { // don't let them select 'Next' if there were no files in the list or if the list isn't full
|
|
||||||
page++;
|
|
||||||
//sel = 0;
|
|
||||||
}
|
|
||||||
} else if (strcmp(fileDirectory[sel-1], "../") == 0) {
|
|
||||||
// Go up a directory (strip a directory name from rootPath)
|
|
||||||
stripDirectory();
|
|
||||||
page = 0;
|
|
||||||
//sel = 0;
|
|
||||||
continue;
|
|
||||||
} else if (fileDirectory[sel-1][strlen(fileDirectory[sel-1])-1] == '/') {
|
|
||||||
// Descend in to the directory. FIXME: file path length?
|
|
||||||
strcat(rootPath, fileDirectory[sel-1]);
|
|
||||||
sel = 0;
|
|
||||||
page = 0;
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
selectedFile = sel - 1;
|
|
||||||
g_display->flush();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* NOTREACHED */
|
|
||||||
}
|
|
||||||
|
|
||||||
void BIOS::stripDirectory()
|
void BIOS::stripDirectory()
|
||||||
{
|
{
|
||||||
rootPath[strlen(rootPath)-1] = '\0'; // remove the last character
|
rootPath[strlen(rootPath)-1] = '\0'; // remove the last character
|
||||||
|
@ -919,31 +1093,45 @@ uint16_t BIOS::GatherFilenames(uint8_t pageOffset, const char *filter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BIOS::showAbout()
|
#if 0
|
||||||
{
|
***
|
||||||
g_display->clrScr();
|
switch (fileSelectionFor) {
|
||||||
|
case ACT_DISK1:
|
||||||
|
if (SelectDiskImage("dsk,.po,nib,woz")) {
|
||||||
|
((AppleVM *)g_vm)->insertDisk(0, staticPathConcat(rootPath, fileDirectory[selectedFile]), false);
|
||||||
|
return BIOS_DONE;
|
||||||
|
...
|
||||||
|
case ACT_DISK2:
|
||||||
|
if (SelectDiskImage("dsk,.po,nib,woz")) {
|
||||||
|
((AppleVM *)g_vm)->insertDisk(1, staticPathConcat(rootPath, fileDirectory[selectedFile]), false);
|
||||||
|
return BIOS_DONE;
|
||||||
|
|
||||||
g_display->drawString(M_SELECTED,
|
...
|
||||||
0,
|
case ACT_HD1:
|
||||||
0,
|
***
|
||||||
"Aiie! - an Apple //e emulator");
|
if (SelectDiskImage("img")) {
|
||||||
|
((AppleVM *)g_vm)->insertHD(0, staticPathConcat(rootPath, fileDirectory[selectedFile]));
|
||||||
|
return BIOS_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
g_display->drawString(M_NORMAL,
|
case ACT_HD2:
|
||||||
15, 20,
|
***
|
||||||
"(c) 2017-2020 Jorj Bauer");
|
if (SelectDiskImage("img")) {
|
||||||
|
((AppleVM *)g_vm)->insertHD(1, staticPathConcat(rootPath, fileDirectory[selectedFile]));
|
||||||
|
return BIOS_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
g_display->drawString(M_NORMAL,
|
|
||||||
15, 38,
|
|
||||||
"https://github.com/JorjBauer/aiie/");
|
|
||||||
|
|
||||||
g_display->drawString(M_NORMAL,
|
...
|
||||||
0,
|
|
||||||
200,
|
|
||||||
"Press any key");
|
|
||||||
|
|
||||||
g_display->flush();
|
/*
|
||||||
|
int8_t sel = 0;
|
||||||
|
int8_t page = 0;
|
||||||
|
uint16_t fileCount = 0;
|
||||||
|
while (1) {
|
||||||
|
fileCount = DrawDiskNames(page, sel, filter);
|
||||||
|
*/
|
||||||
|
|
||||||
while (!g_keyboard->kbhit())
|
|
||||||
;
|
#endif
|
||||||
g_keyboard->read(); // throw out the keypress
|
|
||||||
}
|
|
||||||
|
|
20
bios.h
20
bios.h
|
@ -15,10 +15,12 @@ class BIOS {
|
||||||
BIOS();
|
BIOS();
|
||||||
~BIOS();
|
~BIOS();
|
||||||
|
|
||||||
// return true if a persistent change needs to be stored in EEPROM
|
// return true as long as it's still running
|
||||||
bool runUntilDone();
|
bool loop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
uint16_t MainMenuHandler();
|
||||||
|
|
||||||
void DrawMenuBar();
|
void DrawMenuBar();
|
||||||
void DrawCurrentMenu();
|
void DrawCurrentMenu();
|
||||||
void DrawAiieMenu();
|
void DrawAiieMenu();
|
||||||
|
@ -26,25 +28,27 @@ class BIOS {
|
||||||
void DrawHardwareMenu();
|
void DrawHardwareMenu();
|
||||||
void DrawDisksMenu();
|
void DrawDisksMenu();
|
||||||
|
|
||||||
|
uint16_t AiieMenuHandler(bool needsRedraw, bool performAction);
|
||||||
|
uint16_t VmMenuHandler(bool needsRedraw, bool performAction);
|
||||||
|
uint16_t HardwareMenuHandler(bool needsRedraw, bool performAction);
|
||||||
|
uint16_t DisksMenuHandler(bool needsRedraw, bool performAction);
|
||||||
|
uint16_t AboutScreenHandler(bool needsRedraw, bool performAction);
|
||||||
|
uint16_t PaddlesScreenHandler(bool needsRedraw, bool performAction);
|
||||||
|
uint16_t SelectFileScreenHandler(bool needsRedraw, bool performAction);
|
||||||
|
|
||||||
uint8_t GetAction(int8_t prevAction);
|
uint8_t GetAction(int8_t prevAction);
|
||||||
bool isActionActive(int8_t action);
|
bool isActionActive(int8_t action);
|
||||||
void DrawMainMenu();
|
|
||||||
|
|
||||||
int8_t getCurrentMenuAction();
|
int8_t getCurrentMenuAction();
|
||||||
|
|
||||||
void WarmReset();
|
void WarmReset();
|
||||||
void ColdReboot();
|
void ColdReboot();
|
||||||
|
|
||||||
bool SelectDiskImage(const char *filter);
|
|
||||||
uint16_t DrawDiskNames(uint8_t page, int8_t selection, const char *filter);
|
uint16_t DrawDiskNames(uint8_t page, int8_t selection, const char *filter);
|
||||||
uint16_t GatherFilenames(uint8_t pageOffset, const char *filter);
|
uint16_t GatherFilenames(uint8_t pageOffset, const char *filter);
|
||||||
|
|
||||||
void ConfigurePaddles();
|
|
||||||
|
|
||||||
void stripDirectory();
|
void stripDirectory();
|
||||||
|
|
||||||
void showAbout();
|
|
||||||
|
|
||||||
uint16_t cacheAllEntries(const char *filter);
|
uint16_t cacheAllEntries(const char *filter);
|
||||||
void sortCachedEntries();
|
void sortCachedEntries();
|
||||||
void swapCacheEntries(int a, int b);
|
void swapCacheEntries(int a, int b);
|
||||||
|
|
515
sdl/aiie.cpp
515
sdl/aiie.cpp
|
@ -20,22 +20,14 @@
|
||||||
|
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
|
|
||||||
//#define SHOWFPS
|
|
||||||
//#define SHOWPC
|
|
||||||
//#define SHOWMEMPAGE
|
|
||||||
|
|
||||||
BIOS bios;
|
BIOS bios;
|
||||||
Debugger debugger;
|
Debugger debugger;
|
||||||
|
|
||||||
struct timespec nextInstructionTime, startTime;
|
|
||||||
|
|
||||||
#define NB_ENABLE 1
|
#define NB_ENABLE 1
|
||||||
#define NB_DISABLE 0
|
#define NB_DISABLE 0
|
||||||
|
|
||||||
int send_rst = 0;
|
int send_rst = 0;
|
||||||
|
|
||||||
pthread_t cpuThreadID;
|
|
||||||
|
|
||||||
char disk1name[256] = "\0";
|
char disk1name[256] = "\0";
|
||||||
char disk2name[256] = "\0";
|
char disk2name[256] = "\0";
|
||||||
|
|
||||||
|
@ -91,106 +83,275 @@ void write(void *arg, uint16_t address, uint8_t v)
|
||||||
// no action; this is a dummy function until we've finished initializing...
|
// no action; this is a dummy function until we've finished initializing...
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *cpu_thread(void *dummyptr) {
|
static struct timespec runBIOS(struct timespec now)
|
||||||
struct timespec currentTime;
|
{
|
||||||
|
static bool initialized = false;
|
||||||
|
static struct timespec startTime;
|
||||||
|
static struct timespec nextRuntime;
|
||||||
|
static uint64_t cycleCount = 0;
|
||||||
|
|
||||||
#if 0
|
if (!initialized) {
|
||||||
int policy;
|
do_gettime(&startTime);
|
||||||
struct sched_param param;
|
do_gettime(&nextRuntime);
|
||||||
pthread_getschedparam(pthread_self(), &policy, ¶m);
|
initialized = true;
|
||||||
param.sched_priority = sched_get_priority_max(policy);
|
}
|
||||||
pthread_setschedparam(pthread_self(), policy, ¶m);
|
|
||||||
#endif
|
timespec_add_us(&startTime, 100000*cycleCount, &nextRuntime); // FIXME: what's a good time here? 1/10 sec?
|
||||||
|
|
||||||
|
// Check if it's time to run - and if not, return how long it will
|
||||||
|
// be until we need to run
|
||||||
|
struct timespec diff = tsSubtract(nextRuntime, now);
|
||||||
|
if (diff.tv_sec > 0 || diff.tv_nsec > 0) {
|
||||||
|
// The caller can decide to nanosleep(&diff, NULL)
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
cycleCount++;
|
||||||
|
|
||||||
|
if (!bios.loop()) {
|
||||||
|
printf("BIOS loop has exited\n");
|
||||||
|
g_biosInterrupt = false; // that's all she wrote!
|
||||||
|
}
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct timespec runCPU(struct timespec now)
|
||||||
|
{
|
||||||
|
static bool initialized = false;
|
||||||
|
static struct timespec startTime;
|
||||||
|
static struct timespec nextInstructionTime;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
do_gettime(&startTime);
|
||||||
|
do_gettime(&nextInstructionTime);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for interrupt-like actions before running the CPU
|
||||||
|
if (wantSuspend) {
|
||||||
|
printf("CPU halted; suspending VM\n");
|
||||||
|
g_vm->Suspend("suspend.vm");
|
||||||
|
printf("... done; resuming CPU.\n");
|
||||||
|
wantSuspend = false;
|
||||||
|
}
|
||||||
|
if (wantResume) {
|
||||||
|
printf("CPU halted; resuming VM\n");
|
||||||
|
g_vm->Resume("suspend.vm");
|
||||||
|
printf("... done. resuming CPU.\n");
|
||||||
|
wantResume = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine correct time for next CPU cycle
|
||||||
|
timespec_add_cycles(&startTime, g_cpu->cycles, &nextInstructionTime);
|
||||||
|
|
||||||
|
// Check if it's time to run - and if not, return how long it will be until we need to run
|
||||||
|
struct timespec diff = tsSubtract(nextInstructionTime, now);
|
||||||
|
if (diff.tv_sec > 0 || diff.tv_nsec > 0) {
|
||||||
|
// The caller can decide to nanosleep(&diff, NULL)
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the CPU
|
||||||
|
uint8_t executed = 0;
|
||||||
|
if (debugger.active()) {
|
||||||
|
// With the debugger running, we need to single-step through
|
||||||
|
// instructions.
|
||||||
|
executed = g_cpu->Run(1);
|
||||||
|
} else {
|
||||||
|
// Otherwise we can run a bunch of instructions at once to
|
||||||
|
// save on the overhead.
|
||||||
|
executed = g_cpu->Run(24);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The paddles need to be triggered in real-time on the CPU
|
||||||
|
// clock. That happens from the VM's CPU maintenance poller.
|
||||||
|
((AppleVM *)g_vm)->cpuMaintenance(g_cpu->cycles);
|
||||||
|
|
||||||
|
if (debugger.active()) {
|
||||||
|
debugger.step();
|
||||||
|
// FIXME need to reset starttime for this and g_cpu->cycles
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send_rst) {
|
||||||
|
cpuDebuggerRunning = true;
|
||||||
|
|
||||||
_init_darwin_shim();
|
printf("Sending reset\n");
|
||||||
do_gettime(&startTime);
|
g_cpu->Reset();
|
||||||
printf("Start time: %lu,%lu\n", startTime.tv_sec, startTime.tv_nsec);
|
|
||||||
do_gettime(&nextInstructionTime);
|
send_rst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
printf("free-running\n");
|
#define TARGET_FPS 30
|
||||||
|
struct timespec runDisplay(struct timespec now)
|
||||||
|
{
|
||||||
|
static bool initialized = false;
|
||||||
|
static struct timespec startTime;
|
||||||
|
static struct timespec nextRuntime;
|
||||||
|
static uint64_t cycleCount = 0;
|
||||||
|
|
||||||
// In this loop, we determine when the next CPU event is; sleep until
|
if (!initialized) {
|
||||||
// that event; and then perform the event. There are also peripheral
|
do_gettime(&startTime);
|
||||||
// maintenance calls embedded in the loop...
|
do_gettime(&nextRuntime);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
timespec_add_us(&startTime, (1000000/TARGET_FPS)*cycleCount, &nextRuntime); // 1000000 uS/S and 30fps target
|
||||||
|
|
||||||
while (1) {
|
// Check if it's time to run - and if not, return how long it will
|
||||||
if (g_biosInterrupt) {
|
// be until we need to run
|
||||||
printf("BIOS blocking\n");
|
struct timespec diff = tsSubtract(nextRuntime, now);
|
||||||
while (g_biosInterrupt) {
|
if (diff.tv_sec > 0 || diff.tv_nsec > 0) {
|
||||||
usleep(100);
|
// The caller can decide to nanosleep(&diff, NULL)
|
||||||
}
|
return diff;
|
||||||
printf("BIOS block complete\n");
|
}
|
||||||
|
|
||||||
|
cycleCount++;
|
||||||
|
|
||||||
|
if (!g_biosInterrupt) {
|
||||||
|
g_ui->blit();
|
||||||
|
g_vm->vmdisplay->lockDisplay();
|
||||||
|
if (g_vm->vmdisplay->needsRedraw()) {
|
||||||
|
AiieRect what = g_vm->vmdisplay->getDirtyRect();
|
||||||
|
g_vm->vmdisplay->didRedraw();
|
||||||
|
g_display->blit(what);
|
||||||
}
|
}
|
||||||
|
g_vm->vmdisplay->unlockDisplay();
|
||||||
|
|
||||||
|
// For SDL, I'm throwing the printer update in with the display update...
|
||||||
|
g_printer->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
if (wantSuspend) {
|
|
||||||
printf("CPU halted; suspending VM\n");
|
|
||||||
g_vm->Suspend("suspend.vm");
|
|
||||||
printf("... done; resuming CPU.\n");
|
|
||||||
|
|
||||||
wantSuspend = false;
|
void doDebugging()
|
||||||
}
|
{
|
||||||
if (wantResume) {
|
char buf[25];
|
||||||
printf("CPU halted; resuming VM\n");
|
static time_t startAt = time(NULL);
|
||||||
g_vm->Resume("suspend.vm");
|
static uint32_t loopCount = 0;
|
||||||
printf("... done. resuming CPU.\n");
|
|
||||||
|
|
||||||
wantResume = false;
|
switch (g_debugMode) {
|
||||||
}
|
case D_SHOWFPS:
|
||||||
|
{
|
||||||
do_gettime(¤tTime);
|
// display some FPS data
|
||||||
|
loopCount++;
|
||||||
// Determine the next CPU runtime (nextInstructionTime)
|
uint32_t lenSecs = time(NULL) - startAt;
|
||||||
timespec_add_cycles(&startTime, g_cpu->cycles, &nextInstructionTime);
|
if (lenSecs >= 5) {
|
||||||
|
sprintf(buf, "%u FPS", loopCount / lenSecs);
|
||||||
// Sleep until the CPU is ready to run.
|
g_display->debugMsg(buf);
|
||||||
|
startAt = time(NULL);
|
||||||
// tsSubtract doesn't return negatives; it bounds at zero. So if
|
loopCount = 0;
|
||||||
// either result is zero then it's time to run something.
|
|
||||||
|
|
||||||
struct timespec cpudiff = tsSubtract(nextInstructionTime, currentTime);
|
|
||||||
|
|
||||||
if (cpudiff.tv_sec > 0 || cpudiff.tv_nsec > 0) {
|
|
||||||
// Sleep until the it's ready and loop...
|
|
||||||
nanosleep(&cpudiff, NULL);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cpudiff.tv_sec == 0 && cpudiff.tv_nsec == 0) {
|
|
||||||
// Run the CPU; it's caught up to "real time"
|
|
||||||
|
|
||||||
uint8_t executed = 0;
|
|
||||||
if (debugger.active()) {
|
|
||||||
// With the debugger running, we need to single-step through
|
|
||||||
// instructions.
|
|
||||||
executed = g_cpu->Run(1);
|
|
||||||
} else {
|
|
||||||
// Otherwise we can run a bunch of instructions at once to
|
|
||||||
// save on the overhead.
|
|
||||||
executed = g_cpu->Run(24);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The paddles need to be triggered in real-time on the CPU
|
|
||||||
// clock. That happens from the VM's CPU maintenance poller.
|
|
||||||
((AppleVM *)g_vm)->cpuMaintenance(g_cpu->cycles);
|
|
||||||
|
|
||||||
if (debugger.active()) {
|
|
||||||
debugger.step();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (send_rst) {
|
|
||||||
cpuDebuggerRunning = true;
|
|
||||||
|
|
||||||
printf("Sending reset\n");
|
|
||||||
g_cpu->Reset();
|
|
||||||
|
|
||||||
send_rst = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case D_SHOWMEMFREE:
|
||||||
|
// sprintf(buf, "%lu %u", FreeRamEstimate(), heapSize());
|
||||||
|
// g_display->debugMsg(buf);
|
||||||
|
break;
|
||||||
|
case D_SHOWPADDLES:
|
||||||
|
sprintf(buf, "%u %u", g_paddles->paddle0(), g_paddles->paddle1());
|
||||||
|
g_display->debugMsg(buf);
|
||||||
|
break;
|
||||||
|
case D_SHOWPC:
|
||||||
|
sprintf(buf, "%X", g_cpu->pc);
|
||||||
|
g_display->debugMsg(buf);
|
||||||
|
break;
|
||||||
|
case D_SHOWCYCLES:
|
||||||
|
sprintf(buf, "%llX", g_cpu->cycles);
|
||||||
|
g_display->debugMsg(buf);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
case D_SHOWBATTERY:
|
||||||
|
// sprintf(buf, "BAT %d", analogRead(BATTERYPIN));
|
||||||
|
// g_display->debugMsg(buf);
|
||||||
|
break;
|
||||||
|
case D_SHOWTIME:
|
||||||
|
// sprintf(buf, "%.2d:%.2d:%.2d", hour(), minute(), second());
|
||||||
|
// g_display->debugMsg(buf);
|
||||||
|
break;*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timespec runMaintenance(struct timespec now)
|
||||||
|
{
|
||||||
|
static bool initialized = false;
|
||||||
|
static struct timespec startTime;
|
||||||
|
static struct timespec nextRuntime;
|
||||||
|
static uint64_t cycleCount = 0;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
do_gettime(&startTime);
|
||||||
|
do_gettime(&nextRuntime);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
timespec_add_us(&startTime, 100000*cycleCount, &nextRuntime); // FIXME: what's a good time here? 1/10 sec?
|
||||||
|
|
||||||
|
// Check if it's time to run - and if not, return how long it will
|
||||||
|
// be until we need to run
|
||||||
|
struct timespec diff = tsSubtract(nextRuntime, now);
|
||||||
|
if (diff.tv_sec > 0 || diff.tv_nsec > 0) {
|
||||||
|
// The caller can decide to nanosleep(&diff, NULL)
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
cycleCount++;
|
||||||
|
if (!g_biosInterrupt) {
|
||||||
|
// If the BIOS is running, then let it handle the keyboard directly
|
||||||
|
g_keyboard->maintainKeyboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
doDebugging();
|
||||||
|
g_ui->drawPercentageUIElement(UIePowerPercentage, 100);
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
struct timespec now;
|
||||||
|
do_gettime(&now);
|
||||||
|
|
||||||
|
struct timespec shortest;
|
||||||
|
|
||||||
|
static bool wasBios = false; // so we can tell when it's done
|
||||||
|
if (g_biosInterrupt) {
|
||||||
|
shortest = runBIOS(now);
|
||||||
|
wasBios = true;
|
||||||
|
} else {
|
||||||
|
if (wasBios) {
|
||||||
|
// bios has just exited
|
||||||
|
writePrefs();
|
||||||
|
wasBios = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_biosInterrupt) {
|
||||||
|
shortest = runCPU(now); // about 13% CPU utilization on my laptop
|
||||||
|
}
|
||||||
|
struct timespec diff;
|
||||||
|
diff = runDisplay(now); // about 47% CPU utilization on my laptop
|
||||||
|
if (tsCompare(&shortest, &diff) > 0)
|
||||||
|
shortest = diff;
|
||||||
|
diff = runMaintenance(now); // about 1% CPU utilization on my laptop
|
||||||
|
if (tsCompare(&shortest, &diff) > 0)
|
||||||
|
shortest = diff;
|
||||||
|
|
||||||
|
// If they all have time remaining then sleep until one is ready
|
||||||
|
if (shortest.tv_sec || shortest.tv_nsec) {
|
||||||
|
nanosleep(&shortest, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
_init_darwin_shim();
|
||||||
|
|
||||||
SDL_Init(SDL_INIT_EVERYTHING);
|
SDL_Init(SDL_INIT_EVERYTHING);
|
||||||
|
|
||||||
g_speaker = new SDLSpeaker();
|
g_speaker = new SDLSpeaker();
|
||||||
|
@ -250,177 +411,11 @@ int main(int argc, char *argv[])
|
||||||
signal(SIGINT, sigint_handler);
|
signal(SIGINT, sigint_handler);
|
||||||
signal(SIGPIPE, SIG_IGN); // debugger might have a SIGPIPE happen if the remote end drops
|
signal(SIGPIPE, SIG_IGN); // debugger might have a SIGPIPE happen if the remote end drops
|
||||||
|
|
||||||
printf("creating CPU thread\n");
|
|
||||||
if (!pthread_create(&cpuThreadID, NULL, &cpu_thread, (void *)NULL)) {
|
|
||||||
printf("thread created\n");
|
|
||||||
// pthread_setschedparam(cpuThreadID, SCHED_RR, PTHREAD_MAX_PRIORITY);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_speaker->begin();
|
g_speaker->begin();
|
||||||
|
|
||||||
int64_t lastCycleCount = -1;
|
printf("Starting loop\n");
|
||||||
while (1) {
|
while (1) {
|
||||||
|
loop();
|
||||||
if (g_biosInterrupt) {
|
|
||||||
printf("Invoking BIOS\n");
|
|
||||||
if (bios.runUntilDone()) {
|
|
||||||
// if it returned true, we have something to store persistently in EEPROM.
|
|
||||||
writePrefs();
|
|
||||||
}
|
|
||||||
printf("BIOS done\n");
|
|
||||||
|
|
||||||
// if we turned off debugMode, make sure to clear the debugMsg
|
|
||||||
if (g_debugMode == D_NONE) {
|
|
||||||
g_display->debugMsg("");
|
|
||||||
}
|
|
||||||
|
|
||||||
g_biosInterrupt = false;
|
|
||||||
|
|
||||||
// clear the CPU next-step counters
|
|
||||||
g_cpu->cycles = 0;
|
|
||||||
do_gettime(&startTime);
|
|
||||||
do_gettime(&nextInstructionTime);
|
|
||||||
|
|
||||||
// FIXME: drain whatever's in the speaker queue
|
|
||||||
|
|
||||||
/* FIXME
|
|
||||||
// Force the display to redraw
|
|
||||||
((AppleDisplay*)(g_vm->vmdisplay))->modeChange();
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Poll the keyboard before we start, so we can do selftest on startup
|
|
||||||
g_keyboard->maintainKeyboard();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int64_t usleepcycles = 16384*4; // step-down for display drawing. Dynamically updated based on FPS calculations.
|
|
||||||
|
|
||||||
if (g_vm->vmdisplay->needsRedraw()) {
|
|
||||||
AiieRect what = g_vm->vmdisplay->getDirtyRect();
|
|
||||||
// make sure to clear the flag before drawing; there's no lock
|
|
||||||
// on didRedraw, so the other thread might update it
|
|
||||||
g_vm->vmdisplay->didRedraw();
|
|
||||||
g_display->blit(what);
|
|
||||||
}
|
|
||||||
g_ui->blit();
|
|
||||||
|
|
||||||
g_printer->update();
|
|
||||||
g_keyboard->maintainKeyboard();
|
|
||||||
|
|
||||||
doDebugging();
|
|
||||||
|
|
||||||
g_ui->drawPercentageUIElement(UIePowerPercentage, 100);
|
|
||||||
|
|
||||||
// calculate FPS & dynamically step up/down as necessary
|
|
||||||
static time_t startAt = time(NULL);
|
|
||||||
static uint32_t loopCount = 0;
|
|
||||||
loopCount++;
|
|
||||||
uint32_t lenSecs = time(NULL) - startAt;
|
|
||||||
if (lenSecs >= 5) {
|
|
||||||
float fps = loopCount / lenSecs;
|
|
||||||
|
|
||||||
#ifdef SHOWFPS
|
|
||||||
char buf[25];
|
|
||||||
sprintf(buf, "%f FPS [delay %u]", fps, usleepcycles);
|
|
||||||
g_display->debugMsg(buf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (fps > 30 && usleepcycles < 0x3FFFFFFF) {
|
|
||||||
usleepcycles *= 2;
|
|
||||||
} else if (fps < 20 && usleepcycles > 0xF) {
|
|
||||||
usleepcycles /= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset the counter & we'll adjust again in 5 seconds
|
|
||||||
loopCount = 0;
|
|
||||||
startAt = time(NULL);
|
|
||||||
}
|
|
||||||
if (usleepcycles >= 2) {
|
|
||||||
usleep(usleepcycles);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SHOWPC
|
|
||||||
{
|
|
||||||
char buf[25];
|
|
||||||
sprintf(buf, "%X", g_cpu->pc);
|
|
||||||
g_display->debugMsg(buf);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef SHOWMEMPAGE
|
|
||||||
{
|
|
||||||
char buf[40];
|
|
||||||
sprintf(buf, "AUX %c/%c BNK %d BSR %c/%c ZP %c 80 %c INT %c",
|
|
||||||
g_vm->auxRamRead?'R':'_',
|
|
||||||
g_vm->auxRamWrite?'W':'_',
|
|
||||||
g_vm->bank1,
|
|
||||||
g_vm->readbsr ? 'R':'_',
|
|
||||||
g_vm->writebsr ? 'W':'_',
|
|
||||||
g_vm->altzp ? 'Y':'_',
|
|
||||||
g_vm->_80store ? 'Y' : '_',
|
|
||||||
g_vm->intcxrom ? 'Y' : '_');
|
|
||||||
g_display->debugMsg(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (g_cpu->cycles == lastCycleCount) {
|
|
||||||
// If the CPU didn't advance during our last loop, then delay
|
|
||||||
// here; there can't be any substantial updates, so no need to
|
|
||||||
// beat up the host machine
|
|
||||||
|
|
||||||
usleep(100000);
|
|
||||||
} else {
|
|
||||||
lastCycleCount = g_cpu->cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void doDebugging()
|
|
||||||
{
|
|
||||||
char buf[25];
|
|
||||||
static time_t startAt = time(NULL);
|
|
||||||
static uint32_t loopCount = 0;
|
|
||||||
|
|
||||||
switch (g_debugMode) {
|
|
||||||
case D_SHOWFPS:
|
|
||||||
{
|
|
||||||
// display some FPS data
|
|
||||||
loopCount++;
|
|
||||||
uint32_t lenSecs = time(NULL) - startAt;
|
|
||||||
if (lenSecs >= 5) {
|
|
||||||
sprintf(buf, "%u FPS", loopCount / lenSecs);
|
|
||||||
g_display->debugMsg(buf);
|
|
||||||
startAt = time(NULL);
|
|
||||||
loopCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case D_SHOWMEMFREE:
|
|
||||||
// sprintf(buf, "%lu %u", FreeRamEstimate(), heapSize());
|
|
||||||
// g_display->debugMsg(buf);
|
|
||||||
break;
|
|
||||||
case D_SHOWPADDLES:
|
|
||||||
sprintf(buf, "%u %u", g_paddles->paddle0(), g_paddles->paddle1());
|
|
||||||
g_display->debugMsg(buf);
|
|
||||||
break;
|
|
||||||
case D_SHOWPC:
|
|
||||||
sprintf(buf, "%X", g_cpu->pc);
|
|
||||||
g_display->debugMsg(buf);
|
|
||||||
break;
|
|
||||||
case D_SHOWCYCLES:
|
|
||||||
sprintf(buf, "%llX", g_cpu->cycles);
|
|
||||||
g_display->debugMsg(buf);
|
|
||||||
break;
|
|
||||||
/*
|
|
||||||
case D_SHOWBATTERY:
|
|
||||||
// sprintf(buf, "BAT %d", analogRead(BATTERYPIN));
|
|
||||||
// g_display->debugMsg(buf);
|
|
||||||
break;
|
|
||||||
case D_SHOWTIME:
|
|
||||||
// sprintf(buf, "%.2d:%.2d:%.2d", hour(), minute(), second());
|
|
||||||
// g_display->debugMsg(buf);
|
|
||||||
break;*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,46 +169,52 @@ uint8_t keyPending;
|
||||||
bool SDLKeyboard::kbhit()
|
bool SDLKeyboard::kbhit()
|
||||||
{
|
{
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
if (SDL_PollEvent( &event ) &&
|
if (SDL_PollEvent( &event )) {
|
||||||
event.type == SDL_KEYDOWN) {
|
if (event.type == SDL_QUIT) {
|
||||||
SDL_KeyboardEvent *key = &event.key;
|
exit(0);
|
||||||
if ( (key->keysym.sym >= 'a' && key->keysym.sym <= 'z') ||
|
}
|
||||||
(key->keysym.sym >= '0' && key->keysym.sym <= '9') ||
|
|
||||||
key->keysym.sym == '-' ||
|
if (event.type == SDL_KEYDOWN) {
|
||||||
key->keysym.sym == '=' ||
|
SDL_KeyboardEvent *key = &event.key;
|
||||||
key->keysym.sym == '[' ||
|
|
||||||
key->keysym.sym == '`' ||
|
if ( (key->keysym.sym >= 'a' && key->keysym.sym <= 'z') ||
|
||||||
key->keysym.sym == ']' ||
|
(key->keysym.sym >= '0' && key->keysym.sym <= '9') ||
|
||||||
key->keysym.sym == '\\' ||
|
key->keysym.sym == '-' ||
|
||||||
key->keysym.sym == ';' ||
|
key->keysym.sym == '=' ||
|
||||||
key->keysym.sym == '\'' ||
|
key->keysym.sym == '[' ||
|
||||||
key->keysym.sym == ',' ||
|
key->keysym.sym == '`' ||
|
||||||
key->keysym.sym == '.' ||
|
key->keysym.sym == ']' ||
|
||||||
key->keysym.sym == '/' ||
|
key->keysym.sym == '\\' ||
|
||||||
key->keysym.sym == ' ' ||
|
key->keysym.sym == ';' ||
|
||||||
key->keysym.sym == 27 || // ESC
|
key->keysym.sym == '\'' ||
|
||||||
key->keysym.sym == 13 || // return
|
key->keysym.sym == ',' ||
|
||||||
key->keysym.sym == 9) { // tab
|
key->keysym.sym == '.' ||
|
||||||
keyPending = key->keysym.sym;
|
key->keysym.sym == '/' ||
|
||||||
hasKeyPending = true;
|
key->keysym.sym == ' ' ||
|
||||||
} else {
|
key->keysym.sym == 27 || // ESC
|
||||||
switch (key->keysym.sym) {
|
key->keysym.sym == 13 || // return
|
||||||
case SDLK_UP:
|
key->keysym.sym == 9) { // tab
|
||||||
keyPending = PK_UARR;
|
keyPending = key->keysym.sym;
|
||||||
hasKeyPending = true;
|
hasKeyPending = true;
|
||||||
break;
|
} else {
|
||||||
case SDLK_DOWN:
|
switch (key->keysym.sym) {
|
||||||
keyPending = PK_DARR;
|
case SDLK_UP:
|
||||||
hasKeyPending = true;
|
keyPending = PK_UARR;
|
||||||
break;
|
hasKeyPending = true;
|
||||||
case SDLK_RIGHT:
|
break;
|
||||||
keyPending = PK_RARR;
|
case SDLK_DOWN:
|
||||||
hasKeyPending = true;
|
keyPending = PK_DARR;
|
||||||
break;
|
hasKeyPending = true;
|
||||||
case SDLK_LEFT:
|
break;
|
||||||
keyPending = PK_LARR;
|
case SDLK_RIGHT:
|
||||||
hasKeyPending = true;
|
keyPending = PK_RARR;
|
||||||
break;
|
hasKeyPending = true;
|
||||||
|
break;
|
||||||
|
case SDLK_LEFT:
|
||||||
|
keyPending = PK_LARR;
|
||||||
|
hasKeyPending = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ static void audioCallback(void *unused, Uint8 *stream, int len)
|
||||||
} else if (audioRunning==1) {
|
} else if (audioRunning==1) {
|
||||||
// waiting for first fill; return an empty buffer.
|
// waiting for first fill; return an empty buffer.
|
||||||
memset(stream, 0, SDLSIZE*SAMPLEBYTES);
|
memset(stream, 0, SDLSIZE*SAMPLEBYTES);
|
||||||
|
pthread_mutex_unlock(&togmutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue