From 93c5aa8a4e294c0736b3ddd02b57b3b4f353e539 Mon Sep 17 00:00:00 2001
From: notaz <notasas@gmail.com>
Date: Fri, 20 May 2011 14:41:28 +0300
Subject: [PATCH] hexed: add simple io commands

seems to have some race condition/timing issues..
---
 hexed/pc_transfer.c | 157 ++++++++++++++++++++++++++++++++++++++++----
 hexed/transfer.S    | 119 ++++++++++++++++++++++++++++++++-
 hexed/transfer.h    |  12 +++-
 3 files changed, 272 insertions(+), 16 deletions(-)

diff --git a/hexed/pc_transfer.c b/hexed/pc_transfer.c
index 9e2681a..569acfc 100644
--- a/hexed/pc_transfer.c
+++ b/hexed/pc_transfer.c
@@ -74,22 +74,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 +104,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 +117,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);
@@ -178,7 +210,8 @@ static unsigned int atoi_or_die(const char *a)
 
 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 +276,52 @@ 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
 		usage(argv[0]);
 
@@ -295,7 +374,7 @@ int main(int argc, char *argv[])
 		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,6 +396,58 @@ 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;
+			}
+		}
+	}
 
 	if (file != NULL) {
 		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
diff --git a/hexed/transfer.S b/hexed/transfer.S
index 4ab3aff..0115dd9 100644
--- a/hexed/transfer.S
+++ b/hexed/transfer.S
@@ -108,6 +108,10 @@ recv_ad:
 	move.l		d2,d0
 	rts
 
+send_byte:
+	send_one_byte
+	rts
+
 
 do_transfer:
 	lea		0xa10005,a1
@@ -132,9 +136,11 @@ jumptab:
 	bra		pcc_transfer_recv	/* sent to us */
 	bra		pcc_transfer_send	/* recv from us */
 	bra		pcc_jump
+	bra		pcc_io
 	bra		pcc_test_code
 
 
+/* receive data from PC */
 pcc_transfer_recv:
 	bsr		recv_ad
 	move.l		d0,a0
@@ -149,13 +155,14 @@ tr_recv_loop:
 	bra		return
 
 
+/* send data to PC */
 pcc_transfer_send:
 	bsr		recv_ad
 	move.l		d0,a0
 	bsr		recv_ad
 	move.l		d0,d3
 
-0: /*Lwait_tl_low:*/
+0: /*Lwait_tl_low: it should switch to rx mode before lowering tl */
 	move.b		(a1),d0
 	btst.b		#4,d0
 	bne		0b /*Lwait_tl_low*/
@@ -171,16 +178,124 @@ tr_send_loop:
 	bra		return
 
 
+/* call specified location */
 pcc_jump:
 	bsr		recv_ad
 	move.l		d0,a0
-	jmp		(a0)
+	jsr		(a0)
+	bra		return
+
+
+/* do simple i/o commands */
+pcc_io:
+	moveq.l		#0,d4
+	bsr		recv_byte
+	move.b		d0,d4
+	bsr		recv_byte
+	lsl.l		#8,d4
+	move.b		d0,d4
 
+pcc_io_loop:
+	move.b		#0x40,(0xa1000b).l	/* input mode */
 
+	sub.w		#1,d4
+	bmi		return
+
+	bsr		recv_byte
+	move.b		d0,d3			/* cmd */
+
+	bsr		recv_ad
+	move.l		d0,a2			/* addr */
+
+	cmp.b		#IOSEQ_W32, d3
+	beq		pcc_io_w32
+	cmp.b		#IOSEQ_W16, d3
+	beq		pcc_io_w16
+	cmp.b		#IOSEQ_W8, d3
+	bne		pcc_io_rx
+
+pcc_io_w8:
+	bsr		recv_byte
+	move.b		d0,(a2)
+	bra		pcc_io_loop
+
+pcc_io_w16:
+	bsr		recv_byte
+	move.b		d0,d3
+	bsr		recv_byte
+	lsl.w		#8,d3
+	move.b		d0,d3
+	move.w		d3,(a2)
+	bra		pcc_io_loop
+
+pcc_io_w32:
+	bsr		recv_byte
+	move.b		d0,d3
+	bsr		recv_byte
+	lsl.w		#8,d3
+	move.b		d0,d3
+	bsr		recv_byte
+	lsl.l		#8,d3
+	move.b		d0,d3
+	bsr		recv_byte
+	lsl.l		#8,d3
+	move.b		d0,d3
+	move.l		d3,(a2)
+	bra		pcc_io_loop
+
+pcc_io_rx:
+0: /*Lwait_tl_low:*/
+	move.b		(a1),d0
+	btst.b		#4,d0
+	bne		0b /*Lwait_tl_low*/
+
+	move.b		#0x4f,(0xa1000b).l
+	move.b		#0x40,(a1)
+
+	cmp.b		#IOSEQ_R32, d3
+	beq		pcc_io_r32
+	cmp.b		#IOSEQ_R16, d3
+	beq		pcc_io_r16
+	cmp.b		#IOSEQ_R8, d3
+	bne		return
+
+pcc_io_r8:
+	move.b		(a2),d0
+	bsr		send_byte
+	bra		pcc_io_loop
+
+pcc_io_r16:
+	move.w		(a2),d3
+	move.w		d3,d0
+	lsr.w		#8,d0
+	bsr		send_byte
+	move.b		d3,d0
+	bsr		send_byte
+	bra		pcc_io_loop
+
+pcc_io_r32:
+	move.l		(a2),d3
+	move.l		d3,d0
+	swap		d0
+	lsr.l		#8,d0
+	bsr		send_byte
+	move.l		d3,d0
+	swap		d0
+	bsr		send_byte
+	move.w		d3,d0
+	lsr.w		#8,d0
+	bsr		send_byte
+	move.b		d3,d0
+	bsr		send_byte
+	bra		pcc_io_loop
+
+
+/* some random code */
 pcc_test_code:
 	bra		return
 
 
+
 return:
 	move.b		#0,(0xa1000b).l	/* all inputs */
 	move.l		#0xffe000,a1
diff --git a/hexed/transfer.h b/hexed/transfer.h
index b1aa7cd..b5a9817 100644
--- a/hexed/transfer.h
+++ b/hexed/transfer.h
@@ -1,8 +1,18 @@
+/* all data is big endian */
+
 #define CMD_PREFIX	0x5a
 #define CMD_MD_SEND	0xc1	/* send to MD:   addr[3], len[3], data[] */
 #define CMD_MD_RECV	0xc2	/* recv from MD: addr[3], len[3], data[] */
 #define CMD_JUMP	0xc3	/* jump to addr: addr[3] */
-#define CMD_TEST	0xc4	/* test code */
+#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_FIRST	CMD_MD_SEND
 #define CMD_LAST	CMD_TEST
+
+#define IOSEQ_R8	0xb0
+#define IOSEQ_R16	0xb1
+#define IOSEQ_R32	0xb2
+#define IOSEQ_W8	0xb3
+#define IOSEQ_W16	0xb4
+#define IOSEQ_W32	0xb5
-- 
2.39.5