zeta-v2: Add floppy support (stolen from P112)
authorSergey Kiselev <skiselev@gmail.com>
Wed, 11 Mar 2015 07:22:44 +0000 (00:22 -0700)
committerSergey Kiselev <skiselev@gmail.com>
Wed, 11 Mar 2015 07:22:44 +0000 (00:22 -0700)
Kernel/platform-zeta-v2/Makefile
Kernel/platform-zeta-v2/README
Kernel/platform-zeta-v2/bootrom.s
Kernel/platform-zeta-v2/config.h
Kernel/platform-zeta-v2/devfd.c [new file with mode: 0644]
Kernel/platform-zeta-v2/devfd.h [new file with mode: 0644]
Kernel/platform-zeta-v2/devfd_hw.s [new file with mode: 0644]
Kernel/platform-zeta-v2/devices.c
Kernel/platform-zeta-v2/fuzix.lnk [new file with mode: 0644]
Kernel/platform-zeta-v2/kernel.def
Kernel/platform-zeta-v2/main.c

index 210bd68..50046b5 100644 (file)
@@ -1,6 +1,6 @@
 ASRCS = crt0.s tricks.s commonmem.s zeta-v2.s monitor.s
-ASRCS += ds1302-n8vem.s devrd_hw.s
-CSRCS = devices.c main.c devtty.c devrd.c
+ASRCS += ds1302-n8vem.s devfd_hw.s devrd_hw.s
+CSRCS = devices.c main.c devtty.c devfd.c devrd.c
 DISCARD_CSRCS = discard.c
 DISCARD_DSRCS = ../dev/ds1302_discard.c
 DSRCS = ../dev/devsd.c ../dev/mbr.c ../dev/blkdev.c ../dev/ds1302.c
index 2d0b660..7dadddb 100644 (file)
@@ -10,8 +10,8 @@ Supported hardware:
 
 Memory allocation (16 KiB pages):
 - ROM pages:   0 - 31
-  - Kernel image:      0 - 2 - copied by bootrom.s to pages 32 - 34
-  - RAM disk image:    3 - 19 - copied by bootrom.s to pages 48 - 63
+  - Kernel image:      0 - 3 - copied by bootrom.s to pages 32 - 35
+  - RAM disk image:    4 - 19 - copied by bootrom.s to pages 48 - 63
 - RAM pages:   32 - 63
   - Kernel pages:      32 - 34
   - Common page:       35
@@ -107,8 +107,8 @@ chmod 0755 umount
 exit
 
 5. Create ROM image:
-dd if=fuzix.rom of=fuzix_48k.rom bs=48k count=1 conv=sync
-cat fuzix_48k.rom zeta_v2_rootfs.img > fuzix_zeta_v2_bootfs.rom
+dd if=fuzix.rom of=fuzix_64k.rom bs=64k count=1 conv=sync
+cat fuzix_64k.rom zeta_v2_rootfs.img > fuzix_zeta_v2_bootfs.rom
 
 6. Program the image (fuzix_zeta_v2_bootfs.rom) to the Flash ROM using an
 EPROM programmer
index ee95c87..3099585 100644 (file)
@@ -15,7 +15,7 @@ start:
                out (MPGENA),a          ; enable paging
 
                ; copy FUZIX kernel to RAM
-               ; 3 pages, starting from ROM page 0, RAM page 32
+               ; 4 pages, starting from ROM page 0, RAM page 32
                xor a
 kernel_copy:
                out (MPGSEL_1),a        ; map ROM page to bank #1
@@ -26,22 +26,22 @@ kernel_copy:
                ld bc,#0x4000           ; count - 16 KiB
                ldir                    ; copy it
                sub a,#31               ; next ROM page = RAM page - 32 + 1
-               cp #3                   ; are we there yet (RAM page == 3?)
+               cp #4                   ; are we there yet (RAM page == 4?)
                jr nz,kernel_copy
 
                ; copy data to RAM disk
-               ; 16 pages, starting from ROM page 3, RAM page 48
-               ld a,#3
+               ; 16 pages, starting from ROM page 4, RAM page 48
+               ld a,#4
 ramdisk_copy:
                out (MPGSEL_1),a        ; map ROM page to bank #1
-               add #45                 ; RAM page = ROM page + 45
+               add #44                 ; RAM page = ROM page + 44
                out (MPGSEL_2),a        ; map RAM page to bank #2
                ld hl,#0x4000           ; source - bank #1 offset
                ld de,#0x8000           ; destination - bank #2 offset
                ld bc,#0x4000           ; count - 16 KiB
                ldir                    ; copy it
-               sub #44                 ; next ROM page = RAM page - 45 + 1
-               cp #19                  ; are we there yet (RAM page == 3 + 16?)
+               sub #43                 ; next ROM page = RAM page - 44 + 1
+               cp #20                  ; are we there yet (RAM page == 4 + 16?)
                jr nz,ramdisk_copy
 
                ; scary... switching memory bank under our feet
index 55b3094..01e8159 100644 (file)
@@ -47,6 +47,9 @@
 #define CONFIG_RTC
 #define CONFIG_RTC_INTERVAL 30 /* deciseconds between reading RTC seconds counter */
 
+/* Floppy support */
+#define CONFIG_FLOPPY          /* # define CONFIG_FLOPPY to enable floppy */
+
 /* Optional ParPortProp board connected to PPI */
 //#define CONFIG_PPP           /* #define CONFIG_PPP to enable as tty3 */
 
