#include <sys/io.h>
#include <signal.h>
#include <sys/time.h>
+#include <zlib.h>
#include "transfer.h"
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);
}
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;
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]);
}
}
}
+ 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);
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
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
bra pcc_transfer_send /* recv from us */
bra pcc_jump
bra pcc_io
+ bra pcc_loadstate
bra pcc_test_code
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
#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