hexed: new pc control code (send/recv only for now)
authornotaz <notasas@gmail.com>
Mon, 16 May 2011 12:15:17 +0000 (15:15 +0300)
committernotaz <notasas@gmail.com>
Mon, 16 May 2011 12:15:17 +0000 (15:15 +0300)
hexed/Makefile
hexed/hexed.s
hexed/pc_transfer.c
hexed/transfer.S [new file with mode: 0644]
hexed/transfer.h [new file with mode: 0644]

index f480c15..8b992bd 100644 (file)
@@ -1,12 +1,14 @@
 CROSS = m68k-elf-\r
+CC = $(CROSS)gcc\r
 AS = $(CROSS)as\r
 LD = $(CROSS)ld\r
 OBJCOPY = $(CROSS)objcopy\r
 \r
 ASFLAGS += -m68000 --register-prefix-optional --bitwise-or -pic\r
+CPPFLAGS += -Wa,-m68000 -Wa,--register-prefix-optional -Wa,--bitwise-or -Wa,-pic\r
 \r
 TARGET = hexed.bin\r
-OBJS = sega_gcc.o hexed.o font.o\r
+OBJS = sega_gcc.o hexed.o transfer.o font.o\r
 \r
 all : $(TARGET)\r
 \r
@@ -23,6 +25,9 @@ pc_transfer: pc_transfer.c
        gcc -Wall -O2 -ggdb -o $@ $^\r
 \r
 \r
+.S.o:\r
+       $(CC) -c -o $@ $^ $(CPPFLAGS)\r
+\r
 # ----------- release -----------\r
 ifneq ($(findstring rel,$(MAKECMDGOALS)),)\r
 ifeq ($(VER),)\r
index cdaebcd..b999de1 100644 (file)
@@ -37,6 +37,7 @@
 .globl main
 .globl INT
 .globl VBL
+.globl return_to_main
 
 ##################################################
 #                                                #
@@ -81,7 +82,7 @@
 .equ MMODE_START_MENU, 4
 .equ MMODE_GOTO_PREDEF,        5
 .equ MMODE_JMP_ADDR,   6
-.equ MMODE_DUMP,       7
+.equ MMODE_PC,         7
 
 .equ predef_addr_cnt,  ((predef_addrs_end-predef_addrs)/4)
 
@@ -214,13 +215,6 @@ safe_addrs:
        dc.l 0xa13000, 0xa130ff
 safe_addrs_end:
 
-transfer_mode:
-       dc.l 0x000000           /* 1 for recv */
-transfer_addr:
-       dc.l 0x000000
-transfer_len:
-       dc.l 0x000800
-
 txt_edit:
        .ascii  "- edit -\0"
 txt_a_confirm:
@@ -234,15 +228,13 @@ txt_goto_predef:
 txt_jmp_addr:
        .ascii  "Jump to address\0"
 txt_dump:
-       .ascii  "Transfer\0"
+       .ascii  "PC Transfer\0"
 txt_dtack:
        .ascii  "DTACK safety\0"
-txt_ready_send:
-       .ascii  "Ready to send\0"
-txt_ready_recv:
-       .ascii  "Ready to recv\0"
+txt_transfer_ready:
+       .ascii  "Transfer Ready\0"
 txt_working:
-       .ascii  "Working..    \0"
+       .ascii  "PC mode       \0"
 txt_dtack_err:
        .ascii  "DTACK err?\0"
 txt_exc:
@@ -265,6 +257,8 @@ txt_exc:
 .align 2
 
 main:
+       /* make sure io port 2 is doing inputs */
+       move.b          #0,(0xa1000b).l
        /* mask irqs during init */
        move.w          #0x2700,sr
 
@@ -436,6 +430,12 @@ VBL:
        addq.b          #1,d7
 #      movem.l         d0-d4/a0-a5,-(a7)
 
+       btst.b          #5,(0xa10005).l
+       bne             no_auto_transfer
+       change_mode     MMODE_PC, MMODE_MAIN
+       write_vdp_r_dst 12,(VDP12_SCREEN_V224 | VDP12_SCREEN_H320 | VDP12_STE),(GFXCNTL)
+
+no_auto_transfer:
        moveq.l         #0,d0
        move.w          d7,d0
        lsr.w           #6,d0
@@ -1164,7 +1164,7 @@ msm_no_ud:
 0:
        cmp.b           #3,d1
        bne             0f
-       change_mode     MMODE_DUMP, MMODE_MAIN
+       change_mode     MMODE_PC, MMODE_MAIN
        bsr             start_menu_box
        bra             vbl_end
 0:
