.globl main
.globl INT
.globl VBL
+.globl return_to_main
##################################################
# #
.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)
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:
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:
.align 2
main:
+ /* make sure io port 2 is doing inputs */
+ move.b #0,(0xa1000b).l
/* mask irqs during init */
move.w #0x2700,sr
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
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:
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
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:
#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;
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) {
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++)
{
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;
}
--- /dev/null
+###############################################################################
+#
+# 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