pcw8256: add initial cut at hard disk drivers
authorAlan Cox <alan@linux.intel.com>
Wed, 11 Apr 2018 22:37:52 +0000 (23:37 +0100)
committerAlan Cox <alan@linux.intel.com>
Wed, 11 Apr 2018 22:37:52 +0000 (23:37 +0100)
Update some notes
Add some of the swap bits (more is needed see the COCO3)

Kernel/platform-pcw8256/Makefile
Kernel/platform-pcw8256/README
Kernel/platform-pcw8256/config.h
Kernel/platform-pcw8256/devfhd.c [new file with mode: 0644]
Kernel/platform-pcw8256/devfhd.h [new file with mode: 0644]
Kernel/platform-pcw8256/devices.c
Kernel/platform-pcw8256/fidhd.c [new file with mode: 0644]
Kernel/platform-pcw8256/fuzix.lnk
Kernel/platform-pcw8256/pcw8256.s
Kernel/platform-pcw8256/platform_ide.h [new file with mode: 0644]

index 164a0d5..bb5ea2d 100644 (file)
@@ -1,13 +1,21 @@
 
-CSRCS = devlpr.c devtty.c devfd.c
+CSRCS = devlpr.c devtty.c devfd.c devfhd.c fidhd.c
 CSRCS += devices.c main.c
 
+DSRCS = ../dev/devide.c ../dev/blkdev.c ../dev/mbr.c
+DISCARD_DSRCS = ../dev/devide_discard.c
+
+CROSS_CCOPTS += -I ../dev/
+
 ASRCS =  crt0.s commonmem.s pcw8256.s
 ASRCS += tricks.s fdc765.s
 
 COBJS = $(CSRCS:.c=.rel)
 AOBJS = $(ASRCS:.s=.rel)
-OBJS  = $(COBJS) $(AOBJS)
+DISCARD_DOBJS = $(patsubst ../dev/%.c,%.rel, $(DISCARD_DSRCS))
+DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS))
+
+OBJS  = $(COBJS) $(AOBJS) $(DOBJS) $(DISCARD_DOBJS)
 
 JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst)
 
@@ -19,6 +27,12 @@ $(COBJS): %.rel: %.c
 $(AOBJS): %.rel: %.s
        $(CROSS_AS) $(ASOPTS) $<
 
+$(DOBJS): %.rel: ../dev/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(DISCARD_DOBJS): %.rel: ../dev/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
 clean:
        rm -f $(OBJS) $(JUNK)  core *~ 
 
index 1c3019a..61c57e8 100644 (file)
@@ -52,8 +52,47 @@ At that point the keyboard should work.
 The floppy driver is incomplete but given a rootfs image on /dev/fd1 you
 should be able to at least get it to mount
 
-device 0 = fd0 1 = fd1
+device 256 = fd0 257 = fd1
+
+(0-255 are the UIDE hard disks, or FID hard disks on Joyce)
 
 
 Mixed boot/root images are not currently supported (this just needs a modified
 boot block that starts at a different offset)
+
+
+Memory
+------
+
+Then PCW8256 memory is split into multiple banks not all of which can be used
+for any purpose
+
+The display takes 23040 bytes of video line memory. Each line must be within
+the low 128K and is indexed by the roller RAM
+
+The roller RAM must also be within the low 128K and is 512 bytes.
+
+The keyboard magically replaces the top 16 bytes of bank 3.
+
+Our loader puts the screen into bank 4 and bank 5 (part of), then loads the
+OS into bank 0/1/2/3. We really need to rearrange this so we set the
+final kernel map as something like
+
+0 1 3 5 (4 is display in map)
+
+except that means we must field a hole between BFF0 (keyboard) and Cxxx (
+display). We then end up with a map of
+
+0000-0087      Boot loader
+0088-BFEF      Kernel image
+BFF0-BFFF      Keyboard
+C000-D9FF      Video (lower window)
+DA00-DBFF      Roller map
+DC00-E3FF      Font
+E400-...       Video
+... -FFFF      Common
+
+Whilst doing video we map over 8000-BFFF and rely upon the video and common
+mappings
+
+That leaves bank 2, 6+ for userspace (kernel + video costs us 80K)
index 57f06e0..96f812c 100644 (file)
@@ -31,6 +31,9 @@
 #define VT_RIGHT       89
 #define VT_BOTTOM      31
 
