X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hexed%2Fpc_transfer.c;h=bcfb652a0a06947fb8ab1ca00dbccb59fb259130;hb=c6d1079a7b38a586ea977236d1075075d1e50d57;hp=9e2681a3f70d09ada1c39d04b6927f04e3261f81;hpb=272bd2ec7473ac1f7f29b27752f5402283306cce;p=megadrive.git diff --git a/hexed/pc_transfer.c b/hexed/pc_transfer.c index 9e2681a..bcfb652 100644 --- a/hexed/pc_transfer.c +++ b/hexed/pc_transfer.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "transfer.h" @@ -74,22 +75,28 @@ #define timediff(now, start) \ ((now.tv_sec - start.tv_sec) * 1000000 + now.tv_usec - start.tv_usec) -static void do_exit(const char *msg) +#define PBE2(p) ((*(p) << 8) | *(p+1)) +#define PBE3(p) ((*(p) << 16) | (*(p + 1) << 8) | *(p + 2)) +#define PBE4(p) ((*(p) << 24) | (*(p + 1) << 16) | (*(p + 2) << 8) | *(p + 3)) + +static void do_exit(const char *msg, const char *where) { /* switch TL back to high */ outb(0xe0, PORT_CONTROL); + if (where) + fprintf(stderr, "%s: ", where); if (msg) - printf("%s", msg); + fprintf(stderr, "%s", msg); exit(1); } static void inthandler(int u) { - do_exit("\n"); + do_exit("\n", NULL); } -static void wait_th_low(void) +static void wait_th_low(const char *where) { struct timeval start, now; @@ -98,11 +105,11 @@ static void wait_th_low(void) while (inb(PORT_STATUS) & 0x40) { gettimeofday(&now, NULL); if (timediff(now, start) > ACK_TIMEOUT) - do_exit("timeout waiting TH low\n"); + do_exit("timeout waiting TH low\n", where); } } -static void wait_th_high(void) +static void wait_th_high(const char *where) { struct timeval start, now; @@ -111,42 +118,68 @@ static void wait_th_high(void) while (!(inb(PORT_STATUS) & 0x40)) { gettimeofday(&now, NULL); if (timediff(now, start) > ACK_TIMEOUT) - do_exit("timeout waiting TH high\n"); + do_exit("timeout waiting TH high\n", where); } } +static void output_to_input(void) +{ + /* TL high, recv mode; also give time + * MD to see TL before we lower it in recv_byte */ + outb(0xe0, PORT_CONTROL); + usleep(4*10); /* must be at least 12+8+8 M68k cycles, 28/7.67M */ +} + +static void input_to_output(void) +{ + wait_th_low("input_to_output"); + outb(0xc0, PORT_CONTROL); /* TL high, out mode */ +} + static unsigned int recv_byte(void) { unsigned int byte; outb(0xe2, PORT_CONTROL); /* TL low */ - wait_th_low(); + wait_th_low("recv_byte"); byte = inb(PORT_DATA) & 0x0f; outb(0xe0, PORT_CONTROL); /* TL high */ - wait_th_high(); + wait_th_high("recv_byte"); byte |= inb(PORT_DATA) << 4; return byte; } +static void recv_bytes(unsigned char *b, size_t count) +{ + while (count-- > 0) + *b++ = recv_byte(); +} + static void send_byte(unsigned int byte) { - wait_th_low(); + wait_th_low("recv_bytes"); outb(byte & 0x0f, PORT_DATA); outb(0xc2, PORT_CONTROL); /* TL low */ - wait_th_high(); + wait_th_high("recv_bytes"); outb((byte >> 4) & 0x0f, PORT_DATA); outb(0xc0, PORT_CONTROL); /* TL high */ } +static void send_bytes(unsigned char *b, size_t count) +{ + while (count-- > 0) + send_byte(*b++); +} + static void send_cmd(unsigned int cmd) { send_byte(CMD_PREFIX); @@ -158,7 +191,10 @@ static void usage(const char *argv0) fprintf(stderr, "usage:\n%s [args]\n" "\tsend [size]\n" "\trecv \n" - "\tjump \n", argv0); + "\tjump \n" + "\tio {r{8,16,32} ,w{8,16,32} }*\n" + "\tloadstate \n" + "\trecvvram \n", argv0); exit(1); } @@ -176,9 +212,20 @@ static unsigned int atoi_or_die(const char *a) return i; } +static void checked_gzread(gzFile f, void *data, size_t size) +{ + unsigned int ret; + ret = gzread(f, data, size); + if (ret != size) { + fprintf(stderr, "gzread returned %d/%zu\n", ret, size); + exit(1); + } +} + int main(int argc, char *argv[]) { - unsigned int addr = 0, size = 0, i = 0; + unsigned int addr = 0, size = 0; + unsigned int count = 0, i = 0; int ret; unsigned char *data; FILE *file = NULL; @@ -243,6 +290,135 @@ int main(int argc, char *argv[]) addr = atoi_or_die(argv[2]); } + else if (strcmp(argv[1], "io") == 0) + { + unsigned int cmd = 0, value, iosize; + unsigned char *p = data; + + for (i = 2; i < argc; ) { + if (argv[i][0] == 'r') + cmd = IOSEQ_R8; + else if (argv[i][0] == 'w') + cmd = IOSEQ_W8; + else + usage(argv[0]); + + iosize = atoi_or_die(&argv[i][1]); + if (iosize == 32) + cmd += 2; + else if (iosize == 16) + cmd += 1; + else if (iosize != 8) + usage(argv[0]); + *p++ = cmd; + i++; + + addr = atoi_or_die(argv[i]); + *p++ = addr >> 16; + *p++ = addr >> 8; + *p++ = addr >> 0; + i++; + + if (cmd == IOSEQ_W8 || cmd == IOSEQ_W16 || cmd == IOSEQ_W32) { + value = atoi_or_die(argv[i]); + switch (iosize) { + case 32: + *p++ = value >> 24; + *p++ = value >> 16; + case 16: + *p++ = value >> 8; + case 8: + *p++ = value >> 0; + } + i++; + } + + count++; + } + } + else if (strcmp(argv[1], "loadstate") == 0) + { + unsigned char chunk; + char header[12]; + gzFile f; + int len; + + if (argc != 3) + usage(argv[0]); + + f = gzopen(argv[2], "rb"); + if (f == NULL) { + perror("gzopen"); + return 1; + } + + checked_gzread(f, header, sizeof(header)); + if (strncmp(header, "PicoSEXT", 8) != 0) { + fprintf(stderr, "bad header\n"); + return 1; + } + + while (!gzeof(file)) + { + ret = gzread(f, &chunk, 1); + if (ret == 0) + break; + checked_gzread(f, &len, 4); + //printf("%2d %x\n", chunk, len); + switch (chunk) { + case 3: // VRAM + checked_gzread(f, data, len); + size += len; + break; + case 5: // CRAM + checked_gzread(f, data + 0x10000, len); + size += len; + break; + case 6: // VSRAM + checked_gzread(f, data + 0x10080, len); + size += len; + break; + case 8: // video + checked_gzread(f, data + 0x10100, len); + data[size+0] &= ~1; // no display disable + data[size+1] |= 0x40; // no blanking + size += 0x20; + break; + default: + if (chunk > 64+8) { + fprintf(stderr, "bad chunk: %d\n", chunk); + return 1; + } + gzseek(f, len, SEEK_CUR); + break; + } + } + gzclose(f); + if (size != 0x10120) { + fprintf(stderr, "bad final size: %x\n", size); + return 1; + } + // unbyteswap *RAMs (stored byteswapped) + for (i = 0; i < 0x10100; i += 2) { + int tmp = data[i]; + data[i] = data[i + 1]; + data[i + 1] = tmp; + } + } + else if (strcmp(argv[1], "recvvram") == 0) + { + if (argc != 3) + usage(argv[0]); + + file = fopen(argv[2], "wb"); + if (file == NULL) { + fprintf(stderr, "can't open file: %s\n", argv[2]); + return 1; + } + + size = 0x10000; + memset(data, 0, size); + } else usage(argv[0]); @@ -256,18 +432,29 @@ int main(int argc, char *argv[]) printf("regs: %02x %02x %02x\n", inb(PORT_DATA), inb(PORT_STATUS), inb(PORT_CONTROL)); + + /* wait for start condition */ + if (!(inb(PORT_STATUS) & 0x40)) + printf("waiting for TH high..\n"); + while (!(inb(PORT_STATUS) & 0x40)) + usleep(10000); + outb(0xe8, PORT_CONTROL); /* TR low - request for transfer */ + /* wait for request ack */ if (inb(PORT_STATUS) & 0x40) printf("waiting for TH low..\n"); - while (inb(PORT_STATUS) & 0x40) - usleep(100000); + for (i = 10000; inb(PORT_STATUS) & 0x40; i += 100) { + if (i > 100000) + i = 100000; + usleep(i); + } outb(0xe0, PORT_CONTROL); if (strcmp(argv[1], "send") == 0) { - send_cmd(CMD_MD_SEND); + send_cmd(CMD_PC_SEND); send_byte((addr >> 16) & 0xff); send_byte((addr >> 8) & 0xff); send_byte((addr >> 0) & 0xff); @@ -288,14 +475,14 @@ int main(int argc, char *argv[]) } else if (strcmp(argv[1], "recv") == 0) { - send_cmd(CMD_MD_RECV); + send_cmd(CMD_PC_RECV); send_byte((addr >> 16) & 0xff); send_byte((addr >> 8) & 0xff); send_byte((addr >> 0) & 0xff); send_byte((size >> 16) & 0xff); send_byte((size >> 8) & 0xff); send_byte((size >> 0) & 0xff); - outb(0xe0, PORT_CONTROL); /* TL high, recv mode */ + output_to_input(); for (i = 0; i < size; i++) { @@ -317,12 +504,98 @@ int main(int argc, char *argv[]) send_byte((addr >> 8) & 0xff); send_byte((addr >> 0) & 0xff); } + else if (strcmp(argv[1], "io") == 0) + { + unsigned char *p = data; + unsigned char rdata[4]; + send_cmd(CMD_IOSEQ); + send_byte((count >> 8) & 0xff); + send_byte((count >> 0) & 0xff); + + for (; count > 0; count--) { + input_to_output(); + send_bytes(p, 4); /* cmd + addr */ + + switch (p[0]) { + case IOSEQ_R8: + output_to_input(); + recv_bytes(rdata, 1); + printf("r8 %06x %02x\n", PBE3(p + 1), rdata[0]); + p += 4; + break; + case IOSEQ_R16: + output_to_input(); + recv_bytes(rdata, 2); + printf("r16 %06x %04x\n", PBE3(p + 1), PBE2(rdata)); + p += 4; + break; + case IOSEQ_R32: + output_to_input(); + recv_bytes(rdata, 4); + printf("r32 %06x %08x\n", PBE3(p + 1), PBE4(rdata)); + p += 4; + break; + case IOSEQ_W8: + send_bytes(&p[4], 1); + printf("w8 %06x %02x\n", PBE3(p + 1), p[4]); + p += 5; + break; + case IOSEQ_W16: + send_bytes(&p[4], 2); + printf("w16 %06x %04x\n", PBE3(p + 1), PBE2(p + 4)); + p += 6; + break; + case IOSEQ_W32: + send_bytes(&p[4], 4); + printf("w32 %06x %08x\n", PBE3(p + 1), PBE4(p + 4)); + p += 8; + break; + default: + do_exit("error in ioseq data\n", NULL); + break; + } + } + } + else if (strcmp(argv[1], "loadstate") == 0) + { + send_cmd(CMD_LOADSTATE); - if (file != NULL) { + for (i = 0; i < size; i++) + { + if ((i & 0x1f) == 0) { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("%06x/%06x", i, size); + fflush(stdout); + } + + send_byte(data[i]); + } + } + else if (strcmp(argv[1], "recvvram") == 0) + { + send_cmd(CMD_VRAM_RECV); + output_to_input(); + + for (i = 0; i < size; i++) + { + if ((i & 0xff) == 0) { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("%06x/%06x", i, size); + fflush(stdout); + } + + data[i] = recv_byte(); + } + + fwrite(data, 1, size, file); + } + + if (size != 0) { printf("\b\b\b\b\b\b\b\b\b\b\b\b\b"); printf("%06x/%06x\n", i, size); - fclose(file); } + if (file != NULL) + fclose(file); /* switch TL back to high, disable outputs */ outb(0xe0, PORT_CONTROL);