mirror of
https://github.com/Oibaf66/frodo-wii.git
synced 2024-11-11 06:05:13 +01:00
735 lines
18 KiB
C
735 lines
18 KiB
C
/*
|
||
* C64_x.i - Put the pieces together, X specific stuff
|
||
*
|
||
* Frodo (C) 1994-1997,2002 Christian Bauer
|
||
* Unix stuff by Bernd Schmidt/Lutz Vieweg
|
||
*/
|
||
|
||
#include "main.h"
|
||
|
||
#include <sys/types.h>
|
||
#include <dirent.h>
|
||
|
||
#if defined(GEKKO)
|
||
#include <wiiuse/wpad.h>
|
||
#include <ogc/lwp_watchdog.h>
|
||
#define FONT_PATH "/apps/frodo/FreeMono.ttf"
|
||
#define SAVES_PATH "/apps/frodo/saves"
|
||
#define IMAGE_PATH "/apps/frodo/images"
|
||
#define TMP_PATH "/apps/frodo/tmp"
|
||
#else
|
||
#define FONT_PATH "FreeMono.ttf"
|
||
#define SAVES_PATH "saves"
|
||
#define IMAGE_PATH "images"
|
||
#define TMP_PATH "tmp"
|
||
#endif
|
||
|
||
static struct timeval tv_start;
|
||
static int MENU_SIZE_X, MENU_SIZE_Y;
|
||
static const char *main_menu_messages[] = {
|
||
"Invoke key sequence", /* 0 */
|
||
"Insert disc or tape", /* 1 */
|
||
"Reset C64", /* 2 */
|
||
"Bind key to joystick",/* 3 */
|
||
"Other options", /* 4 */
|
||
"Controller 1 joystick port", /* 5 */
|
||
"^|1|2",
|
||
"Save/Load state", /* 7 */
|
||
" ",
|
||
"Quit", /* 9 */
|
||
NULL,
|
||
};
|
||
|
||
static const char *other_options_messages[] = {
|
||
"Display resolution", /* 0 */
|
||
"^|double-center|stretched",
|
||
"Speed (approx)", /* 2 */
|
||
"^|95|100|110",
|
||
"Emulate 1541", /* 4 */
|
||
"^|On|Off",
|
||
NULL,
|
||
};
|
||
|
||
static const char *save_load_state_messages[] = {
|
||
"Load saved state", /* 0 */
|
||
"Save current state", /* 1 */
|
||
"Delete state", /* 2 */
|
||
NULL,
|
||
};
|
||
|
||
/*
|
||
* Constructor, system-dependent things
|
||
*/
|
||
void C64::c64_ctor1(void)
|
||
{
|
||
// Initialize joystick variables
|
||
#ifdef HAVE_LINUX_JOYSTICK_H
|
||
joyfd[0] = joyfd[1] = -1;
|
||
joy_minx = joy_miny = 32767;
|
||
joy_maxx = joy_maxy = -32768;
|
||
#endif
|
||
|
||
this->fake_key_sequence = false;
|
||
this->fake_key_index = 0;
|
||
this->fake_key_keytime = 5;
|
||
this->fake_key_str = "\nLOAD \"*\",8,1\nRUN\n";
|
||
|
||
this->prefs_changed = false;
|
||
memset(this->save_game_name, 0, sizeof(this->save_game_name));
|
||
strcpy(this->save_game_name, "unknown");
|
||
|
||
MENU_SIZE_X = FULL_DISPLAY_X - FULL_DISPLAY_X / 4;
|
||
MENU_SIZE_Y = FULL_DISPLAY_Y - FULL_DISPLAY_Y / 4;
|
||
|
||
SDL_RWops *rw;
|
||
|
||
Uint8 *data = (Uint8*)malloc(1 * 1024*1024);
|
||
FILE *fp = fopen(FONT_PATH, "r");
|
||
if (!fp) {
|
||
fprintf(stderr, "Could not open font\n");
|
||
exit(1);
|
||
}
|
||
fread(data, 1, 1 * 1024 * 1024, fp);
|
||
rw = SDL_RWFromMem(data, 1 * 1024 * 1024);
|
||
if (!rw) {
|
||
fprintf(stderr, "Could not create RW: %s\n", SDL_GetError());
|
||
exit(1);
|
||
}
|
||
|
||
this->menu_font = TTF_OpenFontRW(rw, 1, 20);
|
||
if (!this->menu_font)
|
||
{
|
||
fprintf(stderr, "Unable to open font\n" );
|
||
exit(1);
|
||
}
|
||
menu_init(&this->main_menu, this->menu_font, main_menu_messages,
|
||
32, 32, MENU_SIZE_X, MENU_SIZE_Y);
|
||
}
|
||
|
||
void C64::c64_ctor2(void)
|
||
{
|
||
gettimeofday(&tv_start, NULL);
|
||
}
|
||
|
||
|
||
/*
|
||
* Destructor, system-dependent things
|
||
*/
|
||
|
||
void C64::c64_dtor(void)
|
||
{
|
||
menu_fini(&this->main_menu);
|
||
}
|
||
|
||
static int cmpstringp(const void *p1, const void *p2)
|
||
{
|
||
return strcmp(* (char * const *) p1, * (char * const *) p2);
|
||
}
|
||
|
||
/* Return true if name ends with ext (for filenames) */
|
||
static bool ext_matches(const char *name, const char *ext)
|
||
{
|
||
int len = strlen(name);
|
||
int ext_len = strlen(ext);
|
||
|
||
if (len <= ext_len)
|
||
return false;
|
||
return (strcmp(name + len - ext_len, ext) == 0);
|
||
|
||
}
|
||
|
||
static const char **get_file_list(const char *base_dir)
|
||
{
|
||
DIR *d = opendir(base_dir);
|
||
const char **file_list;
|
||
int cur = 0;
|
||
struct dirent *de;
|
||
int cnt = 16;
|
||
|
||
if (!d)
|
||
return NULL;
|
||
|
||
file_list = (const char**)malloc(cnt * sizeof(char*));
|
||
file_list[cur++] = strdup("None");
|
||
file_list[cur] = NULL;
|
||
|
||
for (de = readdir(d);
|
||
de;
|
||
de = readdir(d))
|
||
{
|
||
if (ext_matches(de->d_name, ".d64") || ext_matches(de->d_name, ".D64") ||
|
||
ext_matches(de->d_name, ".prg") || ext_matches(de->d_name, ".PRG") ||
|
||
ext_matches(de->d_name, ".p00") || ext_matches(de->d_name, ".P00") ||
|
||
ext_matches(de->d_name, ".s00") || ext_matches(de->d_name, ".S00") ||
|
||
ext_matches(de->d_name, ".t64") || ext_matches(de->d_name, ".T64") ||
|
||
ext_matches(de->d_name, ".sav"))
|
||
{
|
||
char *p;
|
||
|
||
p = strdup(de->d_name);
|
||
file_list[cur++] = p;
|
||
file_list[cur] = NULL;
|
||
if (cur > cnt - 2)
|
||
{
|
||
cnt = cnt + 32;
|
||
file_list = (const char**)realloc(file_list, cnt * sizeof(char*));
|
||
if (!file_list)
|
||
return NULL;
|
||
}
|
||
}
|
||
}
|
||
closedir(d);
|
||
qsort(&file_list[1], cur-1, sizeof(const char *), cmpstringp);
|
||
|
||
return file_list;
|
||
}
|
||
|
||
void C64::select_disc(Prefs *np)
|
||
{
|
||
const char **file_list = get_file_list(IMAGE_PATH);
|
||
menu_t select_disc_menu;
|
||
|
||
if (file_list == NULL)
|
||
return;
|
||
|
||
menu_init(&select_disc_menu, this->menu_font, file_list,
|
||
32, 32, MENU_SIZE_X, MENU_SIZE_Y);
|
||
int opt = menu_select(real_screen, &select_disc_menu, NULL);
|
||
if (opt >= 0)
|
||
{
|
||
const char *name = file_list[opt];
|
||
|
||
if (strcmp(file_list[opt], "None") == 0)
|
||
{
|
||
strcpy(np->DrivePath[0], "\0");
|
||
strcpy(this->save_game_name, "unknown");
|
||
}
|
||
else
|
||
{
|
||
snprintf(np->DrivePath[0], 255, "%s/%s",
|
||
IMAGE_PATH, name);
|
||
strncpy(this->save_game_name, name, 255);
|
||
if (strstr(name, ".prg") || strstr(name, ".PRG") ||
|
||
strstr(name, ".p00") || strstr(name, ".P00") ||
|
||
strstr(name, ".s00") || strstr(name, ".S00")) {
|
||
FILE *src, *dst;
|
||
|
||
/* Clean temp dir first (we only want one file) */
|
||
unlink(TMP_PATH"/a");
|
||
|
||
src = fopen(np->DrivePath[0], "r");
|
||
if (src != NULL)
|
||
{
|
||
snprintf(np->DrivePath[0], 255, "%s", TMP_PATH);
|
||
|
||
/* Special handling of .prg: Copy to TMP_PATH and
|
||
* load that as a dir */
|
||
dst = fopen(TMP_PATH"/a", "w");
|
||
if (dst)
|
||
{
|
||
Uint8 buf[1024];
|
||
size_t v;
|
||
|
||
do {
|
||
v = fread(buf, 1, 1024, src);
|
||
fwrite(buf, 1, v, dst);
|
||
} while (v > 0);
|
||
fclose(dst);
|
||
}
|
||
fclose(src);
|
||
}
|
||
}
|
||
|
||
NewPrefs(np);
|
||
ThePrefs = *np;
|
||
}
|
||
this->prefs_changed = true;
|
||
}
|
||
menu_fini(&select_disc_menu);
|
||
|
||
/* Cleanup everything */
|
||
for ( int i = 0; file_list[i]; i++ )
|
||
free((void*)file_list[i]);
|
||
free(file_list);
|
||
}
|
||
|
||
/*
|
||
C64 keyboard matrix:
|
||
|
||
Bit 7 6 5 4 3 2 1 0
|
||
0 CUD F5 F3 F1 F7 CLR RET DEL
|
||
1 SHL E S Z 4 A W 3
|
||
2 X T F C 6 D R 5
|
||
3 V U H B 8 G Y 7
|
||
4 N O K M 0 J I 9
|
||
5 , @ : . - L P +
|
||
6 / ^ = SHR HOM ; * <20>
|
||
7 R/S Q C= SPC 2 CTL <- 1
|
||
*/
|
||
#define MATRIX(a,b) (((a) << 3) | (b))
|
||
|
||
static const char *key_names[] = { "None", "space", "Run/Stop", "return",
|
||
"F1", "F3", "F5", "F7",
|
||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
|
||
"B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
|
||
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
||
"ctrl", "del", "home", "shl", "shr", "clr", "C=", "left arrow",
|
||
"arrow up", "key down", "key up", "key left", "key right",
|
||
NULL };
|
||
|
||
static int key_keycodes[] = { 0, MATRIX(7, 4), MATRIX(7, 7), MATRIX(0, 1), /* space, R/S, return */
|
||
MATRIX(0, 4), MATRIX(0, 5), MATRIX(0, 6), MATRIX(0, 3), /* F1-F7 */
|
||
MATRIX(4, 3), MATRIX(7, 0), MATRIX(7, 3), MATRIX(1, 0), MATRIX(1, 3), /* 0.. */
|
||
MATRIX(2, 0), MATRIX(2, 3), MATRIX(3, 0), MATRIX(3, 3), MATRIX(4, 0), /* ..9 */
|
||
MATRIX(1, 2), MATRIX(3, 4), MATRIX(2, 4), MATRIX(2, 2),
|
||
MATRIX(1, 6), MATRIX(2, 5), MATRIX(3, 2), MATRIX(3, 5), MATRIX(4, 1), MATRIX(4, 2),
|
||
MATRIX(4, 5), MATRIX(5, 2), MATRIX(4, 4), MATRIX(4, 7), MATRIX(4, 6), MATRIX(5, 1),
|
||
MATRIX(7, 6), MATRIX(2, 1), MATRIX(1, 5), MATRIX(2, 6), MATRIX(3, 6), MATRIX(3, 7),
|
||
MATRIX(1, 1), MATRIX(2, 7), MATRIX(3, 1), MATRIX(1, 4), /* ... Z */
|
||
MATRIX(7, 3), MATRIX(0, 0), MATRIX(6, 4), MATRIX(1, 7), MATRIX(6, 4),
|
||
MATRIX(0, 2), MATRIX(7, 5), MATRIX(7, 1), MATRIX(6, 6),
|
||
MATRIX(0, 7), MATRIX(0, 7) | 0x80, MATRIX(0, 2) | 0x80, MATRIX(0, 2),/* Direction keys */
|
||
};
|
||
|
||
char *C64::bind_one_key(Prefs *np, int which)
|
||
{
|
||
static const char *which_to_button_name[] = { "A", "B", "+", "-", "1",
|
||
"classic X", "classic Y", "classic B", "classic L",
|
||
"classic R", "classic ZR", "classic ZL" };
|
||
static char strs[N_WIIMOTE_BINDINGS][255];
|
||
char *out = strs[which];
|
||
const char *cur_binding = "None";
|
||
int cur = np->JoystickKeyBinding[which];
|
||
|
||
for (unsigned int i = 1; i < sizeof(key_keycodes) / sizeof(key_keycodes[0]); i++ )
|
||
{
|
||
if (key_keycodes[i] == cur)
|
||
{
|
||
cur_binding = key_names[i];
|
||
break;
|
||
}
|
||
}
|
||
snprintf(out, 255, "Bind to %s (now %s)", which_to_button_name[which],
|
||
cur_binding);
|
||
|
||
return out;
|
||
}
|
||
|
||
void C64::bind_keys(Prefs *np)
|
||
{
|
||
const char *bind_key_messages[N_WIIMOTE_BINDINGS + 1];
|
||
bool has_classic_controller = false;
|
||
menu_t bind_key_menu;
|
||
menu_t key_menu;
|
||
|
||
#if defined(GEKKO)
|
||
WPADData *wpad, *wpad_other;
|
||
|
||
wpad = WPAD_Data(0);
|
||
wpad_other = WPAD_Data(1);
|
||
|
||
if (wpad->exp.type == WPAD_EXP_CLASSIC ||
|
||
wpad_other->exp.type == WPAD_EXP_CLASSIC)
|
||
has_classic_controller = true;
|
||
#endif
|
||
|
||
memset(bind_key_messages, 0, sizeof(const char*) * (N_WIIMOTE_BINDINGS + 1));
|
||
|
||
for (int i = 0; i < (has_classic_controller ? N_WIIMOTE_BINDINGS : 5); i++)
|
||
bind_key_messages[i] = this->bind_one_key(np, i);
|
||
|
||
menu_init(&bind_key_menu, this->menu_font, bind_key_messages,
|
||
32, 32, MENU_SIZE_X, MENU_SIZE_Y);
|
||
int opt = menu_select(real_screen, &bind_key_menu, NULL);
|
||
if (opt >= 0)
|
||
{
|
||
menu_init(&key_menu, this->menu_font, key_names,
|
||
32, 32, MENU_SIZE_X, MENU_SIZE_Y);
|
||
int key = menu_select(real_screen, &key_menu, NULL);
|
||
|
||
/* Assume prefs are changed */
|
||
this->prefs_changed = true;
|
||
if (key > 0)
|
||
np->JoystickKeyBinding[opt] = key_keycodes[key];
|
||
else if (key == 0)
|
||
np->JoystickKeyBinding[opt] = -1;
|
||
else
|
||
this->prefs_changed = false;
|
||
menu_fini(&key_menu);
|
||
}
|
||
menu_fini(&bind_key_menu);
|
||
}
|
||
|
||
void C64::other_options(Prefs *np)
|
||
{
|
||
menu_t display_menu;
|
||
int submenus[3] = { np->DisplayOption, 0, !np->Emul1541Proc };
|
||
|
||
#define SPEED_95 33
|
||
#define SPEED_100 28
|
||
#define SPEED_110 25
|
||
|
||
switch (np->MsPerFrame)
|
||
{
|
||
case SPEED_95:
|
||
submenus[1] = 0; break;
|
||
case SPEED_110:
|
||
submenus[1] = 2; break;
|
||
default:
|
||
/* If it has some other value... */
|
||
submenus[1] = 1; break;
|
||
}
|
||
menu_init(&display_menu, this->menu_font, other_options_messages,
|
||
32, 32, MENU_SIZE_X, MENU_SIZE_Y);
|
||
int opt = menu_select(real_screen, &display_menu, submenus);
|
||
if (opt >= 0)
|
||
{
|
||
np->DisplayOption = submenus[0];
|
||
np->Emul1541Proc = submenus[2] == 0 ? true : false;
|
||
|
||
switch(submenus[1])
|
||
{
|
||
case 0:
|
||
np->MsPerFrame = SPEED_95; break;
|
||
case 1:
|
||
np->MsPerFrame = SPEED_100; break;
|
||
case 2:
|
||
default:
|
||
np->MsPerFrame = SPEED_110; break;
|
||
}
|
||
this->prefs_changed = true;
|
||
}
|
||
menu_fini(&display_menu);
|
||
}
|
||
|
||
void C64::run_fake_key_sequence(Prefs *np)
|
||
{
|
||
static const char *fake_key_sequences[] = {
|
||
"\nLOAD \"*\",8,1\nRUN\n",
|
||
"\nLOAD \"?\",8\n",
|
||
"\nLIST\n",
|
||
"\n10 PRINT \"HELLO WORLD\"\n20 GOTO 10\nRUN\n",
|
||
NULL};
|
||
const char *fake_key_messages[] = {
|
||
"LOAD \"*\",8,1 and RUN",
|
||
"LOAD \"?\",8",
|
||
"LIST",
|
||
"10 PRINT \"HELLO WORLD\" and 20 GOTO 10",
|
||
NULL};
|
||
menu_t fake_key_menu;
|
||
int opt;
|
||
|
||
menu_init(&fake_key_menu, this->menu_font, fake_key_messages,
|
||
32, 32, MENU_SIZE_X, MENU_SIZE_Y);
|
||
|
||
opt = menu_select(real_screen, &fake_key_menu, NULL);
|
||
menu_fini(&fake_key_menu);
|
||
if (opt < 0)
|
||
return;
|
||
|
||
this->fake_key_str = fake_key_sequences[opt];
|
||
this->fake_key_sequence = true;
|
||
}
|
||
|
||
void C64::save_load_state(Prefs *np)
|
||
{
|
||
menu_t save_load_menu;
|
||
menu_t select_saves_menu;
|
||
|
||
menu_init(&save_load_menu, this->menu_font, save_load_state_messages,
|
||
32, 32, MENU_SIZE_X, MENU_SIZE_Y);
|
||
int opt = menu_select(real_screen, &save_load_menu, NULL);
|
||
switch(opt)
|
||
{
|
||
case 1: /* save */
|
||
{
|
||
char save_buf[255];
|
||
char prefs_buf[255];
|
||
|
||
snprintf(save_buf, 255, "%s/%s.sav", SAVES_PATH,
|
||
this->save_game_name);
|
||
snprintf(prefs_buf, 255, "%s.prefs", save_buf);
|
||
|
||
this->SaveSnapshot(save_buf);
|
||
np->Save(prefs_buf);
|
||
} break;
|
||
case 0: /* load/delete */
|
||
case 2:
|
||
{
|
||
const char **file_list = get_file_list(SAVES_PATH);
|
||
|
||
if (file_list == NULL)
|
||
break;
|
||
menu_init(&select_saves_menu, this->menu_font, file_list,
|
||
32, 32, MENU_SIZE_X, MENU_SIZE_Y);
|
||
int save = menu_select(real_screen, &select_saves_menu, NULL);
|
||
if (save >= 0)
|
||
{
|
||
char save_buf[255];
|
||
char prefs_buf[255];
|
||
|
||
snprintf(save_buf, 255, "%s/%s", SAVES_PATH, file_list[save]);
|
||
snprintf(prefs_buf, 255, "%s.prefs", save_buf);
|
||
if (opt == 2)
|
||
{
|
||
unlink(save_buf);
|
||
unlink(prefs_buf);
|
||
}
|
||
else /* Load the snapshot */
|
||
{
|
||
this->LoadSnapshot(save_buf);
|
||
np->Load(prefs_buf);
|
||
this->prefs_changed = true;
|
||
}
|
||
}
|
||
menu_fini(&select_saves_menu);
|
||
|
||
/* Cleanup everything */
|
||
for ( int i = 0; file_list[i]; i++ )
|
||
free((void*)file_list[i]);
|
||
free(file_list);
|
||
} break;
|
||
default:
|
||
break;
|
||
}
|
||
menu_fini(&save_load_menu);
|
||
}
|
||
|
||
/*
|
||
* Start main emulation thread
|
||
*/
|
||
|
||
void C64::Run(void)
|
||
{
|
||
// Reset chips
|
||
TheCPU->Reset();
|
||
TheSID->Reset();
|
||
TheCIA1->Reset();
|
||
TheCIA2->Reset();
|
||
TheCPU1541->Reset();
|
||
|
||
// Patch kernal IEC routines
|
||
orig_kernal_1d84 = Kernal[0x1d84];
|
||
orig_kernal_1d85 = Kernal[0x1d85];
|
||
PatchKernal(ThePrefs.FastReset, ThePrefs.Emul1541Proc);
|
||
|
||
quit_thyself = false;
|
||
thread_func();
|
||
}
|
||
|
||
extern "C" int get_kc_from_char(char c_in, int *shifted);
|
||
|
||
/*
|
||
* Vertical blank: Poll keyboard and joysticks, update window
|
||
*/
|
||
|
||
void C64::VBlank(bool draw_frame)
|
||
{
|
||
#if defined(GEKKO)
|
||
WPAD_ScanPads();
|
||
#endif
|
||
|
||
// Poll joysticks
|
||
TheCIA1->Joystick1 = poll_joystick(0);
|
||
TheCIA1->Joystick2 = poll_joystick(1);
|
||
|
||
// Poll keyboard
|
||
TheDisplay->PollKeyboard(TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &joykey);
|
||
if (TheDisplay->quit_requested)
|
||
quit_thyself = true;
|
||
|
||
/* From dreamcast port */
|
||
if (this->fake_key_sequence)
|
||
{
|
||
int shifted;
|
||
int kc = get_kc_from_char(this->fake_key_str[this->fake_key_index], &shifted);
|
||
|
||
TheDisplay->FakeKeyPress(kc, shifted, TheCIA1->KeyMatrix,
|
||
TheCIA1->RevMatrix);
|
||
|
||
this->fake_key_keytime --;
|
||
if (this->fake_key_keytime == 0)
|
||
{
|
||
this->fake_key_keytime = 1;
|
||
this->fake_key_index ++;
|
||
|
||
if (this->fake_key_str[this->fake_key_index] == '\0')
|
||
{
|
||
this->fake_key_sequence = false;
|
||
this->fake_key_index = 0;
|
||
this->fake_key_keytime = 5;
|
||
}
|
||
}
|
||
}
|
||
#ifndef GEKKO
|
||
// Joystick keyboard emulation
|
||
if (TheDisplay->NumLock())
|
||
TheCIA1->Joystick1 &= joykey;
|
||
else
|
||
TheCIA1->Joystick2 &= joykey;
|
||
#endif
|
||
|
||
// Count TOD clocks
|
||
TheCIA1->CountTOD();
|
||
TheCIA2->CountTOD();
|
||
|
||
// Update window if needed
|
||
if (draw_frame) {
|
||
TheDisplay->Update();
|
||
#if 0
|
||
// Calculate time between VBlanks, display speedometer
|
||
struct timeval tv;
|
||
gettimeofday(&tv, NULL);
|
||
if ((tv.tv_usec -= tv_start.tv_usec) < 0) {
|
||
tv.tv_usec += 1000000;
|
||
tv.tv_sec -= 1;
|
||
}
|
||
tv.tv_sec -= tv_start.tv_sec;
|
||
double elapsed_time = (double)tv.tv_sec * 1000000 + tv.tv_usec;
|
||
speed_index = 20000 / (elapsed_time + 1) * 100;
|
||
|
||
// Limit speed to 100% if desired
|
||
if ((speed_index > 100)) {
|
||
usleep((unsigned long)(20000 - elapsed_time));
|
||
speed_index = 100;
|
||
}
|
||
|
||
gettimeofday(&tv_start, NULL);
|
||
|
||
TheDisplay->Speedometer((int)speed_index);
|
||
#endif
|
||
}
|
||
if (this->have_a_break) {
|
||
int submenus[1];
|
||
int opt;
|
||
int old_swap = ThePrefs.JoystickSwap == true ? 1 : 0;
|
||
|
||
Prefs np = ThePrefs;
|
||
this->prefs_changed = false;
|
||
|
||
TheSID->PauseSound();
|
||
submenus[0] = old_swap;
|
||
opt = menu_select(real_screen, &this->main_menu, submenus);
|
||
|
||
switch(opt)
|
||
{
|
||
case 0: /* Load disc/tape */
|
||
this->run_fake_key_sequence(&np);
|
||
break;
|
||
case 1: /* Insert disc/tape */
|
||
this->select_disc(&np);
|
||
break;
|
||
case 2: /* Reset */
|
||
Reset();
|
||
break;
|
||
case 3: /* Bind keys to joystick */
|
||
this->bind_keys(&np);
|
||
break;
|
||
case 4: /* Other options */
|
||
this->other_options(&np);
|
||
break;
|
||
case 5: /* Swap joysticks */
|
||
break;
|
||
case 7: /* Save / load game */
|
||
this->save_load_state(&np);
|
||
break;
|
||
case 9: /* Quit */
|
||
quit_thyself = true;
|
||
break;
|
||
case -1:
|
||
default:
|
||
break;
|
||
}
|
||
if (submenus[0] == 0)
|
||
np.JoystickSwap = false;
|
||
else
|
||
np.JoystickSwap = true;
|
||
if (submenus[0] != old_swap)
|
||
this->prefs_changed = true;
|
||
|
||
if (this->prefs_changed)
|
||
{
|
||
this->NewPrefs(&np);
|
||
ThePrefs = np;
|
||
}
|
||
TheDisplay->FakeKeyPress(-1, false, TheCIA1->KeyMatrix,
|
||
TheCIA1->RevMatrix);
|
||
|
||
this->have_a_break = false;
|
||
if (this->quit_thyself)
|
||
ThePrefs.Save(PREFS_PATH);
|
||
}
|
||
/* From Acorn port */
|
||
static uint64_t lastFrame;
|
||
#if defined(GEKKO)
|
||
uint32_t now = ticks_to_millisecs(gettime());
|
||
#else
|
||
uint32_t now = SDL_GetTicks();
|
||
#endif
|
||
|
||
if ( (now - lastFrame) < ThePrefs.MsPerFrame) {
|
||
usleep( (ThePrefs.MsPerFrame - (now - lastFrame)) * 1000);
|
||
}
|
||
lastFrame = now;
|
||
}
|
||
|
||
/*
|
||
* The emulation's main loop
|
||
*/
|
||
|
||
void C64::thread_func(void)
|
||
{
|
||
int linecnt = 0;
|
||
|
||
#ifdef FRODO_SC
|
||
while (!quit_thyself) {
|
||
|
||
// The order of calls is important here
|
||
if (TheVIC->EmulateCycle())
|
||
TheSID->EmulateLine();
|
||
TheCIA1->CheckIRQs();
|
||
TheCIA2->CheckIRQs();
|
||
TheCIA1->EmulateCycle();
|
||
TheCIA2->EmulateCycle();
|
||
TheCPU->EmulateCycle();
|
||
|
||
if (ThePrefs.Emul1541Proc) {
|
||
TheCPU1541->CountVIATimers(1);
|
||
if (!TheCPU1541->Idle)
|
||
TheCPU1541->EmulateCycle();
|
||
}
|
||
CycleCounter++;
|
||
#else
|
||
while (!quit_thyself) {
|
||
|
||
// The order of calls is important here
|
||
int cycles = TheVIC->EmulateLine();
|
||
TheSID->EmulateLine();
|
||
#if !PRECISE_CIA_CYCLES
|
||
TheCIA1->EmulateLine(ThePrefs.CIACycles);
|
||
TheCIA2->EmulateLine(ThePrefs.CIACycles);
|
||
#endif
|
||
|
||
if (ThePrefs.Emul1541Proc) {
|
||
int cycles_1541 = ThePrefs.FloppyCycles;
|
||
TheCPU1541->CountVIATimers(cycles_1541);
|
||
|
||
if (!TheCPU1541->Idle) {
|
||
// 1541 processor active, alternately execute
|
||
// 6502 and 6510 instructions until both have
|
||
// used up their cycles
|
||
while (cycles >= 0 || cycles_1541 >= 0)
|
||
if (cycles > cycles_1541)
|
||
cycles -= TheCPU->EmulateLine(1);
|
||
else
|
||
cycles_1541 -= TheCPU1541->EmulateLine(1);
|
||
} else
|
||
TheCPU->EmulateLine(cycles);
|
||
} else
|
||
// 1541 processor disabled, only emulate 6510
|
||
TheCPU->EmulateLine(cycles);
|
||
#endif
|
||
linecnt++;
|
||
}
|
||
}
|