+#define MAX_BLKDEV     1       /* UIDE or FIDHD never both */
+#define CONFIG_IDE     /* Has an IDE controller - maybe anyway: UIDE */
+
 #define TICKSPERSEC 50   /* Ticks per second */
 #define PROGBASE    0x0000     /* memory base of program */
 #define PROGLOAD    0x0100     /* load base of program */
@@ -55,6 +58,6 @@
 #define NMOUNTS         2        /* Number of mounts at a time */
 
 
-#define swap_map(x)    ((uint8_t *)(x))        /* For now */
+#define swap_map(x)    (uint8_t *)(0x4000 + ((x) & 0x3FFF))    /* For now */
 
 #define platform_discard()
diff --git a/Kernel/platform-pcw8256/devfhd.c b/Kernel/platform-pcw8256/devfhd.c
new file mode 100644 (file)
index 0000000..e286e85
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *     An implementation of the FID based hard disk interface for Joyce.
+ *     Currently only hard disk interfaces are handled by this driver.
+ */
+#include <kernel.h>
+#include <kdata.h>
+#include <blkdev.h>
+#include <devfhd.h>
+#include <printf.h>
+
+#define MAX_FHD        16
+
+static const char *errstr[2] = { "write", "read" };
+static uint8_t drivemask;
+static uint8_t drivebase;
+static struct dpb dpb[MAX_FHD];
+
+static uint8_t devfhd_transfer_sector(void)
+{
+    uint8_t err;
+    uint8_t drive = blk_op.blkdev->driver_data;
+    fhd_drive = drivebase + drive;
+    fhd_dpb = dpb + drive;
+    /* For now assume HD fixed geometry */
+    fhd_track = blk_op.lba >> 5;
+    fhd_sector = blk_op.lba & 0x1F;
+    fhd_op = blk_op.is_read ? 4 : 5;
+    err = rw_fidhd();
+    if (err) {
+        kprintf("fhd%c: %s error %d\n", 'a' + drive, errstr[blk_op.is_read], err);
+        return 0;
+    }
+    return 1;
+}
+
+static int devfhd_flush_cache(void)
+{
+    uint8_t err;
+    uint8_t drive = blk_op.blkdev->driver_data;
+    fhd_drive = drivebase + drive;
+    fhd_dpb = dpb + drive;
+    err = flush_fidhd();
+    if (err) {
+        kprintf("fhd%c: flush error %d\n", 'a' + drive, err);
+        udata.u_error = EIO;
+        return -1;
+    }
+    return 0;
+}
+
+/* FIXME These bits could be discard.. */
+
+int devfhd_init(void)
+{
+    blkdev_t *blk;
+    uint8_t d;
+
+    /* Either not supported or too old */
+    if (probe_fidhd() < 2)
+        return 0;
+    fhd_op = 4;
+    fhd_drive = 0;
+    fhd_dpb = dpb;
+    /* Find first slot to install */
+    fhd_drive = drivebase = install_fidhd();
+    if (fhd_drive == 0xFF)
+        return 0;
+    /* Now begin registering */
+    fhd_op = 0;
+    for (d = 0; d < MAX_FHD; d++) {
+        uint8_t next = install_fidhd();
+        if (next != 0xFF)
+            drivemask |= (1 << d);
+        /* The current driver guarantees us a 1:1 so we don't do a lookup
+           table. Maybe we should for the future and use next as intended */
+        fhd_drive++;
+        fhd_dpb++;
+    }
+    fhd_dpb = dpb;
+    fhd_drive = drivebase;
+    for (d = 0; d + drivebase < MAX_FHD; d++) {
+        if (drivemask & (1 << d)) {
+            login_fidhd();
+            blk = blkdev_alloc();
+            if (!blk)
+                break;
+            blk->transfer = devfhd_transfer_sector;
+            blk->flush = devfhd_flush_cache;
+            blk->driver_data = d;
+            blk->drive_lba_count = 16834;      /* FIXME use dpb */
+            blkdev_scan(blk, SWAPSCAN);        /* Won't damage fhd_dpb/drive */
+        }
+        fhd_drive++;
+        fhd_dpb++;
+    }
+    return drivemask;
+}
diff --git a/Kernel/platform-pcw8256/devfhd.h b/Kernel/platform-pcw8256/devfhd.h
new file mode 100644 (file)
index 0000000..190ac9e
--- /dev/null
@@ -0,0 +1,28 @@
+struct dpb {
+    uint16_t spt;
+    uint8_t  bsh;
+    uint8_t  blm;
+    uint8_t  exm;
+    uint16_t dsm;
+    uint16_t drm;
+    uint8_t  al0;
+    uint8_t  al1;
+    uint16_t cks;
+    uint16_t off;
+    uint8_t  psh;
+    uint8_t  phm;
+};
+
+extern int devfhd_init(void);
+
+extern uint8_t fhd_drive;
+extern uint8_t fhd_op;
+extern uint16_t fhd_track;
+extern uint16_t fhd_sector;
+extern struct dpb *fhd_dpb;
+
+extern uint8_t probe_fidhd(void);
+extern uint8_t install_fidhd(void);
+extern uint8_t login_fidhd(void);
+extern uint8_t flush_fidhd(void);
+extern uint8_t rw_fidhd(void);
index 07dacde..ad2c45d 100644 (file)
@@ -2,6 +2,9 @@
 #include <version.h>
 #include <kdata.h>
 #include <devfd.h>
