From 4e6ba16d44cf7d8f4c84712c1dc59738f0a2048d Mon Sep 17 00:00:00 2001 From: notaz Date: Wed, 25 May 2011 01:59:16 +0300 Subject: [PATCH] hexed: support PicoDrive savestate loading (only VDP+VRAM for now) --- hexed/Makefile | 2 +- hexed/pc_transfer.c | 104 ++++++++++++++++++++++++++++++++++++++-- hexed/transfer.S | 114 ++++++++++++++++++++++++++++++++++++++++++++ hexed/transfer.h | 3 +- 4 files changed, 218 insertions(+), 5 deletions(-) diff --git a/hexed/Makefile b/hexed/Makefile index 894c439..55a0e05 100644 --- a/hexed/Makefile +++ b/hexed/Makefile @@ -23,7 +23,7 @@ clean: pc_transfer: pc_transfer.c - gcc -Wall -O2 -ggdb -o $@ $^ + gcc -Wall -O2 -ggdb -o $@ $^ -lz %.o: %.S $(CC) -c -o $@ $^ $(CPPFLAGS) diff --git a/hexed/pc_transfer.c b/hexed/pc_transfer.c index 569acfc..ef1f58b 100644 --- a/hexed/pc_transfer.c +++ b/hexed/pc_transfer.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "transfer.h" @@ -190,7 +191,9 @@ 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", 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); diff --git a/hexed/transfer.S b/hexed/transfer.S index 0115dd9..1ac2d62 100644 --- a/hexed/transfer.S +++ b/hexed/transfer.S @@ -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 diff --git a/hexed/transfer.h b/hexed/transfer.h index b5a9817..7db1e5e 100644 --- a/hexed/transfer.h +++ b/hexed/transfer.h @@ -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 -- 2.39.2