dragon: Add DriveWire support
authorTormod Volden <debian.tormod@gmail.com>
Sun, 29 Mar 2015 13:13:21 +0000 (15:13 +0200)
committerAlan Cox <alan@linux.intel.com>
Sun, 29 Mar 2015 14:51:13 +0000 (15:51 +0100)
Reads and writes have been tested both on real hardware
(bit-banger serial) and XRoar (Becker interface).

Thanks to Darren Atkinson and Boisy Pitre for the original
low-level routines!

Signed-off-by: Tormod Volden <debian.tormod@gmail.com>
Kernel/platform-dragon/Makefile
Kernel/platform-dragon/README
Kernel/platform-dragon/devdw.c [new file with mode: 0644]
Kernel/platform-dragon/devdw.h [new file with mode: 0644]
Kernel/platform-dragon/devices.c
Kernel/platform-dragon/drivewire.s [new file with mode: 0644]
Kernel/platform-dragon/dw.def [new file with mode: 0644]
Kernel/platform-dragon/dwread.s [new file with mode: 0644]
Kernel/platform-dragon/dwwrite.s [new file with mode: 0644]

index c490d94..d84c5e8 100644 (file)
@@ -1,8 +1,8 @@
 
-CSRCS = devlpr.c devtty.c devfd.c
+CSRCS = devlpr.c devtty.c devfd.c devdw.c
 CSRCS += devices.c main.c libc.c
 
-ASRCS = p6809.s crt0.s
+ASRCS = p6809.s crt0.s drivewire.s
 ASRCS += tricks.s commonmem.s usermem_sam.s floppy.s
 
 COBJS = $(CSRCS:.c=$(BINEXT))
@@ -31,6 +31,7 @@ image: d64_1.rom
        crt0.o commonmem.o usermem_sam.o \
        p6809.o ../start.o ../version.o ../lowlevel-6809.o \
        tricks.o main.o ../timer.o ../kdata.o devfd.o floppy.o devices.o \
+       drivewire.o devdw.o \
        ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \
        ../syscall_proc.o ../syscall_other.o ../mm.o ../swap.o ../simple.o \
        ../tty.o ../devsys.o ../usermem.o ../syscall_fs2.o ../syscall_exec16.o \
index 1b66ee8..574ce2b 100644 (file)
@@ -143,7 +143,12 @@ then become sta [6]. Something like that anyway.
 
 Disks
 