@@ -1295,20 +1295,11 @@ mode_jmp_finish:
        move.l          d5,a0
        jmp             (a0)
 
-################### transfer #####################
-
 mode_transfer:
-       move.b          #0x40,(0xa1000b).l
-       move.b          #0x40,(0xa10005).l
+       move.b          #0x40,(0xa1000b).l      /* port 2 ctrl */
+       move.b          #0x00,(0xa10005).l      /* port 2 data - start with TH low */
 
-       move.l          (transfer_mode,pc),d0
-       tst.l           d0
-       bne             0f
-       lea             (txt_ready_send,pc),a0
-       bra             1f
-0:
-       lea             (txt_ready_recv,pc),a0
-1:
+       lea             (txt_transfer_ready,pc),a0
        move.l          #13,d0
        move.l          #13,d1
        move.l          #0x8000,d2
@@ -1320,74 +1311,7 @@ wait_tl_low0:
        bne             wait_tl_low0
 
        menu_text       txt_working, 13, 13, 0
-
-       lea             0xa10005,a1
-       move.l          (transfer_addr,pc),a0
-       move.l          (transfer_len,pc),d2
-
-       move.l          (transfer_mode,pc),d0
-       tst.l           d0
-       bne             transfer_recv
-
-transfer_send:
-       move.b          #0x4f,(0xa1000b).l
-
-tr_send_loop:
-       move.b          (a0),d1
-       and.b           #0x0f,d1
-
-wait_tl_low1:
-       move.b          (a1),d0
-       btst.b          #4,d0
-       bne             wait_tl_low1
-
-       move.b          d1,(a1)         /* clears TH and writes data */
-
-       move.b          (a0)+,d1
-       lsr.b           #4,d1
-       bset.b          #6,d1           /* prepare TH */
-
-wait_tl_hi1:
-       move.b          (a1),d0
-       btst.b          #4,d0
-       beq             wait_tl_hi1
-
-       move.b          d1,(a1)
-       subq.l          #1,d2
-       bne             tr_send_loop
-
-       move.b          #0,(0xa1000b).l
-       bra             return_to_main
-
-transfer_recv:
-       move.b          #0,(a1)         /* clear TH */
-
-tr_recv_loop:
-wait_tl_low2:
-       move.b          (a1),d0
-       btst.b          #4,d0
-       bne             wait_tl_low2
-
-       move.b          #0x40,(a1)      /* set TH */
-       move.b          d0,d1
-       and.b           #0x0f,d1
-
-wait_tl_hi2:
-       move.b          (a1),d0
-       btst.b          #4,d0
-       beq             wait_tl_hi2
-
-       move.b          #0,(a1)         /* clear TH */
-       lsl.b           #4,d0
-       or.b            d0,d1
-       move.b          d1,(a0)+
-
-       subq.l          #1,d2
-       bne             tr_recv_loop
-
-       move.b          #0,(0xa1000b).l
-       bra             return_to_main
-
+       bra             do_transfer
 
 # go back to main mode
 return_to_main:
index 844054f..2263a6d 100644 (file)
@@ -1,8 +1,12 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/io.h>
 #include <signal.h>
+#include <sys/time.h>
+
+#include "transfer.h"
 
 /*
  * PC:
  * 7 TH  --> 10 ACK
  * 8 GND --- 21 GND
  * 9 TR  <-- 17 /SLCT_IN
+ *
+ * start: TH low/high, TL high
+ *
+ * TH low  - lower nibble: MD ready to recv | MD sent to PC
+ * TL low  - lower niblle: sent to MD       | ready to recv from MD
+ * TH high - upper nibble: MD ready to recv | MD sent to PC
+ * TL high - upper nibble: sent             | ready to recv from MD
  */
 
-static void inthandler(int u)
+#define ACK_TIMEOUT    2000000
+
+#define PORT_DATA      888
+#define PORT_STATUS    889
+#define PORT_CONTROL   890
+
+#define timediff(now, start) \
+       ((now.tv_sec - start.tv_sec) * 1000000 + now.tv_usec - start.tv_usec)
+
+static void do_exit(const char *msg)
 {
        /* switch TL back to high */
-       outb(0xe0, 890);
-       printf("\n");
+       outb(0xe0, PORT_CONTROL);
+
+       if (msg)
+               printf("%s", msg);
        exit(1);
 }
 
