/* * 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 #include #include "gui/gui.hh" #include "gui/virtual_keyboard.hh" #if defined(GEKKO) #include #include #define SAVES_PATH "/apps/frodo/saves" #define IMAGE_PATH "/apps/frodo/images" #define TMP_PATH "/apps/frodo/tmp" #else #define SAVES_PATH "saves" #define IMAGE_PATH "images" #define TMP_PATH "tmp" #endif #define C64_NETWORK_BROKER "c64-network.game-host.org" /* TODO: */ extern char *fixme_tmp_network_server; static struct timeval tv_start; /* * 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->linecnt = 0; this->fake_key_sequence = false; this->fake_key_index = 0; this->fake_key_keytime = 4; 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"); strncpy(this->server_hostname, C64_NETWORK_BROKER, sizeof(this->server_hostname)); this->server_port = 46214; this->network_connection_type = NONE; this->peer = NULL; if (fixme_tmp_network_server) { printf("Connecting to %s\n", fixme_tmp_network_server); strcpy(this->server_hostname, fixme_tmp_network_server); this->peer = new Network(this->server_hostname, this->server_port); this->network_connection_type = CONNECT; } } void C64::c64_ctor2(void) { gettimeofday(&tv_start, NULL); } /* * Destructor, system-dependent things */ void C64::c64_dtor(void) { } void C64::pushKeyCode(int kc, bool up) { TheDisplay->UpdateKeyMatrix(kc, up, TheCIA1->KeyMatrix, TheCIA1->RevMatrix, NULL); } /* From dreamcast port but heavily modified */ void C64::run_fake_key_sequence() { int kc = Gui::gui->kbd->charToKeycode(this->fake_key_str[this->fake_key_index]); TheDisplay->FakeKeyPress(kc, TheCIA1->KeyMatrix, TheCIA1->RevMatrix); this->fake_key_keytime --; if (this->fake_key_keytime == 0) { this->fake_key_keytime = 4; this->fake_key_index ++; TheDisplay->FakeKeyPress(-1, TheCIA1->KeyMatrix, TheCIA1->RevMatrix); 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; } } } void C64::startFakeKeySequence(const char *str) { this->fake_key_str = str; this->fake_key_sequence = true; } /* * 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(); } void C64::network_vblank() { static uint32_t last_time_update; #if defined(GEKKO) Uint32 now = ticks_to_millisecs(gettime()); #else Uint32 now = SDL_GetTicks(); #endif if (this->peer) { Uint8 *master = this->TheDisplay->BitmapBase(); Network *remote = this->peer; uint8 *js; static bool has_throttled; if (this->quit_thyself) { if (this->network_connection_type != CONNECT) remote->Disconnect(); delete remote; this->peer = NULL; return; } remote->Tick( now - last_time_update ); if (this->network_connection_type == MASTER) { if (ThePrefs.JoystickSwap) js = &TheCIA1->Joystick1; else js = &TheCIA1->Joystick2; } else if (this->network_connection_type == CONNECT) { network_connection_error_t err = this->peer->ConnectFSM(); if (err == OK) { if (this->peer->is_master) this->network_connection_type = MASTER; else this->network_connection_type = CLIENT; this->linecnt = 0; } else if (err != AGAIN_ERROR) { if (err == VERSION_ERROR) { TheDisplay->display_status_string("YOUR FRODO IS TOO OLD, DOWNLOAD NEW AT HTTP://FRODO-WII.GOOGLECODE.COM", 5); } delete remote; this->peer = NULL; } return; } else { if (ThePrefs.JoystickSwap) js = &TheCIA1->Joystick2; else js = &TheCIA1->Joystick1; } /* Has the peer sent any data? */ if (remote->ReceiveUpdate() == true) { if (remote->DecodeUpdate(this->TheDisplay, js, this->TheSID) == false) { /* Disconnect or sending crap, remove this guy! */ TheDisplay->display_status_string("PEER DISCONNECTED", 3); delete remote; this->peer = NULL; if (this->network_connection_type == CLIENT) this->Reset(); this->network_connection_type = NONE; return; } if (this->network_connection_type == CLIENT) this->TheDisplay->Update(remote->GetScreen()); } /* Encode and send updates to the other side (what is determined by * if this is the master or not) */ if (this->network_connection_type == MASTER) { /* Skip this frame if the data rate is too high */ if (remote->ThrottleTraffic()) has_throttled = true; else { remote->EncodeDisplay(master, remote->GetScreen()); remote->FlushSound(); } } char *msg = TheDisplay->GetTextMessage(); if (msg) remote->EncodeTextMessage(msg); remote->EncodeJoystickUpdate(*js); if (remote->SendUpdate() == false) { /* Disconnect or broken data */ printf("Could not send update\n"); } remote->ResetNetworkUpdate(); static uint32_t last_traffic_update; if (last_time_update - last_traffic_update > 300) { TheDisplay->NetworkTrafficMeter(remote->GetKbps() / (8 * 1024.0), has_throttled); last_traffic_update = now; has_throttled = false; } } last_time_update = now; } /* * Vertical blank: Poll keyboard and joysticks, update window */ void C64::VBlank(bool draw_frame) { /* From Acorn port */ static uint32_t lastFrame; uint32_t now; uint8 j1, j2; // Poll joysticks j1 = poll_joystick(0); j2 = poll_joystick(1); // Poll keyboard TheDisplay->PollKeyboard(TheCIA1->KeyMatrix, TheCIA1->RevMatrix, &joykey); if (TheDisplay->quit_requested) quit_thyself = true; if (this->fake_key_sequence) this->run_fake_key_sequence(); /* Keyboard joystick input */ if (ThePrefs.JoystickSwap) j1 &= joykey; else j2 &= joykey; if (this->network_connection_type == MASTER) { /* Only poll one joystick for network servers */ if (ThePrefs.JoystickSwap) TheCIA1->Joystick2 = j2; else TheCIA1->Joystick1 = j2; } else if (this->network_connection_type == CLIENT) { Uint8 which = j2; /* Set both joysticks to the updated value */ if (j2 != 0xff) which = j2; TheCIA1->Joystick1 = which; TheCIA1->Joystick2 = which; } else { TheCIA1->Joystick1 = j1; TheCIA1->Joystick2 = j2; } // Count TOD clocks TheCIA1->CountTOD(); TheCIA2->CountTOD(); // Update window if needed if (draw_frame && this->network_connection_type != CLIENT) { TheDisplay->Update(); } if (this->have_a_break) { TheSID->PauseSound(); } this->network_vblank(); Gui::gui->runLogic(); #if defined(GEKKO) if (this->quit_thyself && Network::networking_started == true) SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); now = ticks_to_millisecs(gettime()); #else now = SDL_GetTicks(); #endif if (this->quit_thyself) ThePrefs.Save((const char*)PREFS_PATH); 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(); /* No need to emulate anything for the client */ if (this->network_connection_type != CLIENT) { 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++; } }