diff --git a/Kernel/platform-zeta-v2/devfd.c b/Kernel/platform-zeta-v2/devfd.c
new file mode 100644 (file)
index 0000000..3479858
--- /dev/null
@@ -0,0 +1,168 @@
+/***************************************************************
+   UZI (Unix Z80 Implementation) Kernel:  devflop.c
+----------------------------------------------------------------
+ Adapted from UZI By Doug Braun, and UZI280 by Stefan Nitschke
+            Copyright (C) 1998 by Harold F. Bower
+       Portions Copyright (C) 1995 by Stefan Nitschke
+****************************************************************/
+/* 2015-01-17 Will Sowerbutts: Ported from UZI-180 to Fuzix */
+/* Assumes 512-byte sectors, 3.5" 1.44 MB formatted disks   */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include "devfd.h"
+
+/* functions implemented in devfd2.s */
+extern int devfd_init(uint8_t minor);
+extern int devfd_read(uint8_t minor);
+extern int devfd_write(uint8_t minor);
+
+/* variables in devfd2.s */
+extern uint8_t devfd_track, devfd_sector, devfd_error, devfd_userbuf;
+extern char *devfd_buffer;
+
+/* D D D D D D D D               Format Byte
+   7 6 5 4 3 2 1 0
+   | | | | | | +-+----- Sector Size: 000=128, 001=256, 010=512, 011=1024 bytes
+   | | | | +-+--------- Disk Size: 00=fixed disk, 01=8", 10=5.25", 11=3.5"
+   | | | +------------- 0 = Normal 300 RPM MFM,    1 = "High-Density" Drive
+   | | +--------------- 0 = Single-Sided,          1 = Double-Sided
+   | +----------------- 0 = Double-Density,        1 = Single-Density
+   +------------------- 0 = 250 kbps (normal MFM), 1 = 500 kbps (Hi-Density) */
+
+#define IBMPC3  0xAE    /* 10101110B HD,  DD, DS, 3.5",   512-byte Sctrs (1.44 MB) */
+#define UZIHD3  0xAF    /* 10101111B HD,  DD, DS, 3.5",  1024-byte Sctrs (1.76 MB) */
+#define IBMPC5  0xAA    /* 10101010B HD,  DD, DS, 5.25",  512-byte Sctrs (1.2 MB)  */
+#define UZIHD5  0xAB    /* 10101011B HD,  DD, DS, 5.25", 1024-byte Sctrs (1.44 MB) */
+#define DSQD3   0x2F    /* 00101111B MFM, DD, DS, 3.5",  1024-byte Sctrs (800 KB)  */
+#define DSDD3   0x2E    /* 00101110B MFM, DD, DS, 3.5",   512-byte Sctrs (800 KB)  */
+#define DSQD5   0x2B    /* 00101011B MFM, DD, DS, 5.25", 1024-byte Sctrs (800 KB)  */
+#define DSDD5   0x2A    /* 00101010B MFM, DD, DS, 5.25",  512-byte Sctrs (800 KB)  */
+
+struct {
+       uint8_t logged;     /* logged (0xff), unlogged (0) */
+       uint8_t cbyte0;     /* bits 7-4: step rate (4ms), bits 3-0: HUT (240ms) */
+       uint8_t cbyte1;     /* head load time in 4ms steps (0=infinite) */
+       uint8_t gap3;       /* gap3 (size 512 = 27, 1024 = 13) */
+       uint8_t spt;        /* physical sectors per track */
+       uint8_t sector1;    /* first sector number */
+       uint8_t format;     /* format byte */
+       uint8_t spinup;     /* spinup (1/20-secs) */
+       uint8_t curtrk;     /* current tranck number */
+       uint8_t ncyl;       /* number of cylinders x heads */
+} devfd_dtbl[4] = {
+    { 0, 0xCF, 1, 27, 18, 1, IBMPC3, 10, 0, 160 },
+    { 0, 0xCF, 1, 27, 18, 1, IBMPC3, 10, 0, 160 },
+    { 0, 0xCF, 1, 27, 18, 1, IBMPC3, 10, 0, 160 },
+    { 0, 0xCF, 1, 27, 18, 1, IBMPC3, 10, 0, 160 },
+};
+
+static int fd_transfer(bool rwflag, uint8_t minor, uint8_t rawflag)
+{
+       uint8_t nblocks, blocks;
+       uint16_t firstblk;
+       uint16_t retc;
+       irqflags_t irq;
+
+       switch(rawflag){
+               case 0:
+                       nblocks = 1;
+                       devfd_buffer = udata.u_buf->bf_data;
+                       devfd_userbuf = 0;
+                       firstblk = udata.u_buf->bf_blk;
+                       break;
+               case 1:
+                       nblocks = udata.u_count >> BLKSHIFT;
+                       devfd_buffer = udata.u_base;
+                       devfd_userbuf = 0xFF;
+                       firstblk = udata.u_offset >> BLKSHIFT;
+                       break;
+#ifdef SWAPDEV
+               case 2:
+                       nblocks = swapcnt >> 9;
+                       devfd_buffer = swapbase;
+                       devfd_userbuf = 0xFF;
+                       firstblk = swapblk;
+                       break;
+#endif
+               default:
+                       goto failout;
+       }
+
+       devfd_track = firstblk / devfd_dtbl[minor].spt;
+       devfd_sector = firstblk % devfd_dtbl[minor].spt; /* Base 0 Sect # */
+       devfd_error = 0;
+
+       if (devfd_track >= devfd_dtbl[minor].ncyl){
+               goto failout;
+       }
+
+       blocks = nblocks;
+       for (;;)
+       {
+               irq = di();
+               if (rwflag)
+                       retc = devfd_read(minor);
+               else
+                       retc = devfd_write(minor);
+               irqrestore(irq);
+
+               if (retc)
+                       break;
+
+               if(--nblocks == 0)
+                       break;
+
+               if (++devfd_sector > devfd_dtbl[minor].spt)
+               {
+                       devfd_sector = 0;
+                       ++devfd_track;
+               }
+               devfd_buffer += 128 << (devfd_dtbl[minor].format & 3);
+       }
+
+       if (devfd_error) {
+               kprintf("fd_%s: error %d track %d sector %d\n",
+                               rwflag ? "read" : "write", devfd_error, devfd_track, devfd_sector);
+               panic("fd_transfer");
+       }
+
+       if (retc) 
+               goto failout;
+
+       return blocks;
+failout:
+       udata.u_error = ENXIO;
+       return -1;
+}
+
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       flag; /* unused */
+       return fd_transfer(true, minor, rawflag);
+}
+
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       flag; /* unused */
+       return fd_transfer(false, minor, rawflag);
+}
+
+int fd_open(uint8_t minor, uint16_t flags)
+{
+       flags; /* unused */
+
+       if (devfd_init(minor)) {
+               udata.u_error = ENXIO;
+               return -1;
+       }
+
+       return 0;
+}
+
+int fd_close(uint8_t minor)
+{
+       devfd_dtbl[minor].logged = 0;   /* Mark Drive as logged out */
+       return 0;
+}
diff --git a/Kernel/platform-zeta-v2/devfd.h b/Kernel/platform-zeta-v2/devfd.h
new file mode 100644 (file)
index 0000000..2019c57
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __DEVFD_DOT_H__
+#define __DEVFD_DOT_H__
+
+/* public interface */
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int fd_open(uint8_t minor, uint16_t flags);
+int fd_close(uint8_t minor);
+void fd_tick(void);
+
+#endif
diff --git a/Kernel/platform-zeta-v2/devfd_hw.s b/Kernel/platform-zeta-v2/devfd_hw.s
new file mode 100644 (file)
index 0000000..280fe03
--- /dev/null
@@ -0,0 +1,656 @@
+;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+; D-X Designs Pty Ltd P112 Floppy disk Routines
+;       Copyright (C) 1998 by Harold F. Bower
+;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+; 2015-01-17 Will Sowerbutts: Ported to sdas/Fuzix from UZI-180
+
+        .module devfd_hw
+
+        ; imported symbols
+        .globl map_kernel
+        .globl map_process_always
+        .globl _devfd_dtbl
+
+        ; exported sybols
+        .globl _devfd_init
+        .globl _devfd_read
+        .globl _devfd_write
+        .globl _devfd_track
+        .globl _devfd_sector
+        .globl _devfd_error
+        .globl _devfd_buffer
+        .globl _devfd_userbuf
+        .globl _fd_tick
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+;------------------------------------------------------------------------------
+        .area _CODE
+
+;    092        - Drive Control Register        (Write Only)
+;       7 6 5 4 3 2 1 0
+;       | | | | | | +-+-- Drive (00=0, 01=1, 10=2, 11=3)
+;       | | | | | +------ 1 = Normal Opn, 0 = Reset Controller
+;       | | | | +-------- 1 = Enable DMA Pins, 0 = Disable DRQ,DAK,INT pins
+;       | | | +---------- 1 = Enable Drive 0 Motor
+;       | | +------------ 1 = Enable Drive 1 Motor
+;       | +-------------- 1 = Enable Drive 2 Motor
+;       +---------------- 1 = Enable Drive 3 Motor
+
+;    FDC_MSR    - Main Status Register (Read)
+;       7 6 5 4 3 2 1 0                         (Write)
+;
+;       7 6 5 4 3 2 1 0                         (Read)
+;       | | | | +-+-+-+-- Drives Seeking (0=B0 Set, 1=B1 Set,.. 3=B3 Set)
+;       | | | +---------- 1 = Command In Progress, 0 = Command Ended
+;       | | +------------ 1 = Non-DMA Execution,   0 = DMA Execution
+;       | +-------------- 1 = Read,                0 = Write
+;       +---------------- 1 = Request for Master,  0 = Internal Execution
+;
+;    FDC_DATA   - Data/Command Register         (Read/Write)
+;                               (Byte Writes/Reads)
+;
+;    FDC_CCR    - Data Rate Register (Write)
+;       7 6 5 4 3 2 1 0                         (Write)
+;       | | | | | | +-+-- 00=500 kb/s, RPM/LC Hi, 01=250/300 kb/s (RPM/LC Lo)
+;       | | | | | |       10=250 kb/s, RPM/LC Lo, 11=1000 kb/s (RPM/LC Hi/Lo)
+;       +-+-+-+-+-+------  (Not Used)
+;
+;-------------------------------------------------------------
+MONTIM  .equ    250             ; Motor On time (Seconds * TICKSPERSEC)
+
+; Offsets into _devfd_dtbl
+oFLG    .equ    0               ; logged:  0 = Not Logged, 1 = Drive Logged
+oPRM1   .equ    1               ; cbyte0:  Step Rate (B7-4), HUT (3-0)
+oPRM2   .equ    2               ; cbyte1:  Hd Load in 4mS steps (0=infinite)
+oGAP3   .equ    3               ; gap3:    Gap 3 Length for Read
+oSPT    .equ    4               ; spt:     Sectors-per-Track
+oSEC1   .equ    5               ; sector1: First Sector Number
+oFMT    .equ    6               ; format:  Bit-mapped Format byte
+oSPIN   .equ    7               ; spinup:  Spinup delay (1/20-secs)
+oTRK    .equ    8               ; curtrk:  Current Head Position (Track)
+oNCYL   .equ    9               ; ncyl:    Number of cylinders
+TBLSIZ  .equ    10              ; sizeof() entry in _devfd_dtbl
+
+;-------------------------------------------------------------
+; Determine if the controller exists and a drive is attached
+;       fdInit (int minor);
+; Enter: Drive Minor # is on Stack
+; Exit : HL = 0 if All is Ok, Non-Zero if Error
+
+_devfd_init:
+        XOR     A
+        LD      (motim),A       ; Mark Motors as initially OFF
+        LD      (hd),A          ;  and initially Head #0
+
+        POP     HL              ; Return Addr
+        POP     BC              ;  minor (in C)
+        PUSH    BC              ;   Keep on Stack for Exit
+        PUSH    HL
+        LD      A,C
+        LD      (drive),A       ; Save Desired Device
+        CP      #4              ; Legal?
+        JR      NC,NoDrv        ; ..Exit if Error
+        CALL    ActivA          ; Else force Reset (B2=0)
+        LD      B,#0
+indel1: DJNZ    indel1          ;    (settle)
+        CALL    Activ8          ;  then bring out of Reset
+indel2: DJNZ    indel2          ;    (settle, B already =0)
+        IN      A,(FDC_MSR)
+        CP      #0x80           ; Do we have correct Ready Status?
+        JR      NZ,NoDrv        ; ..exit Error if Not
+
+        LD      A,(drive)
+        CALL    GetPrm          ; Pt to this drive's table entry
+        PUSH    HL
+        POP     IY
+        LD      oFLG(IY), #0    ; Ensure drive is Unlogged
+        CALL    Spec            ; Set Controller Params
+        JR      C,NoDrv         ; ..Error if TimeOut, Else..
+        CALL    Recal           ; Recalibrate (home) Drive
+        JR      NZ,NoDrv        ; ..Error if it failed
+        LD      oFLG(IY), #1    ; Mark drive as active
+        LD      HL,#0           ; Load Ok Status
+        RET
+
+NoDrv:  LD      HL,#0xFFFF      ; Set Error Status
+        RET
+
+;-------------------------------------------------------------
+; This routine Reads/Writes data from buffer trying up to 4 times
+; before giving up.  If an error occurs after the next-to-last
+; try, the heads are homed to force a re-seek.
+;
+; Enter: Drive Minor # is on Stack.  Entry Point sets Read/Write Flag
+; Exit :  A = 0, Zero Set if Ok, A <> 0, Zero Reset if Errors
+;        (also returns H = 0 and L set to A for compatibilty with C code)
+; Uses : AF,HL
+
+_devfd_read:
+        LD      A,#1
+        .db 0x21 ;..Trash HL, fall thru..
+_devfd_write:
+        LD      A,#0            ; has to be two bytes -- do not optimise to xor a!
+        LD      (rdOp),A
+
+        POP     HL              ; Return Addr
+        POP     BC              ;  minor (->C)
+        PUSH    BC              ;   Keep on Stack for Exit
+        PUSH    HL
+        LD      A,C
+        LD      (drive),A       ; Save Desired Device
+;;      CP      4               ; Legal?
+;;      JR      NC,NoDrv        ; ..Exit if Error
+
+        CALL    Setup           ; Set up subsystem
+;;--    LD      HL,buffer       ;  Point to the host buffer
+;;--    LD      (actDma),HL     ;   and set Memory Pointer
+
+        LD      A,#4            ; Get the maximum retry count
+Rwf1:   LD      (rwRtry),A
+        LD      D,#0xFF         ;  (Verify needed)
+        CALL    SEEK            ; Try to seek to the desired track
+        JR      NZ,Rwf2         ; ..jump if No Good
+
+        LD      A,(rdOp)
+        OR      A               ; Read operation?
+        LD      A,#0x05         ; Load DP8473 Write Command
+        JR      Z,SWrite        ; No, must be Write
+        INC     A               ; (A=06H) Load DP8473 Read Command
+SWrite: OR      #0x40           ;  Set MFM Mode Bit
+        PUSH    BC              ;   Save Regs
+        LD      C,A             ;  Save
+        LD      B,#9            ; Read/Write Comnds are 9 bytes
+
+        LD      A,(eot)         ; Get Last Sctr #
+        PUSH    AF              ;  (save for Exit)
+        LD      A,(sect)        ; Get Desired Sector #
+        LD      (eot),A         ;  make last to Read only one Sector
+
+;;--    LD      HL,(actDma)     ; Get actual DMA Addr
+        ld      hl,(_devfd_buffer)      ;;--
+        CALL    FdCmd           ; Execute Read/Write
+
+        POP     AF              ; Restore Last Sctr #
+        LD      (eot),A         ;  to Comnd Blk
+
+        LD      A,(st1)         ; Get Status Reg 1
+        AND     #0x34           ; Return Any Error Bits
+        POP     BC              ; Restore Regs
+        LD      (_devfd_error),A        ;  (store Error bits)
+        JR      Z,FhdrX         ; ..jump to return if No Errors
+
+Rwf2:   LD      A,(rwRtry)      ; Get retry count
+        CP      #2              ; Are we on Next to last try?
+        CALL    Z,Recal         ;  Return to Track 0 if so
+        LD      A,(rwRtry)      ;   and re-fetch try count
+        DEC     A               ; Do we have more retries left?
+        JR      NZ,Rwf1         ; ..jump to try again if more tries remain
+
+        OR      #0xFF           ; Else show Error
+FhdrX:  LD      L,A
+        LD      H,#0
+        RET                     ;   and Exit
+
+;-------------------------------------------------------------
+; SPEC - Do a Specify Command, setting Step Rate and Head
+;  Load/Unload Time.  Settings require tailoring to Drive.
+;
+; Enter: IY -> Drive Table entry for current drive
+; Exit : Nothing
+; Uses : AF,BC
+
+Spec:   CALL    WRdyT           ; Wait for RQM (hope DIO is Low!), Disable Ints
+        RET     C               ; ..Error if Timed Out
+        LD      A,#0x03         ; Do an FDC Specify Command
+        OUT     (FDC_DATA),A
+
+        CALL    WRdyT
+        RET     C               ; ..Error if Timed Out
+        LD      A,oPRM1(IY)     ;  first Rate Byte (Step Rate, HUT)
+        OUT     (FDC_DATA),A
+
+        CALL    WRdyT
+        RET     C               ; ..Error if Timed Out
+        LD      A,oPRM2(IY)     ; Get Head Load Time
+        ADD     A,A             ;  Shift value left (doubles count)
+        INC     A               ;   Set LSB for Non-DMA Operation
+        OUT     (FDC_DATA),A
+        XOR     A               ;  Return Ok Flag
+        RET
+
+;-------------------------------------------------------------
+; RECAL  Recalibrate Current "drive" (moves heads to track 0).
+; Enter : IY -> Current Drive Table Entry
+;         Variable "drive" set to desired floppy unit
+; Return:  A = 0 if Ok, NZ if Error.  Flags reflect A
+; Uses  : AF            All other Registers Preserved/Not Affected
+;
+; NOTE: BC Must be preserved by this routine.
+
+Recal:  LD      A,(hd)          ; Get head #
+        ADD     A,A
+        ADD     A,A             ;  Shift to B3
+        PUSH    HL              ;   (preserve regs)
+        LD      HL,#drive
+        OR      (HL)            ;   add Drive bits
+        POP     HL              ;    (restore regs)
+
+        LD      (hdr),A         ;   in Command Block
+        LD      A,#3            ; Give this 3 chances to Home
+Recal1: LD      (retrys),A
+        PUSH    BC              ; Save needed regs
+        PUSH    HL
+        LD      BC,#(2*256+7)   ;   (2-byte Recalibrate Comnd = 07H)
+        CALL    FdCmd           ;  execute Recalibrate
+        CALL    FdcDn           ; Clear Pending Ints, Wait for Seek Complete
+        POP     HL              ;   (restore regs)
+        POP     BC
+        AND     #0x10           ; Homed?  (B4=1 if No Trk0 found)
+        JR      Z,RecOk         ; ..jump to Store if Ok
+        LD      A,(retrys)
+        DEC     A               ; Any trys left?
+        JR      NZ,Recal1       ; ..loop if So
+        DEC     A               ; Else set Error Flag (0-->FF)
+        RET
+
+RecOk:  XOR     A               ; Get a Zero (track / flag)
+        LD      oTRK(IY),A      ;  Set in Table
+        RET                     ;   and return
+
+;-------------------------------------------------------------
+; READID - Read the first Valid Address Mark on a track.
+;
+; Enter : "hdr" byte set in Command Blk
+; Return:  A = 0 if Ok, NZ if Error.  Flags reflect A
+; Uses  : AF            All other Registers Preserved/Not Affected
+
+ReadID: LD      A,#0x4a         ; Load ReadID Command + MFM Mode byte
+        PUSH    BC              ; Save regs
+        LD      B,#2            ;  two bytes in ReadID Command
+        LD      C,A             ;   move Command to C
+        CALL    FdCmd           ; Activate DP8473 FDC
+
+        LD      A,(st1)         ; Get Status Reg 1
+        AND     #0x25           ;  Return Any Error Bits
+        POP     BC              ;   Restore regs
+        RET                     ;  ..and quit
+
+;-------------------------------------------------------------
+; SETUP - Set parameters necessary to Read/Write from Active Drive
+; Enter: Variable "drive" set to current Drive (0..3)
+;        Variables _devfd_track and _devfd_sector set to desired block address
+; Exit : IY -> Drive's Table entry
+; Uses : AF,BC,HL
+
+Setup:  LD      A,(drive)
+        PUSH    AF
+        CALL    GetPrm          ; Pt to Current Drive's Table
+        PUSH    HL
+        POP     IY
+        POP     BC
+        LD      A,(active)      ; Get current Activation Byte
+        AND     #0xf0           ;  keep only motors
+        OR      B               ;   add drive bits
+        CALL    Activ8          ;    save new byte and activate FDC
+        LD      A,(_devfd_track)        ; Get Host Track #
+        SRL     A               ;  Div by 2 (LSB to Carry)
+        LD      (trk),A         ;   Physical Track # to Comnd Blk
+        LD      A,#0
+        ADC     A,A             ; LSB becomes Head #
+        LD      (hd),A          ;  save in Comnd Blk
+        ADD     A,A
+        ADD     A,A             ; Shift to B3
+        LD      HL,#drive
+        OR      (HL)            ;  add Drive bits
+        LD      (hdr),A         ;   Save in Comnd Blk
+        LD      A,oGAP3(IY)
+        LD      (gpl),A         ; Set Gap3 Length
+        LD      A,oSPT(IY)
+        LD      (eot),A         ;  Final Sector # on Trk
+        LD      A,oFMT(IY)
+        AND     #3              ; B0/1 of Format byte is Sector Size
+        LD      (rsz),A         ;  save in Comnd Blk
+        LD      A,#0xFF
+        LD      (dtl),A         ;   Set Data Length code
+        LD      A,(_devfd_sector)
+        ADD     A,oSEC1(IY)     ;    Offset Sector # (base 0) by 1st Sector #
+        LD      (sect),A        ;     set in Comnd Blk
+
+        XOR A                   ;  (Preset Hi 500 kbps, 3.5 & 5.25" Rate)
+        BIT     7,oFMT(IY)      ; Hi (500 kbps) Speed?
+        JR      NZ,StSiz0       ; ..jump if Hi-Density/Speed to Set if Yes
+        LD      A,oFMT(IY)
+        AND     #0x0c           ; Else Get Drive size
+        CP      #0x08           ; 5.25"?
+        LD      A,#0x02         ;  (Prepare for 250 kbps)
+        JR      NZ,StSiz0       ; ..jump if Not 5.25" w/Rate Set
+        BIT     4,oFMT(IY)      ; Hi-Density capable drive?
+        LD      A,#0x02         ;  (Prepare for 250 kbps)
+        JR      Z,StSiz0        ; ..jump if No
+        LD      A,#0x01         ; Else set to 300 kbps (@360 rpm = 250kbps)
+StSiz0: OUT     (FDC_CCR),A     ; Set Rate in FDC Reg
+        LD      D,A             ;   preserve Rate bits
+; FIXME: Sergey - delay should be just a constant?
+;        IN0     A,(0x1F)        ; Read Z80182 CPU Cntrl Reg (B7=1 if Hi Speed)
+;        RLA                     ;  Speed to Bit Carry..Turbo?
+        LD      A,#(CPU_CLOCK_KHZ/1000)         ;   (Get Processor Rate in MHz)
+;        JR      C,StSiz1        ;  ..jump if Turbo for longer delay
+        SRL     A               ;  Else divide rate by 2
+StSiz1: INC     D
+        DEC     D               ; 500 kb/s (Hi-Speed) Rate (D=0)?
+        JR      NZ,StSiz2       ; ..jump if Not
+        LD      A,#1            ;  Else minimum delay for "High-Speed"
+StSiz2: LD      (dlyCnt),A      ;   save delay count
+        RET
+
+;-------------------------------------------------------------
+; SEEK - Set the Track for disk operations and seek to it.
+;
+; Enter :  A = Desired Track Number
+;          D = Verify flag (0=No, FF=Yes)
+; Return:  A = 0, Zero Flag Set (Z) if Ok, A <> 0 Zero Clear (NZ) if Error
+; Uses  : AF            All other Registers Preserved/Not Affected
+
+SEEK:   PUSH    HL              ; Save Regs used here
+        PUSH    DE
+        PUSH    BC
+
+        LD      A,(trk)         ;  Get Track #
+        CP      oTRK(IY)        ; Is desired Track same as last logged?
+        LD      oTRK(IY),A      ;  (set as if we made it there)
+        JR      NZ,SEEKNV       ; ..jump if Not Same
+        INC     D               ; Else Set to No Verify (FF->0)
+SEEKNV: LD      A,#4            ; Get the maximum Retry Count
+SEEK1:  LD      (retrys),A      ;  save remaining Retry Count
+        LD      BC,#(3*256+0x0F);   (3-byte Seek Command = 0FH)
+        CALL    FdCmd           ; Execute the Seek
+        CALL    FdcDn           ; Clear Pending Int, wait for Seek Complete
+
+        AND     #0xE0
+        CP      #0x20
+        JR      NZ,SEEK2        ;;
+        
+        AND     #0x40           ; Set NZ if Abnormal Termination
+
+        LD      B,A             ;; Save Seek Status
+        LD      A,(trk)         ;; Check track #
+        CP      C               ;;  Same track?
+        JR      NZ,SEEK2        ;;   Jump to Retry if NOT
+        LD      A,B             ;; Restore Seek Status
+
+        INC     D               ; Are we Verifying (FF -> 0)?
+        CALL    Z,ReadID        ;   Read next ID Mark if So
+        DEC     D               ;    (Correct for Test, 0 -> FF)
+
+        OR      A               ; Set Status (Seek Status if No ReadID)
+        JR      Z,SEEKX         ; ..exit if Ok
+
+SEEK2:  LD      A,(retrys)      ; Else get trys remaining
+        DEC     A               ; Any left (80-track could need two)?
+        JR      NZ,SEEK1        ; ..loop to try again if More
+        DEC     A               ; Else set Error Flag (0->FF)
+
+SEEKX:  POP     BC              ; Restore Regs
+        POP     DE
+        POP     HL
+        RET
+
+
+;-------------------------------------------------------------
+; Check for Proper Termination of Seek/Recalibrate Actions by
+;  executing a Check Interrupt Command returning ST0 in A.
+; Enter: None.  Used after Seek/Recalibrate Commands
+; Exit : A = ST0 Result Byte, C = PCN result byte
+; Uses : AF and C.  All other registers preserved/unused
+
+FdcDn:  PUSH    HL              ; Don't alter regs
+FdcDn0: CALL    WRdy1
+        LD      A,#8            ; Sense Interrupt Status Comnd
+        OUT     (FDC_DATA),A
+        CALL    WRdy1
+        IN      A,(FDC_DATA)    ; Get first Result Byte (ST0)
+        LD      L,A
+        CP      #0x80           ; Invalid Command?
+        JR      Z,FdcDn0        ; ..jump to exit if So
+        CALL    WRdy1
+        IN      A,(FDC_DATA)          ; Read Second Result Byte (Trk #)
+        LD      C,A             ; ..into C
+        LD      A,L
+        BIT     5,A             ; Command Complete?
+        JR      Z,FdcDn0        ; ..loop if Not
+        POP     HL
+        RET
+
+;-------------------------------------------------------------
+; MOTOR CONTROL.  This routine performs final selection of
+; the drive control latch and determines if the Motors are
+; already spinning.  If they are off, then the Motors are
+; activated and the spinup delay time in tenths-of-seconds
+; is performed before returning.
+;
+; Enter : None
+; Return: None
+; Uses  : HL.  Remaining Registers Preserved/Not Affected
+
+Motor:  PUSH    AF              ; Save Regs
+        LD      A,(motim)       ; Get remaining Seconds
+        OR      A               ; Already On?
+        LD      A,#MONTIM       ;  (get On Time)
+        LD      (motim),A       ;   always reset
+        JR      NZ,MotorX       ; ..exit if already running
+        PUSH    BC
+        LD      A,(hdr)         ; Get current Drive
+        OR      #0xF4           ;   Set All Motors On and Controller Active
+        CALL    Activ8          ;     Do It!
+        LD      A,(drive)       ; Get Current drive
+        CALL    GetPrm          ;  Pt to Param table
+        LD      BC,#oSPIN
+        ADD     HL,BC           ;   offset to Spinup Delay
+        LD      A,(HL)          ;    Get value
+        LD      (mtm),A         ;     to GP Counter
+        EI                      ; Ensure Ints are ABSOLUTELY Active..
+MotoLp: LD      A,(mtm)         ;  ..otherwise, loop never times out!
+        OR      A               ; Up to Speed?
+        JR      NZ,MotoLp       ; ..loop if Not
+        DI                      ; No Ints now..
+        POP     BC
+MotorX: POP     AF              ; Restore Reg
+        RET
+
+;-------------------------------------------------------------
+; Wait for FDC RQM to become Ready with Timeout indicator.
+; Timeout Length is arbitrary and depends on CPU Clock Rate.
+
+WRdyT:  ;DI                     ; No Ints while we are doing I/O
+        LD      BC,#30000       ; << Arbitrary >>
+WRdyT0: DEC     BC
+        LD      A,B
+        OR      C               ; Timed Out?
+        SCF                     ;  (set Error Flag in case)
+        RET     Z               ; ..return Error Flag if Yes
+        IN      A,(FDC_MSR)     ; Read Status Reg
+        AND     #0x80           ; Interrupt Present (also kill Carry)?
+        RET     NZ              ; ..return Ok if Yes
+        JR      WRdyT0          ;  ..else loop to try again
+;-------------------------------------------------------------
+; Return Pointer to Parameters of selected Drive
+; Enter: A = Drive (0..3)
+; Exit : HL -> Parameter entry of drive
+; Uses : AF,HL
+
+GetPrm: PUSH    DE
+        LD      DE,#TBLSIZ      ; Entry Size
+        LD      HL,#_devfd_dtbl ;  Init to table start
+        INC     A
+GetPr0: DEC     A               ; End?
+        JR      Z,GetPrX        ; ..quit if Yes, Ptr set
+        ADD     HL,DE           ; Else step to next
+        JR      GetPr0          ; ..loop til found
+
+GetPrX: POP     DE
+        RET
+
+;-------------------------------------------------------------
+; This routine called at each Clock Interrupt.  It is used
+; to provide any necessary timer/timeout functions.
+; Enter: None.
+; Exit : HL -> mtm byte variable
+;        AF - destroyed
+; Uses : AF,HL
+
+_fd_tick:
+        LD      HL,#motim       ; Point to FDC Motor-On timer
+        LD      A,(HL)
+        OR      A               ; Already Timed out?
+        JR      Z,TDone         ; ..jump if Yes
+        DEC     (HL)            ; Else count down
+        CALL    Z,MotOff        ;   stop motors if timed out
+TDone:  INC     HL              ; Advance ptr to watchdog/spinup timer (mtm)
+        LD      A,(HL)
+        OR      A               ; Timed out?
+        RET     Z               ; ..quit if Yes
+        DEC     (HL)            ; Else count down
+        RET                     ;   exit
+
+;-------------------------------------------------------------
+; Motor Off routine.  Force Off to delay on next select
+; Enter: None. (Motoff)
+;        A = FDC Device Control Reg bits (Activ8/ActivA)
+; Exit : A = Current FDC_DOR Register / "active" byte settings
+; Uses : AF
+
+MotOff: XOR     A
+        LD      (motim),A       ; Ensure Motors Marked as OFF
+        LD      A,(active)      ; Get current settings
+        AND     #7              ;  strip off Motor bits
+Activ8: OR      #4              ;   (ensure FDC out of Reset)
+ActivA: LD      (active),A      ;    save
+        OUT     (FDC_DOR),A     ;     and Command!
+        RET
+
+;-------------------------------------------------------------
+; FDCMD - Send Command to DP-8473 FDC
+; Enter:  B = # of Bytes in Command, C = Command Byte
+;        HL -> Buffer for Read/Write Data (If Needed)
+; Exit : AF = Status byte
+; Uses : AF.  All other registers preserved/unused
+
+FdCmd:  PUSH    HL              ; Save regs (for Exit)
+        PUSH    BC
+        PUSH    DE
+
+        PUSH    HL              ; save pointer for possible Transfer
+        CALL    Motor           ; Ensure motors are On
+        LD      HL,#comnd       ; Point to Command Block
+        LD      (HL),C          ;  command passed in C
+        LD      C,#FDC_DATA     ;   FDC Data Port
+        LD      A,(_devfd_userbuf)
+        LD      D,A             ; store userbuf flag in D
+OtLoop: CALL    WRdy            ; Wait for RQM (hoping DIO is Low) (No Ints)
+        OUTI                    ; Output Command bytes to FDC
+        JR      NZ,OtLoop       ; ..loop til all bytes sent
+        POP     HL              ; Restore Possible Transfer Addr
+
+        CALL    FdCmdXfer       ; Do the data transfer (using code in _COMMONMEM)
+
+        LD      HL,#st0         ; Point to Status Result area
+IsGo:   CALL    WRdy
+        BIT     4,A             ; End of Status/Result?
+        JR      Z,FdcXit        ; ..exit if So
+        BIT     6,A             ; Another byte Ready?
+        JR      Z,FdcXit        ; ..exit if Not
+        INI                     ; Else Read Result/Status Byte
+        JR      IsGo            ; ..loop for next
+FdcXit: 
+        POP     DE              ; Restore Regs
+        POP     BC
+        POP     HL
+        RET
+
+;------------------------------------------------------------
+; COMMON MEMORY
+;------------------------------------------------------------
+        .area _COMMONMEM
+
+; inner section of FdCmd routine, has to touch buffers etc
+FdCmdXfer:
+        BIT     0,D             ; Buffer in user memory?
+        CALL    NZ, map_process_always
+
+FdCi1:  CALL    WRdy
+        BIT     5,A             ; In Execution Phase?
+        JR      Z,FdCmdXferDone ; ... tidy up and return if not
+        BIT     6,A             ; Write?
+        JR      NZ,FdCi2        ; ... jump if Not to Read
+        OUTI                    ; Write a Byte from (HL) to (C)
+        JR      FdCi1           ; check for next byte
+FdCi2:  INI                     ; Read a byte from (C) to (HL)
+        JR      FdCi1           ; check for next byte
+FdCmdXferDone:
+        BIT     0,D             ; Buffer in user memory?
+        RET     Z               ; done if not
+        JP      map_kernel      ; else remap kernel and return
+
+;-------------------------------------------------------------
+; Wait for FDC RQM to become Ready, return DIO status in
+; Zero Flag.  Pause before reading status port (~12 mS
+; specified, some assumed in code).
+
+WRdy:
+WRdy1:  LD      A,(dlyCnt)      ; Get delay count
+WRdy0:  DEC     A               ;  count down
+        JR      NZ,WRdy0        ;   for ~6 uS Delay
+
+WRdyL:  IN      A,(FDC_MSR)     ; Read Main Status Register
+        BIT     7,A             ; Interrupt Present?
+        RET     NZ              ;  Return if So
+        JR      WRdyL           ;   Else Loop
+
+dlyCnt: .db     (CPU_CLOCK_KHZ/1000)    ; Delay to avoid over-sampling status register
+
+;------------------------------------------------------------
+; DATA MEMORY
+;------------------------------------------------------------
+         .area _DATA
+
+drive:  .ds     1               ; (minor) Currently Selected Drive
+active: .ds     1               ; Current bits written to FDC_DOR
+
+_devfd_sector:  .ds     1
+_devfd_track:   .ds     1               ; LSB used as Head # in DS formats
+_devfd_error:   .ds     1
+_devfd_buffer:  .ds     2
+_devfd_userbuf: .ds     1
+
+; DISK Subsystem Variable Storage
+comnd:  .ds     1               ; Storage for Command in execution
+hdr:    .ds     1               ; Head (B2), Drive (B0,1)
+trk:    .ds     1               ; Track (t)
+hd:     .ds     1               ; Head # (h)
+sect:   .ds     1               ; Physical Sector Number
+rsz:    .ds     1               ; Bytes/Sector (n)
+eot:    .ds     1               ; End-of-Track Sect #
+gpl:    .ds     1               ; Gap Length
+dtl:    .ds     1               ; Data Length
+
+; FDC Operation Result Storage Area
+st0:    .ds     1               ; Status Byte 0
+st1:    .ds     1               ; Status Byte 1 (can also be PCN)
+        .ds     1               ; ST2 - Status Byte 2
+        .ds     1               ; RC - Track #
+        .ds     1               ; RH - Head # (0/1)
+        .ds     1               ; RR - Sector #
+        .ds     1               ; RN - Sector Size
+
+; -->>> NOTE: Do NOT move these next two variables out of sequence !!! <<<--
+motim:  .ds     1               ; Motor On Time Counter
+mtm:    .ds     1               ; Floppy Spinup Time down-counter
+
+rdOp:   .ds     1               ; Read/write flag
+retrys: .ds     1               ; Number of times to try Opns
+rwRtry: .ds     1               ; Number of read/write tries
+DRVSPD: .ds     1               ; Drive Speed
+DRVSIZ: .ds     1               ; Drive Size
index fb27ee6..df6865d 100644 (file)
@@ -3,6 +3,7 @@
 #include <kdata.h>
 #include <tty.h>
 #include <devsys.h>
+#include <devfd.h>
 #include <devrd.h>
 #include <devtty.h>
 #include <blkdev.h>
@@ -12,7 +13,7 @@ struct devsw dev_tab[] =  /* The device driver switch table */
 {
 /*   open          close       read            write           ioctl */
   /* 0: /dev/fd - Floppy disk block devices */
-  {  no_open,      no_close,   no_rdwr,        no_rdwr,        no_ioctl},
+  {  fd_open,      fd_close,   fd_read,        fd_write,       no_ioctl},
   /* 1: /dev/hd - RAM disk interface */
   {  rd_open,      no_close,   rd_read,        rd_write,       no_ioctl},
   /* 2: /dev/tty -- serial ports */
diff --git a/Kernel/platform-zeta-v2/fuzix.lnk b/Kernel/platform-zeta-v2/fuzix.lnk
new file mode 100644 (file)
index 0000000..da7e6a9
--- /dev/null
@@ -0,0 +1,46 @@
+-mwxuy
+-i fuzix.ihx
+-b _CODE=0x0100
+-b _COMMONMEM=0xF000
+-b _DISCARD=0xE000
+-l z80
+platform-zeta-v2/crt0.rel
+platform-zeta-v2/commonmem.rel
+platform-zeta-v2/zeta-v2.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+platform-zeta-v2/tricks.rel
+platform-zeta-v2/main.rel
+timer.rel
+kdata.rel
+platform-zeta-v2/devfd.rel
+platform-zeta-v2/devfd_hw.rel
+platform-zeta-v2/devrd.rel
+platform-zeta-v2/devrd_hw.rel
+platform-zeta-v2/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_exec16.rel
+syscall_fs.rel
+syscall_proc.rel
+syscall_fs2.rel
+syscall_other.rel
+mm.rel
+swap.rel
+bank16k.rel
+tty.rel
+devsys.rel
+usermem.rel
+usermem_std-z80.rel
+platform-zeta-v2/discard.rel
+platform-zeta-v2/devtty.rel
+platform-zeta-v2/mbr.rel
+platform-zeta-v2/blkdev.rel
+platform-zeta-v2/ds1302.rel
+platform-zeta-v2/ds1302_discard.rel
+platform-zeta-v2/ds1302-n8vem.rel
+platform-zeta-v2/monitor.rel
+-e
index d723ee6..9715bb7 100644 (file)
@@ -14,6 +14,8 @@ PROGLOAD              .equ    0x0100
 
 CONSOLE_RATE           .equ    38400
 
+CPU_CLOCK_KHZ          .equ    20000
+
 ; Z80 CTC ports
 CTC_CH0                .equ    0x20    ; CTC channel 0 and interrupt vector
 CTC_CH1                .equ    0x21    ; CTC channel 1 (periodic interrupts)
index 723a4a3..2bd5689 100644 (file)
@@ -3,6 +3,9 @@
 #include <printf.h>
 #include <devtty.h>
 #include "config.h"
+#ifdef CONFIG_FLOPPY
+#include "devfd.h"
+#endif
 
 extern unsigned char irqvector;
 
@@ -21,6 +24,9 @@ void platform_interrupt(void)
                case 1:
 #ifdef CONFIG_PPP
                        tty_poll_ppp()
+#endif
+#ifdef CONFIG_FLOPPY
+                       fd_tick();
 #endif
                        timer_interrupt(); 
                        return;