/* * 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/status_bar.hh" #include "gui/virtual_keyboard.hh" #if defined(GEKKO) #include #include #endif #define C64_NETWORK_BROKER "c64-network.game-host.org" /* TODO: */ extern char *network_server_connect; 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->network = NULL; if (network_server_connect) { printf("Connecting to %s\n", network_server_connect); strcpy(this->server_hostname, network_server_connect); this->network = 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->network) { Uint8 *master = this->TheDisplay->BitmapBase(); Network *remote = this->network; uint8 *js; static bool has_throttled; if (this->quit_thyself) { remote->Disconnect(); delete remote; this->network = NULL; TheC64->network_connection_type = NONE; return; } remote->Tick( now - last_time_update ); if (this->network_connection_type == MASTER) { if (ThePrefs.JoystickSwap) js = &TheCIA1->Joystick2; else js = &TheCIA1->Joystick1; } else { /* Both are the same */ js = &TheCIA1->Joystick2; } remote->ResetNetworkUpdate(); /* 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! */ Gui::gui->status_bar->queueMessage("Peer disconnected"); delete remote; this->network = 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()); } const char *msg = TheDisplay->GetTextMessage(); if (msg && strlen(msg) > 0) remote->EncodeTextMessage(msg, TheDisplay->text_message_broadcast); free((void *)msg); if (this->network_connection_type == CONNECT) return; /* 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(); } } remote->EncodeJoystickUpdate(*js); if (remote->SendPeerUpdate() == false) { /* Disconnect or broken data */ printf("Could not send update\n"); } 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; int joy_port_1 = 0; if (ThePrefs.JoystickSwap) joy_port_1 = 1; SDL_JoystickUpdate(); // Poll joysticks j1 = poll_joystick(!joy_port_1); j2 = poll_joystick(joy_port_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 == CLIENT) { Uint8 which = j2; if (ThePrefs.JoystickSwap) which = j1; TheCIA1->Joystick1 = which; TheCIA1->Joystick2 = which; } else if (this->network_connection_type == MASTER) { /* The other comes from the network */ if (ThePrefs.JoystickSwap) TheCIA1->Joystick1 = j1; else TheCIA1->Joystick2 = j2; } 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(); } this->network_vblank(); Gui::gui->runLogic(); //if (this->quit_thyself) // ThePrefs.Save(ThePrefs.PrefsPath); #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 ( (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->have_a_break && 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++; } }