#include #include #include #include #include #include #include #include #include #include #include #define BUFLEN 8096 #define MAX_STEP_CYCLES 20000 int sleep_nanos(long int ns) { struct timespec time; time.tv_sec = ns / 1000000000; time.tv_nsec = ns % 1000000000; return nanosleep(&time, NULL); } int server(int connfd, VB *sim) { RdbRequest req; RdbResponse res; char reqbuf[BUFLEN]; char resbuf[BUFLEN]; bool running; rdb_read_result_t read_result; int result; rdb_request_init(&req, connfd, reqbuf, BUFLEN); rdb_response_init(&res, connfd, resbuf, BUFLEN); running = false; while (1) { CommandBuf cmd; int brk; uint32_t cycles; read_result = rdb_request_read(&req, &cmd); if (read_result == read_result_error) { return -1; } else if (read_result == read_result_disconnected) { printf("client has disconnected\n"); return 0; } else if (read_result == read_result_pending) { if (running) { cycles = MAX_STEP_CYCLES; brk = vbEmulate(sim, &cycles); if (brk) { /* We hit a breakpoint */ if (brk == -1) { /* actually, not implemented */ running = false; rdb_response_begin_packet(&res); rdb_response_write_str(&res, "T05:thread:p1.t1;threads:p1.t1;"); result = rdb_response_send_packet(&res); if (result != 0) { return result; } } else { fprintf(stderr, "surprising response %d from vbEmulate\n", brk); return -1; } } else { sleep_nanos((MAX_STEP_CYCLES - cycles) * 50); } } continue; } else { printf("received command \"%.*s\"\n", (int) cmd.len, cmd.buf); fflush(stdout); result = handle_command(&res, &cmd, sim, &running); if (result != 0) { return result; } rdb_request_set_blocking(&req, !running); rdb_request_reset(&req); } } } int readROM(VB *sim, char *filename) { FILE *file = fopen(filename, "rb"); uint8_t *rom; long size; if (!file) { perror("could not open file"); return 1; } if (fseek(file, 0, SEEK_END)) { perror("could not seek file end"); return 1; } size = ftell(file); if (size == -1) { perror("could not read file size"); return 1; } if (fseek(file, 0, SEEK_SET)) { perror("could not seek file start"); return 1; } rom = malloc(size); if (!rom) { perror("could not allocate ROM"); return 1; } fread(rom, 1, size, file); if (ferror(file)) { perror("could not read file"); return 1; } if (fclose(file)) { perror("could not close file"); return 1; } vbSetCartROM(sim, rom, size); return 0; } int main(int argc, char** argv) { VB *sim; short port; int fd, connfd; struct sockaddr_in addr, cliaddr; socklen_t cliaddrlen; int response; if (argc < 2) { fprintf(stderr, "Please pass a ROM file\n"); return 1; } sim = malloc(vbSizeOf()); if (!sim) { return 1; } vbInit(sim); if (readROM(sim, argv[1])) { return 1; } /* relevant state at the start of the physics sim's main */ /* vbSetProgramCounter(sim, 0x070002ba); vbSetProgramRegister(sim, 3, 0x0500ffc0); vbSetProgramRegister(sim, 4, 0x05008000); */ if (argc > 2) { char *end; port = (short) strtol(argv[2], &end, 10); if (argv[2] == end) { perror("could not parse port"); return 1; } } else { port = 8080; } fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { perror("could not open socket"); return 1; } memset(&addr, 0, sizeof(addr)); addr.sin_addr.s_addr = INADDR_ANY; addr.sin_family = AF_INET; addr.sin_port = htons(port); if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) { perror("could not bind socket"); return 1; } if (listen(fd, 1) == -1) { perror("could not listen on socket"); return 1; } printf("connecting\n"); cliaddrlen = sizeof(cliaddr); connfd = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen); if (connfd == -1) { perror("could not accept connection"); return 1; } printf("connected\n"); response = server(connfd, sim); return close(connfd) || close(fd) || response; }