trs80: first cut at drivewire support
authorAlan Cox <alan@linux.intel.com>
Mon, 1 Jun 2015 19:47:21 +0000 (20:47 +0100)
committerAlan Cox <alan@linux.intel.com>
Mon, 1 Jun 2015 19:47:21 +0000 (20:47 +0100)
Limited to a whopping 19200 baud, and assumes you set up the /dev/tty3 port as you want then run drivewire (don't mix and match!)

Needs optimising, actually testing once I've fixed the emulator to do better
serial proxying.

Kernel/platform-trs80/Makefile
Kernel/platform-trs80/devices.c
Kernel/platform-trs80/drivewire.s [new file with mode: 0644]
Kernel/platform-trs80/fuzix.lnk

index 82c1e02..c3ce2e8 100644 (file)
@@ -4,12 +4,17 @@ CSRCS += devices.c main.c
 DISCARD_CSRCS = discard.c devhd_discard.c
 
 ASRCS = trs80.s crt0.s
-ASRCS += tricks.s commonmem.s floppy.s
+ASRCS += tricks.s commonmem.s floppy.s drivewire.s
+
+DSRCS = ../dev/devdw.c
 
 COBJS = $(CSRCS:.c=.rel)
 AOBJS = $(ASRCS:.s=.rel)
 DISCARD_COBJS = $(DISCARD_CSRCS:.c=.rel)
-OBJS  = $(COBJS) $(AOBJS) $(DISCARD_COBJS)
+DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS))
+OBJS  = $(COBJS) $(AOBJS) $(DISCARD_COBJS) $(DOBJS)
+
+CROSS_CCOPTS += -I../dev/
 
 JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst)
 
@@ -21,6 +26,9 @@ $(COBJS): %.rel: %.c
 $(AOBJS): %.rel: %.s
        $(CROSS_AS) $(ASOPTS) $<
 
+$(DOBJS): %.rel: ../dev/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
 $(DISCARD_COBJS): %.rel: %.c
        $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
 
index ad1b01f..1b80402 100644 (file)
@@ -6,6 +6,7 @@
 #include <devhd.h>
 #include <devsys.h>
 #include <devlpr.h>
+#include <devdw.h>
 #include <vt.h>
 #include <devtty.h>
 #include <devgfx.h>
@@ -23,6 +24,11 @@ struct devsw dev_tab[] =  /* The device driver switch table */
   /* 4: /dev/mem etc   System devices (one offs) */
   {  no_open,     no_close,     sys_read,  sys_write,  sys_ioctl },
   /* Pack to 7 with nxio if adding private devices and start at 8 */
+  {  nxio_open,     no_close,    no_rdwr,   no_rdwr,   no_ioctl },
+  {  nxio_open,     no_close,    no_rdwr,   no_rdwr,   no_ioctl },
+  {  nxio_open,     no_close,    no_rdwr,   no_rdwr,   no_ioctl },
+  /* 8: /dev/dw                DriveWire remote disk images */
+  {  dw_open,      no_close,    dw_read,   dw_write,  no_ioctl },
 };
 
 bool validdev(uint16_t dev)
diff --git a/Kernel/platform-trs80/drivewire.s b/Kernel/platform-trs80/drivewire.s
new file mode 100644 (file)
index 0000000..c84b327
--- /dev/null
@@ -0,0 +1,153 @@
+       .module drivewire
+
+       .globl _dw_operation
+       .globl _dw_reset
+
+       .globl map_process_a
+       .globl map_kernel
+
+
+
+       .area _COMMONMEM
+
+       ; dw_reset(driveptr)
+_dw_reset:
+       ret
+
+       ; dw_operation(cmdblock, driveptr)
+_dw_operation:
+       pop bc          ; return
+       pop iy          ; cmdblock
+       pop de          ; driveptr
+       push de
+       push iy
+       push bc
+
+       ld b, 5(iy)     ; page map
+       call map_process_a
+       ld h, 3(iy)     ; pointer
+       ld l, 4(iy)
+       ld b, 1(iy)
+       ld c, 2(iy)
+       xor a
+       cp (iy)
+       ld a, (de)
+       jr nz, is_write
+       call dw_read_sector
+dw_op_ret:
+       ld hl, #0
+       jr nc, dw_op_ok
+       dec hl
+dw_op_ok:
+       jp map_kernel
+is_write:
+       call dw_write_sector
+       jr dw_op_ret
+
+; Entry A = command
+; Exit BCD = 0
+
+dw_hdr:
+       call txbyte
+       ld a, (de)      ; drive
+       call txbyte
+       xor a           ; LSN 23-16 = 0
+       call txbyte
+       ld a, b         ; sector high
+       call txbyte
+       ld a, c         ; sector low    
+       call txbyte
+       ld b, #0
+       ld d, b         ;checkum starts 0
+       ld e, b
+       ret
+
+dw_write_sector:
+       ld a, #0x57             ; WRITE
+       call dw_hdr
+payload1:
+       ld a, e
+       add (hl)
+       ld e, a
+       ld a, d
+       adc #0
+       ld d, a
+       ld a, (hl)
+       inc hl
+       call txbyte
+       djnz payload1
+       ld a, d
+       call txbyte
+       ld a, e
+       call txbyte
+       call rxbyte
+       ret
+
+dw_read_sector:
+       ld a, #0xD2             ; READEX
+       call dw_hdr
+       call rxbyte
+       ret c
+       or a
+       jr nz, error_ret
+;
+;      256 receive bytes
+;
+payload2:
+       call rxbyte
+       ret c
+       ld (hl), a
+       inc hl
+       ld a, (hl)
+       add e
+       ld e, a
+       ld a, #0
+       add d
+       ld d, a
+       djnz payload2
+       ld a, d
+       call txbyte
+       ld a, e
+       call txbyte
+       call rxbyte
+       ret c
+       or a
+       ret z
+       ; We could be smarter about error codes and reporting ?
+error_ret:
+       scf
+       ret
+
+;
+;      Serial logic, polled interrupts off so we can do a reliable 19200
+;      baud (hardware limit)
+;
+txbyte:
+       in a, (0xEA)
+       bit 6, a
+       jr z, txbyte
+       out (0xEB), a
+       ret
+;
+;      We poll for receive in this mode as interrupts are off and we want
+;      *speed*
+;
+rxbyte:
+       ; Loop time is 56 clocks so ~=72K loops/second
+       ; we want to spin for 0.25 (Drivewire limit)
+       ld bc, #0x46
+rxbytel:
+       in a, (0xEA)            ; 11
+       bit 7, a                ; 8
+       jr nz, gotbyte          ; 7(12)
+       dec bc                  ; 10
+       ld a, b                 ; 4
+       or c                    ; 4
+       jr nz, rxbytel          ; 7(12)
+       scf
+       ret
+gotbyte:
+       in a, (0xEB)
+       or a
+       ret
+
index 210e691..da04512 100644 (file)
@@ -40,4 +40,6 @@ devsys.rel
 platform-trs80/devlpr.rel
 platform-trs80/devtty.rel
 platform-trs80/discard.rel
+platform-trs80/devdw.rel
+platform-trs80/drivewire.rel
 -e