From 131b06756b7878a1f03f197bc1af9283fa88308a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 12 Oct 2018 22:03:05 +0100 Subject: [PATCH] trs80m1: first pass towards decent floppy disk support --- Kernel/platform-trs80m1/Makefile | 2 +- Kernel/platform-trs80m1/devfd.c | 228 +++++++++++++++++++++++++++--- Kernel/platform-trs80m1/devfd.h | 18 ++- Kernel/platform-trs80m1/devfd3.c | 107 -------------- Kernel/platform-trs80m1/devices.c | 10 -- Kernel/platform-trs80m1/floppy.s | 25 ++-- Kernel/platform-trs80m1/floppy3.s | 36 ++--- Kernel/platform-trs80m1/fuzix.lnk | 1 - 8 files changed, 242 insertions(+), 185 deletions(-) delete mode 100644 Kernel/platform-trs80m1/devfd3.c diff --git a/Kernel/platform-trs80m1/Makefile b/Kernel/platform-trs80m1/Makefile index 5ce4fec7..e1d415d5 100644 --- a/Kernel/platform-trs80m1/Makefile +++ b/Kernel/platform-trs80m1/Makefile @@ -8,7 +8,7 @@ ASRCS += tricks.s commonmem.s floppy.s floppy3.s stringy.s ide.s # buffers.c must be in CODE2, direct users are more convenient there as # the asm helpers then can avoid another switch -C2SRCS = buffers.c devfd.c devfd3.c devhd.c +C2SRCS = buffers.c devfd.c devhd.c # And these so CODE1 is under 32K C2SRCS += devices.c main.c devstringy.c devinput.c C2SRCS += devlpr.c devtty.c devgfx.c diff --git a/Kernel/platform-trs80m1/devfd.c b/Kernel/platform-trs80m1/devfd.c index 7a154850..f25eb4e6 100644 --- a/Kernel/platform-trs80m1/devfd.c +++ b/Kernel/platform-trs80m1/devfd.c @@ -1,7 +1,30 @@ +/* + * Higher level logic for TRS80 floppy disk interfaces and clones + * on both Model 1 and Model 3 + * + * Things To Do + * - Set sector size and shift values in the config calls + * - Use those in the I/O loop so we can do varying sector sizes + * - Handle double sided media (need to consider heads in the loop) + * - Turn the step rate value into a step mask and use it in the asm code + * - Teach the asm code about density + * - Teach the asm code about double sided and maybe 128 byte sectors + * - Rework density handling + * - Write compensation + * - Formatting + * - Motor delay improvements + * - Try slowing step rate on repeated errors ? + * - 4 retries may not be sufficient ? + * - Head jiggling before we try restore ? + * - Tandy style doubler - how to pass that info ? + * - Autodetect density/sides/geometry + */ #include #include #include +#include #include +#include #define MAX_FD 4 @@ -17,12 +40,117 @@ static uint8_t motorct; /* Extern as they live in common */ extern uint8_t fd_map, fd_tab[MAX_FD]; extern uint8_t fd_selected; -extern uint8_t fd_cmd[6]; +extern uint8_t fd_cmd[7]; -/* - * We only support normal block I/O for the moment. We do need to - * add swapping! - */ +static struct fd_ops *fops; + +static struct fd_ops fd1_ops = { + fd_restore, + fd_operation, + fd_motor_on +}; + +static struct fd_ops fd3_ops = { + fd3_restore, + fd3_operation, + fd3_motor_on +}; + +static struct fdcinfo fdcap[MAX_FD] = { + { + FDF_SD|FDF_DD|FDF_DS|FDF_SEC256|FDF_SEC512, + 0, + 80, + 2, + 12, + FDC_DSTEP|FDC_AUTO|FDC_SEC0, + FDC_FMT_17XX, + 0, /* To calc worst case */ + 0,0,0 + }, + { + FDF_SD|FDF_DD|FDF_DS|FDF_SEC256|FDF_SEC512, + 0, + 80, + 2, + 12, + FDC_DSTEP|FDC_AUTO|FDC_SEC0, + FDC_FMT_17XX, + 0, /* To calc worst case */ + 0,0,0 + }, + { + FDF_SD|FDF_DD|FDF_DS|FDF_SEC256|FDF_SEC512, + 0, + 80, + 2, + 12, + FDC_DSTEP|FDC_AUTO|FDC_SEC0, + FDC_FMT_17XX, + 0, /* To calc worst case */ + 0,0,0 + }, + { + FDF_SD|FDF_DD|FDF_DS|FDF_SEC256|FDF_SEC512, + 0, + 80, + 2, + 12, + FDC_DSTEP|FDC_AUTO|FDC_SEC0, + FDC_FMT_17XX, + 0, /* To calc worst case */ + 0,0,0 + }, +}; + +static struct fdcinfo fdc[MAX_FD] = { + { + FDF_DD|FDF_SEC512, + 0, + 40, + 1, + 9, + 0, + FDC_FMT_17XX, + 0, /* To calc worst case */ + 0,0,0 + }, + { + FDF_DD|FDF_SEC512, + 0, + 40, + 1, + 9, + 0, + FDC_FMT_17XX, + 0, /* To calc worst case */ + 0,0,0 + }, + { + FDF_DD|FDF_SEC512, + 0, + 40, + 1, + 9, + 0, + FDC_FMT_17XX, + 0, /* To calc worst case */ + 0,0,0 + }, + { + FDF_DD|FDF_SEC512, + 0, + 40, + 1, + 9, + 0, + FDC_FMT_17XX, + 0, /* To calc worst case */ + 0,0,0 + }, +}; + +/* Translate the drive into a selection. Assumes single sided on the M1 */ static uint8_t selmap[4] = { 0x01, 0x02, 0x04, 0x08 }; static int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag) @@ -31,47 +159,69 @@ static int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag) int tries; uint8_t err = 0; uint8_t *driveptr = fd_tab + minor; + struct fdcinfo *f = fdc + minor; + /* You can't swap to floppy */ if(rawflag == 2) goto bad2; - /* FIXME: We force DD for now */ - err = fd_motor_on(selmap[minor]|0x80); - if (err) - goto bad; + /* Do we need to select the drive ? */ + if (trs80_model != TRS80_MODEL3 || fd_selected != minor) { + uint8_t err; + uint8_t tmp = 0; + /* Decide if we need double density */ + if (f->features & FDF_DD) + tmp |= 0x80; + err = fops->fd_motor_on(selmap[minor]|tmp); + if (err) + goto bad; + } + /* If we don't know where the head on this drive is then force + a seek */ if (*driveptr == 0xFF) - fd_reset(driveptr); + if (err = fops->fd_restore(driveptr)) + goto bad; + /* Adjust for the block size if raw I/O. For now hard code 512 byte + sectors but we need to sort this */ fd_map = rawflag; if (rawflag && d_blkoff(BLKSHIFT)) return -1; - udata.u_nblock *= 2; - + /* We only deal with single sided 512 byte/sector media for the moment */ fd_cmd[0] = is_read ? FD_READ : FD_WRITE; - fd_cmd[1] = udata.u_block / 9; /* 2 sectors per block */ - fd_cmd[2] = ((udata.u_block % 9) << 1) + 1; /*eww.. */ fd_cmd[3] = is_read ? OPDIR_READ: OPDIR_WRITE; fd_cmd[4] = ((uint16_t)udata.u_dptr) & 0xFF; fd_cmd[5] = ((uint16_t)udata.u_dptr) >> 8; + fd_cmd[6] = 2; /* 0 128 1 256 2 512 : fixed for now */ while (ct < udata.u_nblock) { + /* For each block we need to load we work out where to find it */ + fd_cmd[1] = udata.u_block / f->sectors; + fd_cmd[2] = udata.u_block % f->sectors; + /* Some single density media has sectors numbered from zero */ + if (!(f->config & FDC_SEC0)) + fd_cmd[2]++; + /* Reading 40 track media on an 80 track drive */ + if (f->config & FDC_DSTEP) + fd_cmd[1] <<= 1; + /* Now try the I/O */ for (tries = 0; tries < 4 ; tries++) { - err = fd_operation(driveptr); + err = fops->fd_op(driveptr); if (err == 0) break; + /* Reposition the head */ if (tries > 1) - fd_reset(driveptr); + fops->fd_restore(driveptr); } - /* FIXME: should we try the other half and then bale out ? */ if (tries == 4) goto bad; fd_cmd[5]++; /* Move on 256 bytes in the buffer */ - fd_cmd[2]++; /* Next sector for 2nd block */ + fd_cmd[5]++; /* Move on 256 bytes in the buffer */ ct++; } - return udata.u_nblock << 8; + return udata.u_nblock << 9; bad: kprintf("fd%d: error %x\n", minor, err); bad2: @@ -86,6 +236,11 @@ int fd_open(uint8_t minor, uint16_t flag) udata.u_error = ENODEV; return -1; } + /* No media ? */ + if (fops->fd_restore(fd_tab + minor) && !(flag & O_NDELAY)) { + udata.u_error = EIO; + return -1; + } return 0; } @@ -100,3 +255,38 @@ int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag) flag;rawflag;minor; return fd_transfer(minor, false, rawflag); } + +int fd_ioctl(uint8_t minor, uarg_t request, char *buffer) +{ + switch(request) { + case FDIO_GETCAP: + return uput(fdcap + minor, buffer, sizeof(struct fdcinfo)); + case FDIO_GETINFO: + return uput(fdc + minor, buffer, sizeof(struct fdcinfo)); + case FDIO_SETINFO: + /* Ick.. but we are not portable code so we know how it packs */ + if (uget(fdc + minor, buffer, 7)) + return -1; + /*FIXME when we sort DS meida */ + fdc[minor].heads = 1; + /* TODO : steprate to masks */ + fdc[minor].features &= fdcap[minor].features; + /* Force reconfiguration */ + fd_tab[minor] = 0xFF; + fd_selected = 255; + return 0; + case FDIO_FMTTRK: + return -1; + case FDIO_RESTORE: + return fops->fd_restore(fd_tab + minor); + } + return -1; +} + +void floppy_setup(void) +{ + if (trs80_model == TRS80_MODEL3) + fops = &fd3_ops; + else + fops = &fd1_ops; +} diff --git a/Kernel/platform-trs80m1/devfd.h b/Kernel/platform-trs80m1/devfd.h index 672cf907..0bc76af8 100644 --- a/Kernel/platform-trs80m1/devfd.h +++ b/Kernel/platform-trs80m1/devfd.h @@ -7,9 +7,19 @@ int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag); int fd_open(uint8_t minor, uint16_t flag); /* low level interface */ -uint16_t fd_reset(uint8_t *driveptr); -uint16_t fd_operation(uint8_t *driveptr); -uint16_t fd_motor_on(uint16_t drivesel); -uint16_t fd_motor_off(uint16_t driveptr); +uint8_t fd_restore(uint8_t *driveptr) __z88dk_fastcall; +uint16_t fd_operation(uint8_t *driveptr) __z88dk_fastcall; +uint16_t fd_motor_on(uint16_t drivesel) __z88dk_fastcall; +/* low level interface */ +uint8_t fd3_restore(uint8_t *driveptr) __z88dk_fastcall; +uint16_t fd3_operation(uint8_t *driveptr) __z88dk_fastcall; +uint16_t fd3_motor_on(uint16_t drivesel) __z88dk_fastcall; + +struct fd_ops { + uint8_t (*fd_restore)(uint8_t *driveptr) __z88dk_fastcall; + uint16_t (*fd_op)(uint8_t *driveptr) __z88dk_fastcall; + uint16_t (*fd_motor_on)(uint16_t drivesel) __z88dk_fastcall; +}; + #endif /* __DEVFD_DOT_H__ */ diff --git a/Kernel/platform-trs80m1/devfd3.c b/Kernel/platform-trs80m1/devfd3.c deleted file mode 100644 index 6dd75205..00000000 --- a/Kernel/platform-trs80m1/devfd3.c +++ /dev/null @@ -1,107 +0,0 @@ -#include -#include -#include -#include - -#define MAX_FD 4 - -#define OPDIR_NONE 0 -#define OPDIR_READ 1 -#define OPDIR_WRITE 2 - -#define FD_READ 0x80 /* 2797 needs 0x88, 1797 needs 0x80 */ -#define FD_WRITE 0xA0 /* Likewise A8 v A0 */ - -static uint8_t motorct; - -/* Extern as they live in common */ -extern uint8_t fd_map, fd_tab[MAX_FD]; -extern uint8_t fd_selected; -extern uint8_t fd_cmd[7]; - -/* - * We only support normal block I/O for the moment. We do need to - * add swapping! - */ -static uint8_t selmap[4] = { 0x01, 0x02, 0x04, 0x08 }; - -static int fd3_transfer(uint8_t minor, bool is_read, uint8_t rawflag) -{ - int ct = 0; - int tries; - uint8_t err = 0; - uint8_t *driveptr = fd_tab + minor; - - if(rawflag == 2) - goto bad2; - - if (fd_selected != minor) { - uint8_t err; - /* FIXME: We force DD for now */ - err = fd3_motor_on(selmap[minor]|0x80); - if (err) - goto bad; - } - - if (*driveptr == 0xFF) - fd3_reset(driveptr); - - fd_map = rawflag; - if (rawflag && d_blkoff(BLKSHIFT)) - return -1; - - udata.u_nblock *= 2; - - fd_cmd[0] = is_read ? FD_READ : FD_WRITE; - fd_cmd[1] = udata.u_block / 9; /* 2 sectors per block */ - fd_cmd[2] = ((udata.u_block % 9) << 1) + 1; /*eww.. */ - fd_cmd[3] = is_read ? OPDIR_READ: OPDIR_WRITE; - fd_cmd[4] = ((uint16_t)udata.u_dptr) & 0xFF; - fd_cmd[5] = ((uint16_t)udata.u_dptr) >> 8; - fd_cmd[6] = 1; /* For now . FIXME */ - - while (ct < udata.u_nblock) { - for (tries = 0; tries < 4 ; tries++) { - err = fd3_operation(driveptr); - if (err == 0) - break; - if (tries > 1) - fd3_reset(driveptr); - } - /* FIXME: should we try the other half and then bale out ? */ - if (tries == 4) - goto bad; - fd_cmd[5]++; /* Move on 256 bytes in the buffer */ - fd_cmd[2]++; /* Next sector for 2nd block */ - ct++; - } - return udata.u_nblock << 8; -bad: - kprintf("fd%d: error %x\n", minor, err); -bad2: - udata.u_error = EIO; - return -1; -} - -int fd3_open(uint8_t minor, uint16_t flag) -{ - flag; - if(minor >= MAX_FD) { - udata.u_error = ENODEV; - return -1; - } - return 0; -} - -int fd3_read(uint8_t minor, uint8_t rawflag, uint8_t flag) -{ - flag; - return fd3_transfer(minor, true, rawflag); -} - -int fd3_write(uint8_t minor, uint8_t rawflag, uint8_t flag) -{ - flag;rawflag;minor; -// return 0; - return fd3_transfer(minor, false, rawflag); -} diff --git a/Kernel/platform-trs80m1/devices.c b/Kernel/platform-trs80m1/devices.c index 90159b4a..6bca6b4f 100644 --- a/Kernel/platform-trs80m1/devices.c +++ b/Kernel/platform-trs80m1/devices.c @@ -38,10 +38,6 @@ struct devsw dev_tab[] = /* The device driver switch table */ { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl }, }; -static struct devsw floppy3 = { - fd3_open, no_close, fd3_read, fd3_write, no_ioctl -}; - bool validdev(uint16_t dev) { /* This is a bit uglier than needed but the right hand side is @@ -51,9 +47,3 @@ bool validdev(uint16_t dev) else return true; } - -void floppy_setup(void) -{ - if (trs80_model == TRS80_MODEL3) - memcpy(dev_tab + 1, &floppy3, sizeof(struct devsw)); -} diff --git a/Kernel/platform-trs80m1/floppy.s b/Kernel/platform-trs80m1/floppy.s index ed393d6a..3b5ea256 100644 --- a/Kernel/platform-trs80m1/floppy.s +++ b/Kernel/platform-trs80m1/floppy.s @@ -8,7 +8,7 @@ ; FIXME: precompensation ?? ; FIXME: 512 byte sector support ; - .globl _fd_reset + .globl _fd_restore .globl _fd_operation .globl _fd_motor_on .globl _fd_motor_off @@ -280,13 +280,9 @@ fdio_xfer_out: ; ; Reset to track 0, wait for the command then idle ; -; fd_reset(uint8_t *drvptr) +; fd_restore(uint8_t *drvptr) ; -_fd_reset: - pop de - pop hl - push hl - push de +_fd_restore: call go_slow ld a, #1 ld (FDCSEC), a @@ -297,7 +293,9 @@ _fd_reset: ld a, #0xFF ld (hl), a ; Zap track pointer call waitcmd + ld l,a call go_fast + ld a,l cp #0xff ret z and #0x99 ; Error bit from the reset @@ -305,16 +303,13 @@ _fd_reset: ld (hl), a ; Track 0 correctly hit (so 0) ret ; -; fd_operation(uint16_t *cmd, uint16_t *drive) +; fd_operation(uint8_t *cmd) ; ; The caller must ensure the drive has been selected and the motor is ; running. ; _fd_operation: - pop bc ; return address - pop de ; drive track ptr - push de - push bc + ex de,hl push ix ld a, (_fd_map) or a @@ -368,11 +363,7 @@ waitdiskl: ; ; _fd_motor_on: - pop de - pop bc - push bc - push de - + ld c,l ; ; Is the motor running ? ; diff --git a/Kernel/platform-trs80m1/floppy3.s b/Kernel/platform-trs80m1/floppy3.s index 24a8a671..aa099c2e 100644 --- a/Kernel/platform-trs80m1/floppy3.s +++ b/Kernel/platform-trs80m1/floppy3.s @@ -17,7 +17,7 @@ ; FIXME: backport fixes to model 4 ; ; - .globl _fd3_reset + .globl _fd3_restore .globl _fd3_operation .globl _fd3_motor_on .globl _fd3_motor_off @@ -241,11 +241,11 @@ fdio_inl: fdio_inbyte: out (FDCCTRL), a ; stalls ini - jr nz, fdio_inbyte + jp nz, fdio_inbyte fdio_inbyte2: ; this is patched for I/O size out (FDCCTRL), a ; stalls ini - jr nz, fdio_inbyte2 + jp nz, fdio_inbyte2 jr fdxferdone ; @@ -287,7 +287,7 @@ fdio_waitlock: fdio_outbyte: out (FDCCTRL), a ; stalls outi - jr nz,fdio_outbyte + jp nz,fdio_outbyte fdio_nmiout: ; @@ -306,13 +306,7 @@ fdxferbad: ; ; fd_reset3(uint8_t *drvptr) ; -_fd3_reset: - pop bc - pop de - pop hl - push hl - push de - push bc +_fd3_restore: ld a, (fdcctrl) out (FDCCTRL), a ld a, #1 @@ -328,6 +322,7 @@ _fdr_wait: djnz _fdr_wait call waitdisk + ld l,a cp #0xff ret z and #0x99 ; Error bit from the reset @@ -335,21 +330,16 @@ _fdr_wait: ld (hl), a ; Track 0 correctly hit (so 0) ret ; -; fd_operation3(uint16_t *drive) +; fd_operation3(uint8_t *driveptr) ; ; The caller must ensure the drive has been selected and the motor is ; running. ; _fd3_operation: + ex de,hl ; arg into de ld a, (_fd_map) or a call nz, map_process_always - pop hl ; banked - pop bc ; return address - pop de ; drive track ptr - push de - push bc - push hl push ix ld ix, #_fd_cmd ld l, DATA(ix) @@ -376,12 +366,6 @@ _fd3_operation: ; ; _fd3_motor_on: - pop bc - pop de - pop hl - push hl - push de - push bc ; ; Select drive B, turn on motor if needed ; @@ -397,9 +381,9 @@ _fd3_motor_on: notsel: ld a, l out (FDCCTRL), a - out (FDCCTRL), a ; TRS80 erratum apparently needs this + out (FDCCTRL), a ; TRS80 erratum: model 4 gate array apparently needs this ld (fdcctrl), a - ld bc, #0x7F00 ; Long delay (may need FE or FF for some disks) + ld bc, #0x7F00 ; Long delay (may need FE or FF for some disks?) call nap ; FIXME: longer motor spin up delay goes here (0.5 or 1 second) diff --git a/Kernel/platform-trs80m1/fuzix.lnk b/Kernel/platform-trs80m1/fuzix.lnk index 103543ca..d8eb3353 100644 --- a/Kernel/platform-trs80m1/fuzix.lnk +++ b/Kernel/platform-trs80m1/fuzix.lnk @@ -20,7 +20,6 @@ platform-trs80m1/main.rel timer.rel kdata.rel platform-trs80m1/devfd.rel -platform-trs80m1/devfd3.rel platform-trs80m1/floppy.rel platform-trs80m1/floppy3.rel platform-trs80m1/devhd.rel -- 2.34.1