hexed: support PicoDrive savestate loading (only VDP+VRAM for now)
authornotaz <notasas@gmail.com>
Tue, 24 May 2011 22:59:16 +0000 (01:59 +0300)
committernotaz <notasas@gmail.com>
Tue, 24 May 2011 22:59:16 +0000 (01:59 +0300)
hexed/Makefile
hexed/pc_transfer.c
hexed/transfer.S
hexed/transfer.h

index 894c439..55a0e05 100644 (file)
@@ -23,7 +23,7 @@ clean:
 \r
 \r
 pc_transfer: pc_transfer.c\r
-       gcc -Wall -O2 -ggdb -o $@ $^\r
+       gcc -Wall -O2 -ggdb -o $@ $^ -lz\r
 \r
 %.o: %.S\r
        $(CC) -c -o $@ $^ $(CPPFLAGS)\r
index 569acfc..ef1f58b 100644 (file)
@@ -31,6 +31,7 @@
 #include <sys/io.h>
 #include <signal.h>
 #include <sys/time.h>
+#include <zlib.h>
 
 #include "transfer.h"
 
@@ -190,7 +191,9 @@ static void usage(const char *argv0)
        fprintf(stderr, "usage:\n%s <cmd> [args]\n"
                "\tsend <file> <addr> [size]\n"
                "\trecv <file> <addr> <size>\n"
-               "\tjump <addr>\n", argv0);
+               "\tjump <addr>\n"
+               "\tio {r{8,16,32} <addr>,w{8,16,32} <addr> <data>}*\n"
+               "\tloadstate <picodrive_savestate>\n", argv0);
        exit(1);
 }
 
@@ -208,6 +211,16 @@ 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;
@@ -322,6 +335,75 @@ int main(int argc, char *argv[])
                        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
                usage(argv[0]);
 
@@ -448,12 +530,28 @@ int main(int argc, char *argv[])
                        }
                }
        }
+       else if (strcmp(argv[1], "loadstate") == 0)
+       {
+               send_cmd(CMD_LOADSTATE);
+
+               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]);
+               }
+       }
 
-       if (file != NULL) {
+       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);
index 0115dd9..1ac2d62 100644 (file)
@@ -92,6 +92,18 @@ recv_byte:
        recv_one_byte 1
        rts
 
+# receive 1 16bit word to d0
+#  in: a1 - data port
+#  trash: d1,d2
+recv_word:
+       recv_one_byte
+       move.b          d0,d2
+       recv_one_byte
+       lsl.w           #8,d2
+       move.b          d0,d2
+       move.w          d2,d0
+       rts
+
 # receive address/size to d0 (3 bytes BE)
 #  in: a1 - data port
 #  trash: d1,d2
@@ -112,6 +124,41 @@ send_byte:
        send_one_byte
        rts
 
+.equ sat_maxsize, (80*8+0x200) /* sprites+max_align */
+
+# make sure cache is invalidated
+# note: VRAM copy doesn't seem to help here
+# note2: cache is updated as data is written
+#  in: d0 - vdp reg5, a0 = 0xc00000
+#  trash: d1,d2,a2
+invalidate_sprite_cache:
+       move.w          #0x8f02,4(a0)           /* auto increment 2 */
+       lsl.b           #1,d0                   /* upper byte of sat address */
+       move.b          d0,d1
+       lsr.b           #6,d1                   /* 15:14 dst addr */
+       and.b           #0x3f,d0                /* assemble cmd */
+       lsl.w           #8,d0
+       swap            d0
+       move.b          d1,d0
+       move.l          d0,4(a0)
+
+       move.l          #0xffe000,a2
+       move.l          #sat_maxsize/2-1,d2
+0:
+       move.w          (a0),(a2)+
+       dbra            d2,0b
+
+       bset            #30,d0                  /* VRAM write */
+       move.l          d0,4(a0)
+
+       move.l          #0xffe000,a2
+       move.l          #sat_maxsize/2-1,d2
+0:
+       move.w          (a2)+,(a0)
+       dbra            d2,0b
+       rts
+
+
 
 do_transfer:
        lea             0xa10005,a1
@@ -137,6 +184,7 @@ jumptab:
        bra             pcc_transfer_send       /* recv from us */
        bra             pcc_jump
        bra             pcc_io
+       bra             pcc_loadstate
        bra             pcc_test_code
 
 
@@ -290,6 +338,72 @@ pcc_io_r32:
        bra             pcc_io_loop
 
 
+/* PicoDrive savestate load */
+pcc_loadstate:
+       /* write VRAM */
+       move.l          #0xc00000,a0
+       move.w          #0x8f02,4(a0)           /* auto increment 2 */
+
+       move.l          #0x40000000,4(a0)
+       move.l          #0x10000/2-1,d3
+tr_do_vram_loop:
+       bsr             recv_word
+       move.w          d0,(a0)
+       dbra            d3, tr_do_vram_loop
+
+       /* write cram */
+       move.l          #0xc0000000,4(a0)
+       move.l          #0x80/2-1,d3
+tr_do_cram_loop:
+       bsr             recv_word
+       move.w          d0,(a0)
+       dbra            d3, tr_do_cram_loop
+
+       /* write vsram */
+       move.l          #0x40000010,4(a0)
+       move.l          #0x80/2-1,d3
+tr_do_vsram_loop:
+       bsr             recv_word
+       move.w          d0,(a0)
+       dbra            d3, tr_do_vsram_loop
+
+       /* recv and write regs */
+       lea             0xffe000,a3
+       move.l          a3,a2
+       moveq.l         #0x20-1,d3
+tr_do_vdpreg_recv_loop:
+       bsr             recv_byte
+       move.b          d0,(a2)+
+       dbra            d3, tr_do_vdpreg_recv_loop
+
+       move.l          a3,a2
+       moveq.l         #0,d3
+tr_do_vdpreg_loop:
+       move.b          d3,d1
+       or.b            #0x80,d1
+       lsl.w           #8,d1
+       move.b          (d3,a2),d1
+       move.w          d1,4(a0)
+       addq.l          #1,d3
+       cmp.b           #0x17,d3        /* FIXME: r23 might cause DMA or.. */
+       bne             0f              /* ..something and hang VDP.. */
+       add.b           #1,d3           /* ..so we skip it */
+0:
+       cmp.b           #0x20,d3
+       blt             tr_do_vdpreg_loop
+
+       moveq.l         #0,d0
+       move.b          5(a3),d0
+       bsr             invalidate_sprite_cache
+
+
+0:     bra             0b
+
+       bra             return
+
+
+
+
 /* some random code */
 pcc_test_code:
        bra             return
index b5a9817..7db1e5e 100644 (file)
@@ -5,7 +5,8 @@
 #define CMD_MD_RECV    0xc2    /* recv from MD: addr[3], len[3], data[] */
 #define CMD_JUMP       0xc3    /* jump to addr: addr[3] */
 #define CMD_IOSEQ      0xc4    /* perform i/o ops: count[2], [type[1], addr[3], data[{0,1,2,4}]]* */
-#define CMD_TEST       0xc5    /* test code */
+#define CMD_LOADSTATE  0xc5    /* load PD state: vram[64k], cram[128], vsram[128], vdp[32] */
+#define CMD_TEST       0xc6    /* test code */
 
 #define CMD_FIRST      CMD_MD_SEND
 #define CMD_LAST       CMD_TEST