hexed: add simple io commands
authornotaz <notasas@gmail.com>
Fri, 20 May 2011 11:41:28 +0000 (14:41 +0300)
committernotaz <notasas@gmail.com>
Fri, 20 May 2011 11:41:28 +0000 (14:41 +0300)
seems to have some race condition/timing issues..

hexed/pc_transfer.c
hexed/transfer.S
hexed/transfer.h

index 9e2681a..569acfc 100644 (file)
 #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");
index 4ab3aff..0115dd9 100644 (file)
@@ -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
index b1aa7cd..b5a9817 100644 (file)
@@ -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