From: Sergey Kiselev Date: Wed, 11 Mar 2015 07:22:44 +0000 (-0700) Subject: zeta-v2: Add floppy support (stolen from P112) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=94915956ad0b604c5a05ce6f0dfc88cd32640d54;p=FUZIX.git zeta-v2: Add floppy support (stolen from P112) --- diff --git a/Kernel/platform-zeta-v2/Makefile b/Kernel/platform-zeta-v2/Makefile index 210bd684..50046b56 100644 --- a/Kernel/platform-zeta-v2/Makefile +++ b/Kernel/platform-zeta-v2/Makefile @@ -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 diff --git a/Kernel/platform-zeta-v2/README b/Kernel/platform-zeta-v2/README index 2d0b660e..7dadddb8 100644 --- a/Kernel/platform-zeta-v2/README +++ b/Kernel/platform-zeta-v2/README @@ -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 diff --git a/Kernel/platform-zeta-v2/bootrom.s b/Kernel/platform-zeta-v2/bootrom.s index ee95c879..3099585d 100644 --- a/Kernel/platform-zeta-v2/bootrom.s +++ b/Kernel/platform-zeta-v2/bootrom.s @@ -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 diff --git a/Kernel/platform-zeta-v2/config.h b/Kernel/platform-zeta-v2/config.h index 55b30942..01e8159e 100644 --- a/Kernel/platform-zeta-v2/config.h +++ b/Kernel/platform-zeta-v2/config.h @@ -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 index 00000000..34798581 --- /dev/null +++ b/Kernel/platform-zeta-v2/devfd.c @@ -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 +#include +#include +#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 index 00000000..2019c576 --- /dev/null +++ b/Kernel/platform-zeta-v2/devfd.h @@ -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 index 00000000..280fe03d --- /dev/null +++ b/Kernel/platform-zeta-v2/devfd_hw.s @@ -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 diff --git a/Kernel/platform-zeta-v2/devices.c b/Kernel/platform-zeta-v2/devices.c index fb27ee6b..df6865dc 100644 --- a/Kernel/platform-zeta-v2/devices.c +++ b/Kernel/platform-zeta-v2/devices.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -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 index 00000000..da7e6a96 --- /dev/null +++ b/Kernel/platform-zeta-v2/fuzix.lnk @@ -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 diff --git a/Kernel/platform-zeta-v2/kernel.def b/Kernel/platform-zeta-v2/kernel.def index d723ee68..9715bb7e 100644 --- a/Kernel/platform-zeta-v2/kernel.def +++ b/Kernel/platform-zeta-v2/kernel.def @@ -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) diff --git a/Kernel/platform-zeta-v2/main.c b/Kernel/platform-zeta-v2/main.c index 723a4a31..2bd56896 100644 --- a/Kernel/platform-zeta-v2/main.c +++ b/Kernel/platform-zeta-v2/main.c @@ -3,6 +3,9 @@ #include #include #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;