+#include <blkdev.h>
+#include <devide.h>
+#include <devfhd.h>
 #include <devsys.h>
 #include <devlpr.h>
 #include <devtty.h>
@@ -12,10 +15,10 @@ struct devsw dev_tab[] =  /* The device driver switch table */
 {
 // minor    open         close        read      write       ioctl
 // -----------------------------------------------------------------
-  /* 0: /dev/fd                Floppy disc block devices  */
+  /* 0: /dev/hd                Hard disc block devices (UIDE or FIDHD) */
+  {  blkdev_open,   no_close,  blkdev_read,    blkdev_write,   blkdev_ioctl }, /* 0: /dev/hd -- standard block device interface */
+  /* 1: /dev/fd                Floppy disc block devices */
   {  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },
-  /* 1: /dev/hd                Hard disc block devices (absent) */
-  {  nxio_open,     no_close,    no_rdwr,   no_rdwr,   no_ioctl },
   /* 2: /dev/tty       TTY devices */
   {  tty_open,     tty_close,   tty_read,  tty_write,  vt_ioctl },
   /* 3: /dev/lpr       Printer devices */
@@ -39,4 +42,7 @@ void device_init(void)
 {
   tty_init_port();
   fd_probe();
+  /* See what we are attaching */
+  if (devfhd_init() == 0)
+    devide_init();
 }
diff --git a/Kernel/platform-pcw8256/fidhd.c b/Kernel/platform-pcw8256/fidhd.c
new file mode 100644 (file)
index 0000000..45a884b
--- /dev/null
@@ -0,0 +1,162 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <blkdev.h>
+#include <devfhd.h>
+
+char spambuf[93];
+struct dpb *fhd_dpb;
+uint8_t fhd_drive;
+uint8_t fhd_op;                        /* must follow fhd_drive directly */
+uint16_t fhd_sector;
+uint16_t fhd_track;
+
+uint8_t probe_fidhd(void) __naked
+{
+__asm
+       xor a
+       .db 0xed
+       .db 0xfe
+       ld l,a
+       or a
+       ret z
+       ld l,h
+       ret
+__endasm;
+}
+
+/*
+ *     Install a drive using the given dpb, with spambuf as a buffer
+ *     for (currrntly) unused messages on error [93 byte]
+ *
+ *     Caller sets driveno, returns volume number to use or FF on fail
+ */
+
+uint8_t install_fidhd(void) __naked
+{
+__asm
+       push ix
+       push iy
+       ld bc,#0x00fe           ; probably FF for MYZ80 only ?
+       ld ix, (_fhd_dpb)
+       ld hl, #_spambuf
+       ld de, (_fhd_drive)     ; d = op e = drive
+       ld a,#7
+       .db 0xed
+       .db 0xfe
+       cp #2
+       ld l,#0xFF
+       jr nz, instbad
+       ld l,b
+instbad:
+       pop iy
+       pop ix
+       ret
+__endasm;
+}
+
+/*
+ *     Returns 0 for ok, 1/2/FF on error as others
+ */
+uint8_t flush_fidhd(void) __naked
+{
+__asm
+       push ix
+       push iy
+       ld ix, (_fhd_dpb)
+       ld a, (_fhd_drive)
+       ld b,a
+       ld a,#6
+       .byte 0xed
+       .byte 0xfe
+       pop iy
+       pop ix
+       ld h,#0
+       ld l,a
+       ret z
+       ret c
+       ld h,b
+       ret
+__endasm;
+}
+/*
+ *     Returns 0 for OK and if ok also writes the 17 byte DPB for this
+ *     drive to ix. In theory the DPB we get handed back could be for a
+ *     whole tonload of formats but the main one we care about is the myz80
+ *     8MB image with 16k/track (32 sectors), 512 tracks.
+ *
+ *     Currently we must do the login at boot time and we can't tolerate
+ *     a media change of size. (see read/write case for why).
+ */
+uint8_t login_fidhd(void) __naked
+{
+__asm
+       push ix
+       push iy
+       ld bc, (_fhd_drive-1)
+       ld ix, (_fhd_dpb)
+       ld a, #3
+       .byte 0xed
+       .byte 0xfe
+       pop iy
+       pop ix
+       ld h,#0
+       ld l,a
+       ret
+__endasm;
+}
+
+COMMON_MEMORY
+
+/*
+ *     Low level I/O has to live in common as we switch banks around in
+ *     order to read into user space or into a paging bank.
+ *     
+ *     Warning: because our common is copied per instance our variables
+ *     in common are map specific.
+ * 
+ *     Read a sector. On return 0 = ok, 1 = error FF = mediach
+ *     if recoverable error high byte = error code else 0
+ */
+
+uint8_t rw_fidhd(void) __naked
+{
+__asm
+       ld a,(_fhd_op)
+       push ix
+       push iy
+       ; We must fetch these while in kernel bank. dataptr will point into
+       ; the bank we switch to but the dpb is in kernel bank.
+       ;
+       ; We rely upon the fact we scan all the drives before userspace
+       ; runs thus the dpb has been copied into each common copy and is
+       ; static.
+       ;
+       ld ix, (_fhd_dpb)
+       ld iy, (_blk_op+BLKPARAM_ADDR_OFFSET)
+       ld de, (_fhd_sector)
+       ld hl, (_fhd_track)
+       ld bc, (_fhd_drive-1)
+       push af
+       ld a, (_blk_op+BLKPARAM_IS_USER_OFFSET)
+       or a
+       jr z, k_map
+       cp #1
+       call z, map_process_always
+       ld a, (_blk_op+BLKPARAM_SWAP_PAGE)
+       call nz, map_for_swap
+k_map:
+       pop af
+       .byte 0xed
+       .byte 0xfe
+       pop iy
+       pop ix
+       call map_kernel
+       ld h,#0
+       ld l,a
+       ret z
+       ret c
+       ld h,b
+       ret
+__endasm;
+}
index d47043d..ea74c7b 100644 (file)
@@ -38,4 +38,11 @@ platform-pcw8256/devlpr.rel
 platform-pcw8256/devtty.rel
 vt.rel
 font8x8.rel
+platform-pcw8256/blkdev.rel
+platform-pcw8256/mbr.rel
+platform-pcw8256/devide.rel
+platform-pcw8256/devide_discard.rel
+platform-pcw8256/devfhd.rel
+platform-pcw8256/fidhd.rel
+
 -e
index ce87625..6eb9179 100644 (file)
@@ -14,6 +14,7 @@
            .globl _need_resched
            .globl map_save
            .globl map_restore
+           .globl map_for_swap
            .globl platform_interrupt_all
            .globl _copy_common
 
@@ -179,6 +180,11 @@ map_kernel:
            pop af
            ret
 
+map_for_swap:
+           ld (map_current+1),a
+           out (0xF1),a        ; map at 0x4000
+           ret
+
 map_process_always:
            push af
            push hl
diff --git a/Kernel/platform-pcw8256/platform_ide.h b/Kernel/platform-pcw8256/platform_ide.h
new file mode 100644 (file)
index 0000000..2b8824d
--- /dev/null
@@ -0,0 +1,6 @@
+#define ide_select(x)
+#define ide_deselect()
+
+/* UIDE8 for the PCW series: 8bit, no altstatus/control */
+#define IDE_8BIT_ONLY
+#define IDE_REG_CS1_BASE   0xC8