-Not supported yet.
+Virtual disk drives over "DriveWire" are supported. For real machines
+it uses a bit-banging serial interface on the printer port.
+For XRoar it is using the Becker interface, which is supported by the
+DW4 server by Aaron Wolfe https://sites.google.com/site/drivewire4/
+
+Real disk controllers are not supported yet.
 
 With an expander we should look across all the cartridges to find out which
 one is us and which one (should be slot #4) contains a cartridge with DK at
@@ -155,8 +160,6 @@ one slot!
 
 Also to consider
 
-DriveWire - over Beckerport - serial 'virtual disk' protocol
-
 CoCoSDC: SDC virtual disk including LBA mode interface for SD hard disk and
 also flash for catridge slots (banked). Looks ideal but not documented
 usefully.
@@ -172,7 +175,7 @@ Delta:      WD2791
 
 RSDOS: WD1793
 
-Becker port at 0xFF40 (FF46 ? on Dragon)
+Hardware Becker port at 0xFF40 (FF46 ? on Dragon)
 
 IDE: FF70-FF78 - data latched (write high/load, read low/high) [0-7 IDE regs
                8 maps the latches]
diff --git a/Kernel/platform-dragon/devdw.c b/Kernel/platform-dragon/devdw.c
new file mode 100644 (file)
index 0000000..ae3fc91
--- /dev/null
@@ -0,0 +1,89 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devdw.h>
+
+#define MAX_DW 4       /* can be 255 */
+
+#define DW_READ                0
+#define DW_WRITE       1
+
+static uint8_t dw_tab[MAX_DW];
+
+/*
+ *     Block device glue for DriveWire
+ *
+ *     DriveWire uses 256 byte sector transfers
+ */
+
+static int dw_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+    blkno_t block;
+    uint16_t dptr;
+    int ct = 0;
+    int tries;
+    uint8_t err;
+    uint8_t *driveptr = dw_tab + minor;
+    uint8_t cmd[5];
+
+    if(rawflag)
+        goto bad2;
+
+    dptr = (uint16_t)udata.u_buf->bf_data;
+    block = udata.u_buf->bf_blk;
+
+//    kprintf("Issue command: drive %d\n", minor);
+    /* maybe mimicking floppy driver more than needed? */
+    cmd[0] = is_read ? DW_READ : DW_WRITE;
+    cmd[1] = block >> 7;       /* 2 sectors per block */
+    cmd[2] = (block << 1) & 0xFF;
+    cmd[3] = dptr >> 8;
+    cmd[4] = dptr & 0xFF;
+    *driveptr = minor; /* pass minor (drive number) through here for now */
+        
+    while (ct < 2) {
+        for (tries = 0; tries < 4 ; tries++) {
+            // kprintf("dw_operation on block %d ct %d\n", block, ct);
+            err = dw_operation(cmd, driveptr);
+            if (err == 0)
+                break;
+            if (tries > 1)
+                dw_reset(driveptr);
+        }
+        /* FIXME: should we try the other half and then bail out ? */
+        if (tries == 3)
+            goto bad;
+        cmd[3]++;      /* Move on 256 bytes in the buffer */
+        cmd[2]++;      /* Next sector for 2nd block */
+        ct++;
+    }
+    return 1;
+bad:
+    kprintf("dw%d: error %x\n", minor, err);
+bad2:
+    udata.u_error = EIO;
+    return -1;
+}
+
+/* FIXME: for bit-banger transport (not Becker) we should set up
+   the PIA at some point too */
+
+int dw_open(uint8_t minor, uint16_t flag)
+{
+    if(minor >= MAX_DW) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
+
+int dw_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    return dw_transfer(minor, true, rawflag);
+}
+
+int dw_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    return dw_transfer(minor, false, rawflag);
+}
+
diff --git a/Kernel/platform-dragon/devdw.h b/Kernel/platform-dragon/devdw.h
new file mode 100644 (file)
index 0000000..d7b9358
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __DEVDW_DOT_H__
+#define __DEVDW_DOT_H__
+
+/* public interface */
+int dw_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int dw_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int dw_open(uint8_t minor, uint16_t flag);
+
+/* low level interface */
+uint8_t dw_reset(uint8_t *drive);
+uint8_t dw_operation(uint8_t *cmd, uint8_t *drive);
+
+#endif /* __DEVDW_DOT_H__ */
+
index fe99fe2..a188243 100644 (file)
@@ -2,6 +2,7 @@
 #include <version.h>
 #include <kdata.h>
 #include <devfd.h>
+#include <devdw.h>
 #include <devsys.h>
 #include <devlpr.h>
 #include <tty.h>
