From 252331ae5ce813ed0ad31ffdaa9b93f0449cf206 Mon Sep 17 00:00:00 2001 From: Tormod Volden Date: Sun, 29 Mar 2015 15:13:21 +0200 Subject: [PATCH] dragon: Add DriveWire support 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 --- Kernel/platform-dragon/Makefile | 5 +- Kernel/platform-dragon/README | 11 +- Kernel/platform-dragon/devdw.c | 89 ++++++++ Kernel/platform-dragon/devdw.h | 14 ++ Kernel/platform-dragon/devices.c | 6 + Kernel/platform-dragon/drivewire.s | 139 ++++++++++++ Kernel/platform-dragon/dw.def | 70 ++++++ Kernel/platform-dragon/dwread.s | 341 +++++++++++++++++++++++++++++ Kernel/platform-dragon/dwwrite.s | 196 +++++++++++++++++ 9 files changed, 865 insertions(+), 6 deletions(-) create mode 100644 Kernel/platform-dragon/devdw.c create mode 100644 Kernel/platform-dragon/devdw.h create mode 100644 Kernel/platform-dragon/drivewire.s create mode 100644 Kernel/platform-dragon/dw.def create mode 100644 Kernel/platform-dragon/dwread.s create mode 100644 Kernel/platform-dragon/dwwrite.s diff --git a/Kernel/platform-dragon/Makefile b/Kernel/platform-dragon/Makefile index c490d940..d84c5e82 100644 --- a/Kernel/platform-dragon/Makefile +++ b/Kernel/platform-dragon/Makefile @@ -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 \ diff --git a/Kernel/platform-dragon/README b/Kernel/platform-dragon/README index 1b66ee81..574ce2ba 100644 --- a/Kernel/platform-dragon/README +++ b/Kernel/platform-dragon/README @@ -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 index 00000000..ae3fc914 --- /dev/null +++ b/Kernel/platform-dragon/devdw.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +#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 index 00000000..d7b93583 --- /dev/null +++ b/Kernel/platform-dragon/devdw.h @@ -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__ */ + diff --git a/Kernel/platform-dragon/devices.c b/Kernel/platform-dragon/devices.c index fe99fe2c..a188243c 100644 --- a/Kernel/platform-dragon/devices.c +++ b/Kernel/platform-dragon/devices.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -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 index 00000000..babebeb9 --- /dev/null +++ b/Kernel/platform-dragon/drivewire.s @@ -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 index 00000000..677f4c71 --- /dev/null +++ b/Kernel/platform-dragon/dw.def @@ -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 index 00000000..1b4c587b --- /dev/null +++ b/Kernel/platform-dragon/dwread.s @@ -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