-int main(int argc, char *argv[])
+static void inthandler(int u)
 {
-       int size, byte, ret, i;
-       unsigned char *data;
-       char *p = NULL;
-       FILE *file;
+       do_exit("\n");
+}
 
-       if (argc != 4 || argv[1][0] != '-' || (argv[1][1] != 'r' && argv[1][1] != 'w')) {
-               printf("usage:\n%s {-r,-w} <file> <size_hex>\n", argv[0]);
-               return 1;
+static void wait_th_low(void)
+{
+       struct timeval start, now;
+
+       gettimeofday(&start, NULL);
+
+       while (inb(PORT_STATUS) & 0x40) {
+               gettimeofday(&now, NULL);
+               if (timediff(now, start) > ACK_TIMEOUT)
+                       do_exit("timeout waiting TH low\n");
        }
+}
 
-       file = fopen(argv[2], argv[1][1] == 'r' ? "wb" : "rb");
-       if (file == NULL) {
-               fprintf(stderr, "can't open file: %s\n", argv[2]);
-               return 1;
+static void wait_th_high(void)
+{
+       struct timeval start, now;
+
+       gettimeofday(&start, NULL);
+
+       while (!(inb(PORT_STATUS) & 0x40)) {
+               gettimeofday(&now, NULL);
+               if (timediff(now, start) > ACK_TIMEOUT)
+                       do_exit("timeout waiting TH high\n");
        }
+}
+
+static unsigned int recv_byte(void)
+{
+       unsigned int byte;
+
+       outb(0xe2, PORT_CONTROL);       /* TL low */
+
+       wait_th_low();
+
+       byte = inb(PORT_DATA) & 0x0f;
+
+       outb(0xe0, PORT_CONTROL);       /* TL high */
+
+       wait_th_high();
+
+       byte |= inb(PORT_DATA) << 4;
+
+       return byte;
+}
+
+static void send_byte(unsigned int byte)
+{
+       wait_th_low();
+
+       outb(byte & 0x0f, PORT_DATA);
+       outb(0xc2, PORT_CONTROL);       /* TL low */
+
+       wait_th_high();
+
+       outb((byte >> 4) & 0x0f, PORT_DATA);
+       outb(0xc0, PORT_CONTROL);       /* TL high */
+}
+
+static void send_cmd(unsigned int cmd)
+{
+       send_byte(CMD_PREFIX);
+       send_byte(cmd);
+}
+
+static void usage(const char *argv0)
+{
+       fprintf(stderr, "usage:\n%s <cmd> [args]\n"
+               "\tsend <file> <addr> [size]\n"
+               "\trecv <file> <addr> <size>\n", argv0);
+       exit(1);
+}
+
+static unsigned int atoi_or_die(const char *a)
+{
+       char *p = NULL;
+       unsigned int i;
 
-       size = (int)strtoul(argv[3], &p, 16);
+       i = strtoul(a, &p, 0);
        if (p == NULL || *p != 0) {
-               fprintf(stderr, "can't convert size %s\n", argv[3]);
-               return 1;
+               fprintf(stderr, "atoi: can't convert: %s\n", a);
+               exit(1);
        }
 
-       data = malloc(size);
+       return i;
+}
+
+int main(int argc, char *argv[])
+{
+       unsigned int addr = 0, size = 0, i = 0;
+       int ret;
+       unsigned char *data;
+       FILE *file = NULL;
+
+       if (argc < 2)
+               usage(argv[0]);
+
+       data = malloc(0x1000000);
        if (data == NULL) {
-               fprintf(stderr, "can't alloc %d bytes\n", size);
+               fprintf(stderr, "can't alloc %d bytes\n", 0x1000000);
                return 1;
        }
 
-       ret = ioperm(888, 3, 1);
+       /* parse args, read files.. */
+       if (strcmp(argv[1], "send") == 0)
+       {
+               if (argc != 4 && argc != 5)
+                       usage(argv[0]);
+
+               file = fopen(argv[2], "rb");
+               if (file == NULL) {
+                       fprintf(stderr, "can't open file: %s\n", argv[2]);
+                       return 1;
+               }
+
+               addr = atoi_or_die(argv[3]);
+               if (argv[4] == NULL) {
+                       fseek(file, 0, SEEK_END);
+                       size = ftell(file);
+                       fseek(file, 0, SEEK_SET);
+               }
+               else
+                       size = atoi_or_die(argv[4]);
+
+               ret = fread(data, 1, size, file);
+               if (ret != size) {
+                       fprintf(stderr, "fread returned %d/%d\n", ret, size);
+                       perror(NULL);
+                       return 1;
+               }
+       }
+       else if (strcmp(argv[1], "recv") == 0)
+       {
+               if (argc != 5)
+                       usage(argv[0]);
+
+               file = fopen(argv[2], "wb");
+               if (file == NULL) {
+                       fprintf(stderr, "can't open file: %s\n", argv[2]);
+                       return 1;
+               }
+
+               addr = atoi_or_die(argv[3]);
+               size = atoi_or_die(argv[4]);
+
+               memset(data, 0, size);
+       }
+       else
+               usage(argv[0]);
+
+       ret = ioperm(PORT_DATA, 3, 1);
        if (ret != 0) {
                perror("ioperm");
                return 1;
@@ -74,16 +220,28 @@ int main(int argc, char *argv[])
 
        signal(SIGINT, inthandler);
 
-       printf("regs: %02x %02x %02x\n", inb(888), inb(889), inb(890));
-       outb(0xe0, 890);
+       printf("regs: %02x %02x %02x\n",
+               inb(PORT_DATA), inb(PORT_STATUS), inb(PORT_CONTROL));
+       outb(0xe8, PORT_CONTROL);       /* TR low - request for transfer */
 
-       while (!(inb(889) & 0x40)) {
-               printf("waiting for TH..\n");
-               sleep(5);
-       }
+       if (inb(PORT_STATUS) & 0x40)
+               printf("waiting for TH low..\n");
+       while (inb(PORT_STATUS) & 0x40)
+               sleep(1);
+
+       outb(0xe0, PORT_CONTROL);
 
-       if (argv[1][1] == 'r')
+       if (strcmp(argv[1], "send") == 0)
        {
+               printf("send %06x %06x\n", addr, size);
+               send_cmd(CMD_MD_SEND);
+               send_byte((addr >> 16) & 0xff);
+               send_byte((addr >>  8) & 0xff);
+               send_byte((addr >>  0) & 0xff);
+               send_byte((size >> 16) & 0xff);
+               send_byte((size >>  8) & 0xff);
+               send_byte((size >>  0) & 0xff);
+
                for (i = 0; i < size; i++)
                {
                        if ((i & 0xff) == 0) {
@@ -92,33 +250,19 @@ int main(int argc, char *argv[])
                                fflush(stdout);
                        }
 
-                       outb(0xe2, 890);        /* TL low */
-
-                       /* wait for TH low */
-                       while (inb(889) & 0x40) ;
-
-                       byte = inb(888) & 0x0f;
-
-                       outb(0xe0, 890);        /* TL high */
-
-                       /* wait for TH high */
-                       while (!(inb(889) & 0x40)) ;
-
-                       byte |= inb(888) << 4;
-                       data[i] = byte;
+                       send_byte(data[i]);
                }
-
-               fwrite(data, 1, size, file);
        }
-       else
+       else if (strcmp(argv[1], "recv") == 0)
        {
-               ret = fread(data, 1, size, file);
-               if (ret < size)
-                       printf("warning: read only %d/%d\n", ret, size);
-
-               outb(0xc0, 890);        /* out mode, TL hi */
-               outb(data[0] & 0x0f, 888);
-               outb(0xc2, 890);        /* out mode, TL low (start condition) */
+               send_cmd(CMD_MD_RECV);
+               send_byte((addr >> 16) & 0xff);
+               send_byte((addr >>  8) & 0xff);
+               send_byte((addr >>  0) & 0xff);
+               send_byte((size >> 16) & 0xff);
+               send_byte((size >>  8) & 0xff);
+               send_byte((size >>  0) & 0xff);
+               outb(0xe0, PORT_CONTROL);       /* TL high, recv mode */
 
                for (i = 0; i < size; i++)
                {
@@ -128,25 +272,18 @@ int main(int argc, char *argv[])
                                fflush(stdout);
                        }
 
-                       /* wait for TH low */
-                       while (inb(889) & 0x40) ;
-
-                       byte = data[i];
-
-                       outb(byte & 0x0f, 888);
-                       outb(0xc2, 890);        /* TL low */
-
-                       /* wait for TH high */
-                       while (!(inb(889) & 0x40)) ;
-
-                       outb(byte >> 4, 888);
-                       outb(0xc0, 890);        /* TL high */
+                       data[i] = recv_byte();
                }
+
+               fwrite(data, 1, size, file);
        }
        printf("\b\b\b\b\b\b\b\b\b\b\b\b\b");
        printf("%06x/%06x\n", i, size);
        fclose(file);
 
+       /* switch TL back to high, disable outputs */
+       outb(0xe0, PORT_CONTROL);
+
        return 0;
 }
 
diff --git a/hexed/transfer.S b/hexed/transfer.S
new file mode 100644 (file)
index 0000000..0168e49
--- /dev/null
@@ -0,0 +1,174 @@
+###############################################################################
+#
+# Copyright (c) 2011, GraÅžvydas Ignotas
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the organization nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Assemble with gas
+#   --register-prefix-optional --bitwise-or
+#
+
+#include "transfer.h"
+
+.text
+.globl do_transfer
+
+
+# receive 1 byte to d0
+#  in: a1 - data port
+#  trash: d1
+.macro recv_one_byte is_last=0
+       move.b          #0,(a1)         /* clear TH */
+
+0: /*L_wait_tl_low*/
+       move.b          (a1),d1
+       btst.b          #4,d1
+       bne             0b /*L_wait_tl_low*/
+
+       move.b          #0x40,(a1)      /* set TH */
+       and.b           #0x0f,d1
+
+0: /*L_wait_tl_hi*/
+       move.b          (a1),d0
+       btst.b          #4,d0
+       beq             0b /*L_wait_tl_hi*/
+
+.if !\is_last
+       move.b          #0,(a1)         /* clear TH - ready for next */
+.endif
+       lsl.b           #4,d0
+       or.b            d1,d0
+.endm
+
+# send 1 byte in d0
+#  in: a1 - data port
+#  trash: d1,d2
+.macro send_one_byte
+       move.b          d0,d2
+       and.b           #0x0f,d2
+
+0: /*Lwait_tl_low:*/
+       move.b          (a1),d1
+       btst.b          #4,d1
+       bne             0b /*Lwait_tl_low*/
+
+       move.b          d2,(a1)         /* clears TH and writes data */
+
+       move.b          d0,d2
+       lsr.b           #4,d2
+       bset.b          #6,d2           /* prepare TH */
+
+0: /*wait_tl_hi*/
+       move.b          (a1),d1
+       btst.b          #4,d1
+       beq             0b /*wait_tl_hi1*/
+
+       move.b          d2,(a1)
+.endm
+
+recv_byte:
+       recv_one_byte 1
+       rts
+
+# receive address/size to d0 (3 bytes BE)
+#  in: a1 - data port
+#  trash: d1,d2
+recv_ad:
+       moveq.l         #0,d2
+       bsr             recv_byte
+       move.b          d0,d2
+       bsr             recv_byte
+       lsl.l           #8,d2
+       move.b          d0,d2
+       bsr             recv_byte
+       lsl.l           #8,d2
+       move.b          d0,d2
+       move.l          d2,d0
+       rts
+
+
+do_transfer:
+       lea             0xa10005,a1
+       move.b          #0x40,(0xa1000b).l      /* ctrl - all inputs except TH */
+       move.b          #0x00,(a1)
+
+       bsr             recv_byte
+       cmp.b           #CMD_PREFIX,d0
+       bne             return
+
+       bsr             recv_byte
+       cmp.b           #CMD_MD_SEND,d0         /* sent to us */
+       beq             transfer_recv
+       cmp.b           #CMD_MD_RECV,d0         /* recv from us */
+       beq             transfer_send
+       bra             return
+
+
+transfer_recv:
+       bsr             recv_ad
+       move.l          d0,a0
+       bsr             recv_ad
+       move.l          d0,d3
+
+tr_recv_loop:
+       recv_one_byte
+       move.b          d0,(a0)+
+       subq.l          #1,d3
+       bne             tr_recv_loop
+       bra             return
+
+transfer_send:
+       bsr             recv_ad
+       move.l          d0,a0
+       bsr             recv_ad
+       move.l          d0,d3
+
+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)
+
+tr_send_loop:
+       move.b          (a0)+,d0
+       send_one_byte
+       subq.l          #1,d3
+       bne             tr_send_loop
+       bra             return
+
+
+return:
+       move.b          #0,(0xa1000b).l /* all inputs */
+       move.l          #0xffe000,a1
+       move.l          d0,(a1)+        /* last state for debug */
+       move.l          d1,(a1)+
+       move.l          d2,(a1)+
+       move.l          d3,(a1)+
+       move.l          a0,(a1)+
+       bra             return_to_main
+
+
+# vim:filetype=asmM68k
diff --git a/hexed/transfer.h b/hexed/transfer.h
new file mode 100644 (file)
index 0000000..0fcda0c
--- /dev/null
@@ -0,0 +1,4 @@
+#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[] */
+