Mercurial > vba-clojure
view src/gba/remote.cpp @ 92:1ff2c546f5ad
added tick(), which allows one to step through each opcode of gameboy
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sun, 11 Mar 2012 19:07:31 -0500 |
parents | 8870086b716c |
children |
line wrap: on
line source
1 #include <cstdlib>2 #include <cstdio>3 #include <cstring>4 #include <config.h>6 #ifndef WIN327 # include <unistd.h>8 # include <sys/socket.h>9 # include <netdb.h>10 # ifdef HAVE_NETINET_IN_H11 # include <netinet/in.h>12 # endif // HAVE_NETINET_IN_H13 # ifdef HAVE_ARPA_INET_H14 # include <arpa/inet.h>15 # else // ! HAVE_ARPA_INET_H16 # define socklen_t int17 # endif // ! HAVE_ARPA_INET_H18 #else // WIN3219 # include "../win32/stdafx.h"20 # include <winsock.h>21 # include <io.h>22 # define socklen_t int23 # define close closesocket24 # define read _read25 # define write _write26 #endif // WIN3228 #include "GBA.h"29 #include "GBAGlobals.h"31 extern bool debugger;32 extern void CPUUpdateCPSR();33 #ifdef SDL34 extern void (*dbgMain)();35 extern void (*dbgSignal)(int, int);36 extern void debuggerMain();37 extern void debuggerSignal(int, int);38 #endif40 int remotePort = 55555;41 int remoteSignal = 5;42 int remoteSocket = -1;43 int remoteListenSocket = -1;44 bool remoteConnected = false;45 bool remoteResumed = false;47 int (*remoteSendFnc)(char *, int) = NULL;48 int (*remoteRecvFnc)(char *, int) = NULL;49 bool (*remoteInitFnc)() = NULL;50 void (*remoteCleanUpFnc)() = NULL;52 #if (defined WIN32 && !defined SDL)53 void remoteSetSockets(SOCKET l, SOCKET r)54 {55 remoteSocket = r;56 remoteListenSocket = l;57 }59 #endif61 int remoteTcpSend(char *data, int len)62 {63 return send(remoteSocket, data, len, 0);64 }66 int remoteTcpRecv(char *data, int len)67 {68 return recv(remoteSocket, data, len, 0);69 }71 bool remoteTcpInit()72 {73 if (remoteSocket == -1)74 {75 #ifdef WIN3276 WSADATA wsaData;77 int error = WSAStartup(MAKEWORD(1, 1), &wsaData);78 #endif // WIN3279 int s = socket(PF_INET, SOCK_STREAM, 0);81 remoteListenSocket = s;83 if (s < 0)84 {85 fprintf(stderr, "Error opening socket\n");86 exit(-1);87 }88 int tmp = 1;89 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof(tmp));91 // char hostname[256];92 // gethostname(hostname, 256);94 // hostent *ent = gethostbyname(hostname);95 // unsigned long a = *((unsigned long *)ent->h_addr);97 sockaddr_in addr;98 addr.sin_family = AF_INET;99 addr.sin_port = htons(remotePort);100 addr.sin_addr.s_addr = htonl(0);101 int count = 0;102 while (count < 3)103 {104 if (bind(s, (sockaddr *)&addr, sizeof(addr)))105 {106 addr.sin_port = htons(ntohs(addr.sin_port)+1);107 }108 else109 break;110 }111 if (count == 3)112 {113 fprintf(stderr, "Error binding \n");114 exit(-1);115 }117 fprintf(stderr, "Listening for a connection at port %d\n",118 ntohs(addr.sin_port));120 if (listen(s, 1))121 {122 fprintf(stderr, "Error listening\n");123 exit(-1);124 }125 socklen_t len = sizeof(addr);127 #ifdef WIN32128 int flag = 0;129 ioctlsocket(s, FIONBIO, (unsigned long *)&flag);130 #endif // WIN32131 int s2 = accept(s, (sockaddr *)&addr, &len);132 if (s2 > 0)133 {134 fprintf(stderr, "Got a connection from %s %d\n",135 inet_ntoa((in_addr)addr.sin_addr),136 ntohs(addr.sin_port));137 }138 else139 {140 #ifdef WIN32141 int error = WSAGetLastError();142 #endif // WIN32143 }144 char dummy;145 recv(s2, &dummy, 1, 0);146 if (dummy != '+')147 {148 fprintf(stderr, "ACK not received\n");149 exit(-1);150 }151 remoteSocket = s2;152 // close(s);153 }154 return true;155 }157 void remoteTcpCleanUp()158 {159 if (remoteSocket > 0)160 {161 fprintf(stderr, "Closing remote socket\n");162 close(remoteSocket);163 remoteSocket = -1;164 }165 if (remoteListenSocket > 0)166 {167 fprintf(stderr, "Closing listen socket\n");168 close(remoteListenSocket);169 remoteListenSocket = -1;170 }171 }173 int remotePipeSend(char *data, int len)174 {175 int res = write(1, data, len);176 return res;177 }179 int remotePipeRecv(char *data, int len)180 {181 int res = read(0, data, len);182 return res;183 }185 bool remotePipeInit()186 {187 char dummy;188 read(0, &dummy, 1);189 if (dummy != '+')190 {191 fprintf(stderr, "ACK not received\n");192 exit(-1);193 }195 return true;196 }198 void remotePipeCleanUp()199 {}201 void remoteSetPort(int port)202 {203 remotePort = port;204 }206 void remoteSetProtocol(int p)207 {208 if (p == 0)209 {210 remoteSendFnc = remoteTcpSend;211 remoteRecvFnc = remoteTcpRecv;212 remoteInitFnc = remoteTcpInit;213 remoteCleanUpFnc = remoteTcpCleanUp;214 }215 else216 {217 remoteSendFnc = remotePipeSend;218 remoteRecvFnc = remotePipeRecv;219 remoteInitFnc = remotePipeInit;220 remoteCleanUpFnc = remotePipeCleanUp;221 }222 }224 void remoteInit()225 {226 if (remoteInitFnc)227 remoteInitFnc();228 }230 void remotePutPacket(char *packet)231 {232 char *hex = "0123456789abcdef";233 char buffer[1024];235 int count = strlen(packet);237 unsigned char csum = 0;239 char *p = buffer;240 *p++ = '$';242 for (int i = 0; i < count; i++)243 {244 csum += packet[i];245 *p++ = packet[i];246 }247 *p++ = '#';248 *p++ = hex[csum>>4];249 *p++ = hex[csum & 15];250 *p++ = 0;251 // printf("Sending %s\n", buffer);252 remoteSendFnc(buffer, count + 4);254 char c = 0;255 remoteRecvFnc(&c, 1);256 /*257 if(c == '+')258 printf("ACK\n");259 else if(c=='-')260 printf("NACK\n");261 */262 }264 void remoteOutput(char *s, u32 addr)265 {266 char buffer[16384];268 char *d = buffer;269 *d++ = 'O';271 if (s)272 {273 char c = *s++;274 while (c)275 {276 sprintf(d, "%02x", c);277 d += 2;278 c = *s++;279 }280 }281 else282 {283 char c = debuggerReadByte(addr);284 addr++;285 while (c)286 {287 sprintf(d, "%02x", c);288 d += 2;289 c = debuggerReadByte(addr);290 addr++;291 }292 }293 remotePutPacket(buffer);294 // fprintf(stderr, "Output sent %s\n", buffer);295 }297 void remoteSendSignal()298 {299 char buffer[1024];300 sprintf(buffer, "S%02x", remoteSignal);301 remotePutPacket(buffer);302 }304 void remoteSendStatus()305 {306 char buffer[1024];307 sprintf(buffer, "T%02x", remoteSignal);308 char *s = buffer;309 s += 3;310 for (int i = 0; i < 15; i++)311 {312 u32 v = reg[i].I;313 sprintf(s, "%02x:%02x%02x%02x%02x;", i,314 (v & 255),315 (v >> 8) & 255,316 (v >> 16) & 255,317 (v >> 24) & 255);318 s += 12;319 }320 u32 v = armNextPC;321 sprintf(s, "0f:%02x%02x%02x%02x;", (v & 255),322 (v >> 8) & 255,323 (v >> 16) & 255,324 (v >> 24) & 255);325 s += 12;326 CPUUpdateCPSR();327 v = reg[16].I;328 sprintf(s, "19:%02x%02x%02x%02x;", (v & 255),329 (v >> 8) & 255,330 (v >> 16) & 255,331 (v >> 24) & 255);332 s += 12;333 *s = 0;334 // printf("Sending %s\n", buffer);335 remotePutPacket(buffer);336 }338 void remoteBinaryWrite(char *p)339 {340 u32 address;341 int count;342 sscanf(p, "%x,%x:", &address, &count);343 // printf("Binary write for %08x %d\n", address, count);345 p = strchr(p, ':');346 p++;347 for (int i = 0; i < count; i++)348 {349 u8 b = *p++;350 switch (b)351 {352 case 0x7d:353 b = *p++;354 debuggerWriteByte(address, (b^0x20));355 address++;356 break;357 default:358 debuggerWriteByte(address, b);359 address++;360 break;361 }362 }363 // printf("ROM is %08x\n", debuggerReadMemory(0x8000254));364 remotePutPacket("OK");365 }367 void remoteMemoryWrite(char *p)368 {369 u32 address;370 int count;371 sscanf(p, "%x,%x:", &address, &count);372 // printf("Memory write for %08x %d\n", address, count);374 p = strchr(p, ':');375 p++;376 for (int i = 0; i < count; i++)377 {378 u8 v = 0;379 char c = *p++;380 if (c <= '9')381 v = (c - '0') << 4;382 else383 v = (c + 10 - 'a') << 4;384 c = *p++;385 if (c <= '9')386 v += (c - '0');387 else388 v += (c + 10 - 'a');389 debuggerWriteByte(address, v);390 address++;391 }392 // printf("ROM is %08x\n", debuggerReadMemory(0x8000254));393 remotePutPacket("OK");394 }396 void remoteMemoryRead(char *p)397 {398 u32 address;399 int count;400 sscanf(p, "%x,%x:", &address, &count);401 // printf("Memory read for %08x %d\n", address, count);403 char buffer[1024];405 char *s = buffer;406 for (int i = 0; i < count; i++)407 {408 u8 b = debuggerReadByte(address);409 sprintf(s, "%02x", b);410 address++;411 s += 2;412 }413 *s = 0;414 remotePutPacket(buffer);415 }417 void remoteStepOverRange(char *p)418 {419 u32 address;420 u32 final;421 sscanf(p, "%x,%x", &address, &final);423 remotePutPacket("OK");425 remoteResumed = true;426 do427 {428 CPULoop(1);429 if (debugger)430 break;431 }432 while (armNextPC >= address && armNextPC < final);434 remoteResumed = false;436 remoteSendStatus();437 }439 void remoteWriteWatch(char *p, bool active)440 {441 u32 address;442 int count;443 sscanf(p, ",%x,%x#", &address, &count);445 fprintf(stderr, "Write watch for %08x %d\n", address, count);447 if (address < 0x2000000 || address > 0x3007fff)448 {449 remotePutPacket("E01");450 return;451 }453 if (address > 0x203ffff && address < 0x3000000)454 {455 remotePutPacket("E01");456 return;457 }459 u32 final = address + count;461 if (address < 0x2040000 && final > 0x2040000)462 {463 remotePutPacket("E01");464 return;465 }466 else if (address < 0x3008000 && final > 0x3008000)467 {468 remotePutPacket("E01");469 return;470 }472 for (int i = 0; i < count; i++)473 {474 if ((address >> 24) == 2)475 freezeWorkRAM[address & 0x3ffff] = active;476 else477 freezeInternalRAM[address & 0x7fff] = active;478 address++;479 }481 remotePutPacket("OK");482 }484 void remoteReadRegisters(char *p)485 {486 char buffer[1024];488 char *s = buffer;489 int i;490 // regular registers491 for (i = 0; i < 15; i++)492 {493 u32 v = reg[i].I;494 sprintf(s, "%02x%02x%02x%02x", v & 255, (v >> 8) & 255,495 (v >> 16) & 255, (v >> 24) & 255);496 s += 8;497 }498 // PC499 u32 pc = armNextPC;500 sprintf(s, "%02x%02x%02x%02x", pc & 255, (pc >> 8) & 255,501 (pc >> 16) & 255, (pc >> 24) & 255);502 s += 8;504 // floating point registers (24-bit)505 for (i = 0; i < 8; i++)506 {507 sprintf(s, "000000000000000000000000");508 s += 24;509 }511 // FP status register512 sprintf(s, "00000000");513 s += 8;514 // CPSR515 CPUUpdateCPSR();516 u32 v = reg[16].I;517 sprintf(s, "%02x%02x%02x%02x", v & 255, (v >> 8) & 255,518 (v >> 16) & 255, (v >> 24) & 255);519 s += 8;520 *s = 0;521 remotePutPacket(buffer);522 }524 void remoteWriteRegister(char *p)525 {526 int r;528 sscanf(p, "%x=", &r);530 p = strchr(p, '=');531 p++;533 char c = *p++;535 u32 v = 0;537 u8 data[4] = {0, 0, 0, 0};539 int i = 0;541 while (c != '#')542 {543 u8 b = 0;544 if (c <= '9')545 b = (c - '0') << 4;546 else547 b = (c + 10 - 'a') << 4;548 c = *p++;549 if (c <= '9')550 b += (c - '0');551 else552 b += (c + 10 - 'a');553 data[i++] = b;554 c = *p++;555 }557 v = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);559 // printf("Write register %d=%08x\n", r, v);560 reg[r].I = v;561 if (r == 15)562 {563 armNextPC = v;564 if (armState)565 reg[15].I = v + 4;566 else567 reg[15].I = v + 2;568 }569 remotePutPacket("OK");570 }572 void remoteStubMain()573 {574 if (!debugger)575 return;577 if (remoteResumed)578 {579 remoteSendStatus();580 remoteResumed = false;581 }583 while (true)584 {585 char buffer[1024];586 int res = remoteRecvFnc(buffer, 1024);588 if (res == -1)589 {590 fprintf(stderr, "GDB connection lost\n");591 #ifdef SDL592 dbgMain = debuggerMain;593 dbgSignal = debuggerSignal;594 #endif595 debugger = false;596 break;597 }599 // fprintf(stderr, "Received %s\n", buffer);600 char *p = buffer;601 char c = *p++;602 char pp = '+';603 remoteSendFnc(&pp, 1);605 if (c != '$')606 continue;607 c = *p++;608 switch (c)609 {610 case '?':611 remoteSendSignal();612 break;613 case 'D':614 remotePutPacket("OK");615 #ifdef SDL616 dbgMain = debuggerMain;617 dbgSignal = debuggerSignal;618 #endif619 remoteResumed = true;620 debugger = false;621 return;622 case 'e':623 remoteStepOverRange(p);624 break;625 case 'k':626 remotePutPacket("OK");627 #ifdef SDL628 dbgMain = debuggerMain;629 dbgSignal = debuggerSignal;630 #endif631 debugger = false;632 emulating = false;633 return;634 case 'C':635 remoteResumed = true;636 debugger = false;637 return;638 case 'c':639 remoteResumed = true;640 debugger = false;641 return;642 case 's':643 remoteResumed = true;644 remoteSignal = 5;645 CPULoop(1);646 if (remoteResumed)647 {648 remoteResumed = false;649 remoteSendStatus();650 }651 break;652 case 'g':653 remoteReadRegisters(p);654 break;655 case 'P':656 remoteWriteRegister(p);657 break;658 case 'M':659 remoteMemoryWrite(p);660 break;661 case 'm':662 remoteMemoryRead(p);663 break;664 case 'X':665 remoteBinaryWrite(p);666 break;667 case 'H':668 remotePutPacket("OK");669 break;670 case 'q':671 remotePutPacket("");672 break;673 case 'Z':674 if (*p++ == '2')675 {676 remoteWriteWatch(p, true);677 }678 else679 remotePutPacket("");680 break;681 case 'z':682 if (*p++ == '2')683 {684 remoteWriteWatch(p, false);685 }686 else687 remotePutPacket("");688 break;689 default:690 {691 *(strchr(p, '#') + 3) = 0;692 fprintf(stderr, "Unknown packet %s\n", --p);693 remotePutPacket("");694 break;695 }696 }697 }698 }700 void remoteStubSignal(int sig, int number)701 {702 remoteSignal = sig;703 remoteResumed = false;704 remoteSendStatus();705 debugger = true;706 }708 void remoteCleanUp()709 {710 if (remoteCleanUpFnc)711 remoteCleanUpFnc();712 }