@@ -22,6 +23,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-dragon/drivewire.s b/Kernel/platform-dragon/drivewire.s
new file mode 100644 (file)
index 0000000..babebeb
--- /dev/null
@@ -0,0 +1,139 @@
+;
+; DriveWire sector routines
+;
+; Copyright 2015 Tormod Volden
+; Copyright 2008 Boisy G. Pitre
+; Distributed under the GNU General Public License, version 2 or later.
+;
+
+       ; exported
+       .globl _dw_operation
+       .globl _dw_reset
+
+       .area .text
+
+_dw_reset:
+       ; maybe reinitalise PIA here?
+       ; and send DW_INIT request to server?
+       rts
+
+_dw_operation:
+       pshs y
+       ; get parameters from C, X points to cmd packet
+       ldy 4,s         ; driveptr
+       lda ,y          ; for now, contains minor = drive number directly
+       ldb ,x          ; write flag
+       ; buffer location into Y
+       ldy 3,x
+       ; sector number into X
+       ldx 1,x
+       tstb
+       bne @write
+       jsr dw_read_sector
+       bra @done
+@write  jsr dw_write_sector
+@done  bcs @err
+       bne @err
+       ldx #0
+@ret   puls y,pc
+@err   ldx #0xFFFF
+       bra @ret
+
+; Write a sector to the DriveWire server
+; Drive number in A, sector number in X, buffer location in Y
+; Sets carry or non-zero flags on error
+dw_write_sector:
+       ; header: OP, drive = A, LSN 23-16 = 0, LSN 15-8 and LSN 7-0 = X
+       clrb
+       pshs a,b,x
+       ldb #OP_WRITE
+       pshs b
+       ; send header
+       tfr s,x
+       pshs y          ; save buffer location
+       ldy #5
+       jsr DWWrite
+       ; send payload
+       ldx ,s
+       ldy #256
+       jsr DWWrite
+       ; calculate checksum of payload, backwards
+       exg x,y         ; Y is zero after DWWrite
+@sum   ldb ,-y
+       abx
+       cmpy ,s         ; buffer location start
+       bne @sum
+       stx ,s          ; checksum to send
+       tfr s,x
+       ldy #2
+       jsr DWWrite
+       ; get status byte from server into following byte
+       ldy #1
+       clra            ; clear carry bit for BECKER variant
+       jsr DWRead
+       leas 7,s
+       bcs @ret
+       bne @ret
+       ldb -5,s        ; received status byte (zero is success)
+@ret   rts
+
+;
+; Based on "DoRead" by Boisy G. Pitre from DWDOS hosted on toolshed.sf.net 
+; Read a sector from the DriveWire server
+; Drive number in A, 16-bit sector in X, buffer location in Y
+; Sets carry or non-zero flags on error
+
+dw_read_sector:
+         ; header: OP, drive = A, LSN 23-16 = 0, LSN 15-8 and LSN 7-0 = X
+         clrb
+         pshs  d,x,y
+         lda   #OP_READEX
+ReRead   pshs  a
+         leax  ,s
+        ldy   #$0005
+        lbsr  DWWrite
+        puls  a
+        ldx   4,s                      get read buffer pointer
+        ldy   #256                     read 256 bytes
+        ldd   #133*1                   1 second timeout
+        bsr   DWRead
+         bcs   ReadEx
+         bne   ReadEx
+; Send 2 byte checksum
+        pshs  y
+        leax  ,s
+        ldy   #2
+        lbsr  DWWrite
+        ldy   #1
+        ldd   #133*1
+        bsr   DWRead
+        leas  2,s
+        bcs   ReadEx
+        bne   ReadEx
+; Check received status byte
+        lda   ,s
+        beq   ReadEx
+        cmpa  #E_CRC
+        bne   ReadErr
+        lda   #OP_REREADEX
+        clr   ,s
+        bra   ReRead  
+ReadErr  comb                  ; set carry bit
+ReadEx  puls  d,x,y,pc
+
+; Used by DWRead and DWWrite
+IntMasks equ   $50
+NOINTMASK equ  1
+
+; Hardcode these for now so that we can use below files unmodified
+H6309    equ 0
+BECKER   equ 1
+ARDUINO  equ 0
+JMCPBCK  equ 0
+BAUD38400 equ 0
+
+; These files are copied almost as-is from HDB-DOS
+         include "dw.def"
+         include "dwread.s"
+         include "dwwrite.s"
+
diff --git a/Kernel/platform-dragon/dw.def b/Kernel/platform-dragon/dw.def
new file mode 100644 (file)
index 0000000..677f4c7
--- /dev/null
@@ -0,0 +1,70 @@
+********************************************************************
+*
+* Copied from HDB-DOS from toolshed.sf.net
+*
+* dwdefs - DriveWire Definitions File
+*
+* $Id: dwdefs.d,v 1.10 2010/02/21 06:24:47 aaronwolfe Exp $
+*
+* Ed.    Comments                                       Who YY/MM/DD
+* ------------------------------------------------------------------
+*   1    Started                                        BGP 03/04/03
+*   2    Added DWGLOBS area                             BGP 09/12/27
+
+         nam   dwdefs
+         ttl   DriveWire Definitions File
+
+* Addresses
+BBOUT       equ    $FF20
+BBIN        equ    $FF22
+
+* Opcodes
+OP_NOP      equ    $00         No-Op
+OP_RESET1   equ    $FE         Server Reset
+OP_RESET2   equ    $FF         Server Reset
+OP_RESET3   equ    $F8         Server Reset
+OP_DWINIT      equ        'Z           DriveWire dw3 init/OS9 boot
+OP_TIME     equ    '#          Current time requested
+OP_INIT     equ    'I          Init routine called
+OP_READ     equ    'R          Read one sector
+OP_REREAD   equ    'r          Re-read one sector
+OP_READEX   equ    'R+128      Read one sector
+OP_REREADEX equ    'r+128      Re-read one sector
+OP_WRITE    equ    'W          Write one sector
+OP_REWRIT   equ    'w          Re-write one sector
+OP_GETSTA   equ    'G          GetStat routine called
+OP_SETSTA   equ    'S          SetStat routine called
+OP_TERM     equ    'T          Term routine called
+OP_SERINIT  equ    'E
+OP_SERTERM  equ    'E+128
+
+* Printer opcodes
+OP_PRINT    equ    'P          Print byte to the print buffer
+OP_PRINTFLUSH equ  'F          Flush the server print buffer
+
+* Serial opcodes
+OP_SERREAD equ 'C
+OP_SERREADM equ 'c
+OP_SERWRITE equ 'C+128
+OP_SERGETSTAT equ 'D
+OP_SERSETSTAT equ 'D+128
+
+* for dw vfm
+OP_VFM equ 'V+128
+
+* WireBug opcodes (Server-initiated)
+OP_WIREBUG_MODE  equ   'B
+* WireBug opcodes (Server-initiated)
+OP_WIREBUG_READREGS   equ  'R  Read the CoCo's registers
+OP_WIREBUG_WRITEREGS  equ  'r  Write the CoCo's registers
+OP_WIREBUG_READMEM    equ  'M  Read the CoCo's memory
+OP_WIREBUG_WRITEMEM   equ  'm  Write the CoCo's memory
+OP_WIREBUG_GO         equ  'G  Tell CoCo to get out of WireBug mode and continue execution
+
+* VPort opcodes (CoCo-initiated)
+OP_VPORT_READ         equ  'V
+OP_VPORT_WRITE        equ  'v
+
+* Error definitions
+E_CRC      equ   $F3            Same as NitrOS-9 E$CRC
+
diff --git a/Kernel/platform-dragon/dwread.s b/Kernel/platform-dragon/dwread.s
new file mode 100644 (file)
index 0000000..1b4c587
--- /dev/null
@@ -0,0 +1,341 @@
+*******************************************************
+*
+* Copied from HDB-DOS from toolshed.sf.net
+* The original code is public domain
+*
+* DWRead
+*    Receive a response from the DriveWire server.
+*    Times out if serial port goes idle for more than 1.4 (0.7) seconds.
+*    Serial data format:  1-8-N-1
+*    4/12/2009 by Darren Atkinson
+*
+* Entry:
+*    X  = starting address where data is to be stored
+*    Y  = number of bytes expected
+*
+* Exit:
+*    CC = carry set on framing error, Z set if all bytes received
+*    X  = starting address of data received
+*    Y  = checksum
+*    U is preserved.  All accumulators are clobbered
+*
+
+          IFNE ARDUINO
+* Note: this is an optimistic routine. It presumes that the server will always be there, and
+* has NO timeout fallback. It is also very short and quick.
+DWRead    clra                          ; clear Carry (no framing error)
+          pshs   u,x,cc              ; preserve registers
+          leau   ,x
+          ldx    #$0000
+loop@     tst    $FF51                  ; check for CA1 bit (1=Arduino has byte ready)
+          bpl    loop@                  ; loop if not set
+          ldb    $FF50                  ; clear CA1 bit in status register
+          stb    ,u+                    ; save off acquired byte
+          abx                           ; update checksum
+          leay   ,-y
+          bne    loop@
+
+          leay      ,x                  ; return checksum in Y
+          puls      cc,x,u,pc        ; restore registers and return
+
+          ELSE
+
+          IFNE JMCPBCK
+* NOTE: There is no timeout currently on here...
+DWRead    clra                          ; clear Carry (no framing error)
+          deca                          ; clear Z flag, A = timeout msb ($ff)
+          tfr       cc,b
+          pshs      u,x,dp,b,a          ; preserve registers, push timeout msb
+          leau   ,x
+          ldx    #$0000
+          IFEQ   NOINTMASK
+          orcc   #IntMasks
+          ENDC
+loop@     ldb    $FF4C
+          bitb   #$02
+          beq    loop@
+          ldb    $FF44
+          stb    ,u+
+          abx
+          leay   ,-y
+          bne    loop@
+
+          tfr    x,y
+          ldb    #0
+          lda    #3
+          leas      1,s                 ; remove timeout msb from stack
+          inca                          ; A = status to be returned in C and Z
+          ora       ,s                  ; place status information into the..
+          sta       ,s                  ; ..C and Z bits of the preserved CC
+          leay      ,x                  ; return checksum in Y
+          puls      cc,dp,x,u,pc        ; restore registers and return
+          ELSE
+          IFNE BECKER
+          IFNDEF BCKSTAT
+BCKSTAT   equ   $FF41
+          ENDC
+          IFNDEF BCKPORT
+BCKPORT   equ   $FF42
+          ENDC
+* NOTE: There is no timeout currently on here...
+DWRead    clra                          ; clear Carry (no framing error)
+          deca                          ; clear Z flag, A = timeout msb ($ff)
+          tfr       cc,b
+          pshs      u,x,dp,b,a          ; preserve registers, push timeout msb
+          leau   ,x
+          ldx    #$0000
+          IFEQ   NOINTMASK
+          orcc   #IntMasks
+          ENDC
+loop@     ldb    BCKSTAT
+          bitb   #$02
+          beq    loop@
+          ldb    BCKPORT
+          stb    ,u+
+          abx
+          leay   ,-y
+          bne    loop@
+          tfr    x,y
+          ldb    #0
+          lda    #3
+timeout   leas      1,s                 ; remove timeout msb from stack
+          inca                          ; A = status to be returned in C and Z
+          ora       ,s                  ; place status information into the..
+          sta       ,s                  ; ..C and Z bits of the preserved CC
+          leay      ,x                  ; return checksum in Y
+          puls      cc,dp,x,u,pc        ; restore registers and return
+          ENDC
+          ENDC
+          ENDC
+
+          IFEQ BECKER+JMCPBCK+ARDUINO
+          IFNE BAUD38400
+*******************************************************
+* 38400 bps using 6809 code and timimg
+*******************************************************
+
+DWRead    clra                          ; clear Carry (no framing error)
+          deca                          ; clear Z flag, A = timeout msb ($ff)
+          tfr       cc,b
+          pshs      u,x,dp,b,a          ; preserve registers, push timeout msb
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+          tfr       a,dp                ; set direct page to $FFxx
+          setdp     $ff
+          leau      ,x                  ; U = storage ptr
+          ldx       #0                  ; initialize checksum
+          adda      #2                  ; A = $01 (serial in mask), set Carry
+
+* Wait for a start bit or timeout
+rx0010    bcc       rxExit              ; exit if timeout expired
+          ldb       #$ff                ; init timeout lsb
+rx0020    bita      <BBIN               ; check for start bit
+          beq       rxByte              ; branch if start bit detected
+          subb      #1                  ; decrement timeout lsb
+          bita      <BBIN
+          beq       rxByte
+          bcc       rx0020              ; loop until timeout lsb rolls under
+          bita      <BBIN
+          beq       rxByte
+          addb      ,s                  ; B = timeout msb - 1
+          bita      <BBIN
+          beq       rxByte
+          stb       ,s                  ; store decremented timeout msb
+          bita      <BBIN
+          bne       rx0010              ; loop if still no start bit
+
+* Read a byte
+rxByte    leay      ,-y                 ; decrement request count
+          ldd       #$ff80              ; A = timeout msb, B = shift counter
+          sta       ,s                  ; reset timeout msb for next byte
+rx0030    exg       a,a
+          nop
+          lda       <BBIN               ; read data bit
+          lsra                          ; shift into carry
+          rorb                          ; rotate into byte accumulator
+          lda       #$01                ; prep stop bit mask
+          bcc       rx0030              ; loop until all 8 bits read
+
+          stb       ,u+                 ; store received byte to memory
+          abx                           ; update checksum
+          ldb       #$ff                ; set timeout lsb for next byte
+          anda      <BBIN               ; read stop bit
+          beq       rxExit              ; exit if framing error
+          leay      ,y                  ; test request count
+          bne       rx0020              ; loop if another byte wanted
+          lda       #$03                ; setup to return SUCCESS
+
+* Clean up, set status and return
+rxExit    leas      1,s                 ; remove timeout msb from stack
+          inca                          ; A = status to be returned in C and Z
+          ora       ,s                  ; place status information into the..
+          sta       ,s                  ; ..C and Z bits of the preserved CC
+          leay      ,x                  ; return checksum in Y
+          puls      cc,dp,x,u,pc        ; restore registers and return
+          setdp     $00
+
+
+          ELSE
+          IFNE H6309
+*******************************************************
+* 57600 (115200) bps using 6309 native mode
+*******************************************************
+
+DWRead    clrb                          ; clear Carry (no framing error)
+          decb                          ; clear Z flag, B = $FF
+          pshs      u,x,dp,cc           ; preserve registers
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+*         ldmd      #1                  ; requires 6309 native mode
+          tfr       b,dp                ; set direct page to $FFxx
+          setdp     $ff
+          leay      -1,y                ; adjust request count
+          leau      ,x                  ; U = storage ptr
+          tfr       0,x                 ; initialize checksum
+          lda       #$01                ; A = serial in mask
+          bra       rx0030              ; go wait for start bit
+
+* Read a byte
+rxByte    sexw                          ; 4 cycle delay
+          ldw       #$006a              ; shift counter and timing flags
+          clra                          ; clear carry so next will branch
+rx0010    bcc       rx0020              ; branch if even bit number (15 cycles)
+          nop                           ; extra (16th) cycle
+rx0020    lda       <BBIN               ; read bit
+          lsra                          ; move bit into carry
+          rorb                          ; rotate bit into byte accumulator
+          lda       #0                  ; prep A for 8th data bit
+          lsrw                          ; bump shift count, timing bit to carry
+          bne       rx0010              ; loop until 7th data bit has been read
+          incw                          ; W = 1 for subtraction from Y
+          inca                          ; A = 1 for reading bit 7
+          anda      <BBIN               ; read bit 7
+          lsra                          ; move bit 7 into carry, A = 0
+          rorb                          ; byte is now complete
+          stb       ,u+                 ; store received byte to memory
+          abx                           ; update checksum
+          subr      w,y                 ; decrement request count
+          inca                          ; A = 1 for reading stop bit
+          anda      <BBIN               ; read stop bit
+          bls       rxExit              ; exit if completed or framing error
+
+* Wait for a start bit or timeout
+rx0030    clrw                          ; initialize timeout counter
+rx0040    bita      <BBIN               ; check for start bit
+          beq       rxByte              ; branch if start bit detected
+          addw      #1                  ; bump timeout counter
+          bita      <BBIN
+          beq       rxByte
+          bcc       rx0040              ; loop until timeout rolls over
+          lda       #$03                ; setup to return TIMEOUT status
+
+* Clean up, set status and return
+rxExit    beq       rx0050              ; branch if framing error
+          eora      #$02                ; toggle SUCCESS flag
+rx0050    inca                          ; A = status to be returned in C and Z
+          ora       ,s                  ; place status information into the..
+          sta       ,s                  ; ..C and Z bits of the preserved CC
+          leay      ,x                  ; return checksum in Y
+          puls      cc,dp,x,u,pc        ; restore registers and return
+          setdp     $00
+
+
+          ELSE
+*******************************************************
+* 57600 (115200) bps using 6809 code and timimg
+*******************************************************
+
+DWRead    clra                          ; clear Carry (no framing error)
+          deca                          ; clear Z flag, A = timeout msb ($ff)
+          tfr       cc,b
+          pshs      u,x,dp,b,a          ; preserve registers, push timeout msb
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+          tfr       a,dp                ; set direct page to $FFxx
+          ;setdp     $ff
+          leau      ,x                  ; U = storage ptr
+          ldx       #0                  ; initialize checksum
+          lda       #$01                ; A = serial in mask
+          bra       rx0030              ; go wait for start bit
+
+* Read a byte
+rxByte    leau      1,u                 ; bump storage ptr
+          leay      ,-y                 ; decrement request count
+          lda       <BBIN               ; read bit 0
+          lsra                          ; move bit 0 into Carry
+          ldd       #$ff20              ; A = timeout msb, B = shift counter
+          sta       ,s                  ; reset timeout msb for next byte
+          rorb                          ; rotate bit 0 into byte accumulator
+rx0010    lda       <BBIN               ; read bit (d1, d3, d5)
+          lsra
+          rorb
+          bita      1,s                 ; 5 cycle delay
+          bcs       rx0020              ; exit loop after reading bit 5
+          lda       <BBIN               ; read bit (d2, d4)
+          lsra
+          rorb
+          leau      ,u
+          bra       rx0010
+
+rx0020    lda       <BBIN               ; read bit 6
+          lsra
+          rorb
+          leay      ,y                  ; test request count
+          beq       rx0050              ; branch if final byte of request
+          lda       <BBIN               ; read bit 7
+          lsra
+          rorb                          ; byte is now complete
+          stb       -1,u                ; store received byte to memory
+          abx                           ; update checksum
+          lda       <BBIN               ; read stop bit
+          anda      #$01                ; mask out other bits
+          beq       rxExit              ; exit if framing error
+
+* Wait for a start bit or timeout
+rx0030    bita      <BBIN               ; check for start bit
+          beq       rxByte              ; branch if start bit detected
+          bita      <BBIN               ; again
+          beq       rxByte
+          ldb       #$ff                ; init timeout lsb
+rx0040    bita      <BBIN
+          beq       rxByte
+          subb      #1                  ; decrement timeout lsb
+          bita      <BBIN
+          beq       rxByte
+          bcc       rx0040              ; loop until timeout lsb rolls under
+          bita      <BBIN
+          beq       rxByte
+          addb      ,s                  ; B = timeout msb - 1
+          bita      <BBIN
+          beq       rxByte
+          stb       ,s                  ; store decremented timeout msb
+          bita      <BBIN
+          beq       rxByte
+          bcs       rx0030              ; loop if timeout hasn't expired
+          bra       rxExit              ; exit due to timeout
+
+rx0050    lda       <BBIN               ; read bit 7 of final byte
+          lsra
+          rorb                          ; byte is now complete
+          stb       -1,u                ; store received byte to memory
+          abx                           ; calculate final checksum
+          lda       <BBIN               ; read stop bit
+          anda      #$01                ; mask out other bits
+          ora       #$02                ; return SUCCESS if no framing error
+
+* Clean up, set status and return
+rxExit    leas      1,s                 ; remove timeout msb from stack
+          inca                          ; A = status to be returned in C and Z
+          ora       ,s                  ; place status information into the..
+          sta       ,s                  ; ..C and Z bits of the preserved CC
+          leay      ,x                  ; return checksum in Y
+          puls      cc,dp,x,u,pc        ; restore registers and return
+          ;setdp     $00
+
+          ENDC
+          ENDC
+          ENDC
+
diff --git a/Kernel/platform-dragon/dwwrite.s b/Kernel/platform-dragon/dwwrite.s
new file mode 100644 (file)
index 0000000..d262968
--- /dev/null
@@ -0,0 +1,196 @@
+*******************************************************
+*
+* Copied from HDB-DOS from toolshed.sf.net
+* The original code is public domain
+*
+* DWWrite
+*    Send a packet to the DriveWire server.
+*    Serial data format:  1-8-N-1
+*    4/12/2009 by Darren Atkinson
+*
+* Entry:
+*    X  = starting address of data to send
+*    Y  = number of bytes to send
+*
+* Exit:
+*    X  = address of last byte sent + 1
+*    Y  = 0
+*    All others preserved
+*
+
+
+          IFNE ARDUINO
+DWWrite   pshs      a                  ; preserve registers
+txByte
+          lda       ,x+                ; get byte from buffer
+          sta       $FF52              ; put it to PIA
+loop@     tst       $FF53              ; check status register
+          bpl       loop@              ; until CB1 is set by Arduino, continue looping
+          tst       $FF52              ; clear CB1 in status register
+          leay      -1,y                ; decrement byte counter
+          bne       txByte              ; loop if more to send
+
+          puls      a,pc                ; restore registers and return
+
+          ELSE
+
+          IFNE JMCPBCK
+DWWrite   pshs      d,cc              ; preserve registers
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+txByte
+          lda       ,x+
+          sta       $FF44
+          leay      -1,y                ; decrement byte counter
+          bne       txByte              ; loop if more to send
+
+          puls      cc,d,pc           ; restore registers and return
+
+          ELSE
+          IFNE BECKER
+          IFNDEF BCKPORT
+BCKPORT   equ   $FF42
+          ENDC
+DWWrite   pshs      d,cc              ; preserve registers
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+;          ldu       #BBOUT              ; point U to bit banger out register
+;          lda       3,u                 ; read PIA 1-B control register
+;          anda      #$f7                ; clear sound enable bit
+;          sta       3,u                 ; disable sound output
+;          fcb       $8c                 ; skip next instruction
+
+txByte
+          lda       ,x+
+          sta       BCKPORT
+          leay      -1,y                ; decrement byte counter
+          bne       txByte              ; loop if more to send
+
+          puls      cc,d,pc           ; restore registers and return
+          ENDC
+          ENDC
+          ENDC
+
+          IFEQ BECKER+JMCPBCK+ARDUINO
+          IFNE BAUD38400
+*******************************************************
+* 38400 bps using 6809 code and timimg
+*******************************************************
+
+DWWrite   pshs      u,d,cc              ; preserve registers
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+          ldu       #BBOUT              ; point U to bit banger out register
+          lda       3,u                 ; read PIA 1-B control register
+          anda      #$f7                ; clear sound enable bit
+          sta       3,u                 ; disable sound output
+          fcb       $8c                 ; skip next instruction
+
+txByte    stb       ,--u                ; send stop bit
+          leau      ,u+
+          lda       #8                  ; counter for start bit and 7 data bits
+          ldb       ,x+                 ; get a byte to transmit
+          lslb                          ; left rotate the byte two positions..
+          rolb                          ; ..placing a zero (start bit) in bit 1
+tx0010    stb       ,u++                ; send bit
+          tst       ,--u
+          rorb                          ; move next bit into position
+          deca                          ; decrement loop counter
+          bne       tx0010              ; loop until 7th data bit has been sent
+          leau      ,u
+          stb       ,u                  ; send bit 7
+          lda       ,u++
+          ldb       #$02                ; value for stop bit (MARK)
+          leay      -1,y                ; decrement byte counter
+          bne       txByte              ; loop if more to send
+
+          stb       ,--u                ; leave bit banger output at MARK
+          puls      cc,d,u,pc           ; restore registers and return
+
+          ELSE
+
+          IFNE H6309
+*******************************************************
+* 57600 (115200) bps using 6309 native mode
+*******************************************************
+
+DWWrite   pshs      u,d,cc              ; preserve registers
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+*         ldmd      #1                  ; requires 6309 native mode
+          ldu       #BBOUT+1            ; point U to bit banger out register +1
+          aim       #$f7,2,u            ; disable sound output
+          lda       #8                  ; counter for start bit and 7 data bits
+          fcb       $8c                 ; skip next instruction
+
+txByte    stb       -1,u                ; send stop bit
+tx0010    ldb       ,x+                 ; get a byte to transmit
+          lslb                          ; left rotate the byte two positions..
+          rolb                          ; ..placing a zero (start bit) in bit 1
+          bra       tx0030
+
+tx0020    bita      #1                  ; even or odd bit number ?
+          beq       tx0040              ; branch if even (15 cycles)
+tx0030    nop                           ; extra (16th) cycle
+tx0040    stb       -1,u                ; send bit
+          rorb                          ; move next bit into position
+          deca                          ; decrement loop counter
+          bne       tx0020              ; loop until 7th data bit has been sent
+          leau      ,u+
+          stb       -1,u                ; send bit 7
+          ldd       #$0802              ; A = loop counter, B = MARK value
+          leay      -1,y                ; decrement byte counter
+          bne       txByte              ; loop if more to send
+
+          stb       -1,u                ; final stop bit
+          puls      cc,d,u,pc           ; restore registers and return
+
+          ELSE
+*******************************************************
+* 57600 (115200) bps using 6809 code and timimg
+*******************************************************
+
+DWWrite   pshs      dp,d,cc             ; preserve registers
+          IFEQ      NOINTMASK
+          orcc      #IntMasks           ; mask interrupts
+          ENDC
+          ldd       #$04ff              ; A = loop counter, B = $ff
+          tfr       b,dp                ; set direct page to $FFxx
+          ;setdp     $ff
+          ldb       <$ff23              ; read PIA 1-B control register
+          andb      #$f7                ; clear sound enable bit
+          stb       <$ff23              ; disable sound output
+          fcb       $8c                 ; skip next instruction
+
+txByte    stb       <BBOUT              ; send stop bit
+          ldb       ,x+                 ; get a byte to transmit
+          nop
+          lslb                          ; left rotate the byte two positions..
+          rolb                          ; ..placing a zero (start bit) in bit 1
+tx0020    stb       <BBOUT              ; send bit (start bit, d1, d3, d5)
+          rorb                          ; move next bit into position
+          exg       a,a
+          nop
+          stb       <BBOUT              ; send bit (d0, d2, d4, d6)
+          rorb                          ; move next bit into position
+          leau      ,u
+          deca                          ; decrement loop counter
+          bne       tx0020              ; loop until 7th data bit has been sent
+
+          stb       <BBOUT              ; send bit 7
+          ldd       #$0402              ; A = loop counter, B = MARK value
+          leay      ,-y                 ; decrement byte counter
+          bne       txByte              ; loop if more to send
+
+          stb       <BBOUT              ; leave bit banger output at MARK
+          puls      cc,d,dp,pc          ; restore registers and return
+          ;setdp     $00
+
+          ENDC
+          ENDC
+          ENDC
+