pdp11: more platform updating
authorAlan Cox <alan@linux.intel.com>
Sat, 17 Feb 2018 22:39:13 +0000 (22:39 +0000)
committerAlan Cox <alan@linux.intel.com>
Sat, 17 Feb 2018 22:39:13 +0000 (22:39 +0000)
Not yet a complete usable machine

Kernel/platform-pdp11/Makefile
Kernel/platform-pdp11/README
Kernel/platform-pdp11/boot-rx0.s [new file with mode: 0644]
Kernel/platform-pdp11/config.h
Kernel/platform-pdp11/dev_rk.c [new file with mode: 0644]
Kernel/platform-pdp11/dev_rx.c [new file with mode: 0644]
Kernel/platform-pdp11/devtty.c

index 40344ae..b4d1d83 100644 (file)
@@ -39,3 +39,7 @@ image:
        tricks.o ../syscall_fs3.o \
        ../usermem_std-pdp11.o devtty.o libc.o > ../fuzix.map
        pdp11-aout-objcopy fuzix.aout -O binary ../fuzix.bin
+
+       pdp11-aout-as boot-rx0.s -o boot-rx0.o
+       pdp11-aout-ld boot-rx0.o -o boot-rx0.aout
+       pdp11-aout-objcopy boot-rx0.aout -O binary boot-rx0
index f514980..9ee34d5 100644 (file)
@@ -4,3 +4,15 @@ breaks.
 Once it all builds and the syscall and some minimal driver code is filled in
 it ought to come in at about 20KW for a pure swap based system so probably
 not useful on an MMUless /11 except for testing.
+
+Boot notes:
+       start block with nop apparently sometimes needed
+       Generally first block, but on rx appears to be first sector of track 1
+       (not 0 as expected)
+
+Boot logic:
+       Load inode 1 (hardcoded offset)
+       Walk direct link blocks looking for /bootstrap
+       Load only direct blocks of the referenced inode
+
+       Run /bootstrap
diff --git a/Kernel/platform-pdp11/boot-rx0.s b/Kernel/platform-pdp11/boot-rx0.s
new file mode 100644 (file)
index 0000000..1d4256d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *     Boot off an RX0. 
+ */
+
+start:
+       nop
+       mov     $hello,r0
+loop:
+       movb    0177564,r2
+       bpl     loop
+       movb    (r0)+,r1
+       beq     done
+       movb    r1,0177566
+       br      loop
+done:
+       jsr     pc, donereq
+       mov     $0x200,r0
+       movb    $111, r1                // 111 blocks is our 56K
+       mov     $0177170,r2             // controller base
+       movb    $1,r3                   // sector
+       movb    $2,r4                   // track
+next:
+       movb    $0x07,(r2)
+       jsr     pc, txwait
+       movb    r3,2(r2)
+       jsr     pc, txwait
+       movb    r4,2(r2)
+       jsr     pc, donereq
+
+       movb    $0x80,r5
+       movb    $0x03,(r2)
+load:
+       tstb    (r2)
+       bpl     load
+       movb    2(r2),(r0)+
+       dec     r5
+       bne     load
+
+       dec     r1
+       beq     _finished
+       inc     r3
+       cmp     $27,r3
+       bne     next
+       movb    $1,r3
+       inc     r4
+       br      done
+
+donereq:
+       bis     $0x20,(r2)
+       beq     donereq
+       rts     pc
+
+txwait:
+       tstb    (r2)
+       bpl     txwait
+       rts     pc
+
+_finished:
+       jmp     0x200
+
+hello: .asciz "Loading Fuzix..."
index 10e8889..9ffee1a 100644 (file)
@@ -38,5 +38,5 @@
 /* Device parameters */
 #define NUM_DEV_TTY 1
 #define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
-#define NBUFS    6        /* Number of block buffers */
+#define NBUFS    5        /* Number of block buffers */
 #define NMOUNTS         2        /* Number of mounts at a time */
diff --git a/Kernel/platform-pdp11/dev_rk.c b/Kernel/platform-pdp11/dev_rk.c
new file mode 100644 (file)
index 0000000..cdb11d6
--- /dev/null
@@ -0,0 +1,139 @@
+/* 
+ * PDP/11 RK05 cartridge driver
+ * We assume RK05 packs for PDP/11 the moment (2/202/12 geometry)
+ *
+ * Also assumed is one unit. But that's easily fixed
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <dev_rk.h>
+
+static uint16_t *rkds = (uint16_t *)0177400;
+static uint16_t *rker = (uint16_t *)0177402;
+static uint16_t *rkcs = (uint16_t *)0177404;
+static uint16_t *rkwc = (uint16_t *)0177406;
+static uint16_t *rkba = (uint16_t *)0177410;
+static uint16_t *rkda = (uint16_t *)0177412;
+
+static int rk_probe(uint8_t minor)
+{
+    /* FIXME: timeout ?? */
+    while(!(*rkcs & 0x80));
+    *rkda = minor << 12;
+    *rkcs = 0x0B;      /* Drive reset, go */
+    while(!(*rkcs & 0x80));
+    /* Now check the drive status */
+    if (!(*rkds & 0x80))
+        return 0;
+    if (*rkds & 0x20)
+        return 3;
+    return 1;
+}
+    
+static int rk_transfer(bool is_read, uint8_t minor, uint8_t rawflag)
+{
+    uint16_t ct = 0;
+    uint16_t st;
+    uint16_t *page = NULL;
+    uint8_t cmd = is_read ?  4 : 2;
+
+    if (rk_offline & (1 << minor)) {
+        udata.u_error = EIO;
+        return -1;
+    }
+    if(rawflag == 1) {
+        if (d_blkoff(9))
+            return -1;
+        page =  &udata.u_page;
+#ifdef SWAPDEV
+    } else if (rawflag == 2) {         /* Swap device special */
+        page = &swappage;              /* Acting on this page */
+#endif
+    } else { /* rawflag == 0 */
+    }
+
+
+    /* We don't try and merge linearly sequential writes but these are so rare
+       (mkfs basically) even without vm.. We may want to reconsider for swap
+       however */
+    /* Overlapped seek is also supported but we can't really use it */
+
+    while (ct < udata.u_nblock) {
+        /* It's not quite as simple as it seems because while there is a single
+           disk address register it's up to use to set the bits properly for
+           sectors, suface, cylinder, drive */
+        uint16_t darv = minor << 13;
+        uint8_t sector;
+        uint8_t surface = 0x00;
+        uint16_t cylinder;
+
+        /* Assume a PDP/11 catridge not a PDP/8 one */
+        sector = udata.u_block % 12;
+        cylinder = udata.u_block /12;
+        /* Check this logic: there are spare tracks but are they hard/soft
+           spared ? */
+        if (cylinder > 202) {
+            cylinder -= 202;
+            surface = 0x10;
+        }
+        darv |= sector | surface
+        darv |= (cylinder << 5);
+
+        /* Wait until ready */        
+        while(!(*rkcd & 0x80));
+
+        /* Load the target, addresses and command */
+        *rkda = darv;
+        *rkwc = -256;  /* 512 bytes for now */
+        *rkba = udata.u_dptr;
+        *rkcs = cmd | 1;       /* Needs top bits of VA when we do virtual */
+
+        while(!(*rkcd & 0x80));
+
+        st = *rker;
+        if (st) {
+            kprintf("fd%d: block %d, error %x/%x\n", minor, udata.u_block, st,
+                *rkds);
+            if (st & 0xFFF0)
+                rk_offline |= (1 << minor);
+            break;
+        }
+        udata.u_block++;
+        ct++;
+        udata.u_dptr += 512;
+    }
+    return ct << 9;
+}
+
+/* For now assume a single controller, max 8 packs, no partitioning support */
+
+int rk_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    uint8_t r;
+    /* No such drive or drive not loaded */
+    if(minor >= 8 || !(r = rk_probe(minor))) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    /* Read only media */
+    if ((r & 2) && O_ACCMODE(flag)) {
+        udata.u_error = EROFS;
+        return -1;
+    }
+    return 0;
+}
+
+int rk_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return rk_transfer(true, minor + 8, rawflag);
+}
+
+int rk_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return rk_transfer(false, minor + 8, rawflag);
+}
diff --git a/Kernel/platform-pdp11/dev_rx.c b/Kernel/platform-pdp11/dev_rx.c
new file mode 100644 (file)
index 0000000..577e552
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *     Driver for an RX floppy disk controller
+ *
+ *     77 track, 26 sector per track, 128 byte per sector floppy
+ *
+ *     Usually lives at 17170/2 (command/status at 0 data at 2)
+ *
+ *     See "RX8/RX11 Floppy Disk System User's Manual EK-RX01-OP-001"
+ */
+
+#include <kernel.h>
+#include <printf.h>
+#include <dev_rx.h>
+
+#define GO             0x01
+
+#define CMD_FILL       0x00
+#define CMD_EMPTY      0x02
+#define CMD_WRITE      0x04
+#define CMD_READ       0x06
+#define CMD_READSTAT   0x08
+#define CMD_FORMAT     0x0A    /* Set density (later models only) */
+#define CMD_WRITEDEL   0x0C
+#define CMD_READERROR  0x0E
+
+#define DRIVE_B                0x10
+#define DONE           0x20
+#define INTEN          0x40
+#define XFERRQ         0x80
+#define INTIALIZE      0x4000
+#define ERROR          0x8000
+
+static uint16_t *dev = (uint16_t *)0177170;
+static uint8_t drive;
+static uint8_t track;
+static uint8_t sector;
+
+static void issue_read(void)
+{
+    uint8_t x;
+    uint8_t ct = 0;
+    /* Might want timeouts here */
+
+    /* Wait for it to stop being busy  */
+    while(!(*dev & DONE));     
+    *dev = CMD_READ|GO|drive;  /* READ|GO|DRIVE_B etc */
+    while(!(*dev & XFERRQ));
+    dev[1] = sector;           /* When ready send the sector */
+    while(!(*dev & XFERRQ));
+    dev[1] = track;            /* And the track */
+
+    /* The controller will no go off and get the sector */
+    while(!(*dev & DONE));
+    
+    /* Now read the buffer */
+    *dev = CMD_EMPTY|GO;       /* Ready for xfer */
+    while(ct < 128) {
+        x = *dev;
+        if (x & XFERRQ) {
+            *udata.u_dptr++ = dev[1];  /* Store byte */
+            ct++:
+        }
+        /* An early done means an error */
+        if (x & DONE)
+            break;             /* Error */
+    }
+    return dev[1];     /* Error bits */
+}
+
+static void issue_write(void)
+{
+    uint8_t x;
+    uint8_t ct = 0;
+    while(!(*dev & DONE));     /* Make sure we are not busy */
+
+    /* We need to fill the buffer */
+    *dev = CMD_FILL|GO;        /* Ready for xfer */
+    while(ct < 128) {
+        x = *dev;
+        if (x & 0x80) {                /* Failure */
+            dev[1] = *udata.u_dptr+;   /* Store byte */
+            ct++:
+        }
+        if (x & DONE)
+            break;             /* Error */
+    }
+    /* Error in xfer ? */
+    if (dev[0] & (1 << 15)))
+        return dev[1];
+    /* Now we have copied the buffer into the controller we issue an I/O */
+    *dev = CMD_WRITE|GO|drive; /* READ|GO|DRIVE_B etc */
+    while(!(*dev & XFERRQ));
+    dev[1] = sector;
+    while(!(*dev & XFERRQ));
+    dev[1] = track;
+    
+    /* Wait for the write to complete or error */
+    while(!(*dev & DONE));
+    return dev[1];     /* Error bits */
+}
+
+static int probe_drive(void)
+{
+    while(!(*dev & DONE));
+    *dev = CMD_READSTAT|GO|drive;
+    while(!(*dev & DONE));
+    return (*dev & 0x80);
+}
+
+static int rx_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+    int ct = 0;
+    int tries;
+    uint8_t err = 0;
+    uint16_t ptr;
+
+    if(rawflag == 2)
+        goto bad2;
+
+    rx_map = rawflag;
+    if (rawflag && d_blkoff(BLKSHIFT))
+            return -1;
+
+    /* In 128's */
+    udata.u_nblock *= 4;
+    udata.u_block *= 4;
+
+    drive = (minor & 1) ? DRIVE_B : 0;
+
+    while (ct < udata.u_nblock) {
+        track = udata.u_block /26;
+        sector = (udata.u_block % 26) + 1;
+        for (tries = 0; tries < 4 ; tries++) {
+            ptr = udata.u_dptr;
+            err = (is_read ? issue_read : issue_write)(dev))
+            if (err == 0)
+                break;
+            udata.u_dptr = ptr;
+            if (tries > 1)
+                rx_reset(driveptr);
+        }
+        /* FIXME: should we try the other half and then bale out ? */
+        if (tries == 4)
+            goto bad;
+        ct++;
+        udata.u_block++;
+    }
+    return ct << 7;
+bad:
+    kprintf("rx%d: error %x\n", minor, err);
+bad2:
+    udata.u_error = EIO;
+    return -1;
+}
+
+int rx_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    drive = (minor & 1) ? DRIVE_B : 0;
+    if(minor >= MAX_FD || !probe_drive()) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
+
+int rx_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return rx_transfer(minor, true, rawflag);
+}
+
+int rx_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;rawflag;minor;
+    return rx_transfer(minor, false, rawflag);
+}
+    
\ No newline at end of file
index 3954fa8..eb00d3a 100644 (file)
@@ -6,8 +6,10 @@
 #include <device.h>
 #include <tty.h>
 
-volatile uint8_t *uart_data = (volatile uint8_t *)0xF03000;    /* UART data */
-volatile uint8_t *uart_status = (volatile uint8_t *)0xF03010;  /* UART status */
+volatile uint16_t *uart_rxstatus = (volatile uint16_t *)0177560;
+volatile uint8_t *uart_rxdata = (volatile uint8_t *)0177562;
+volatile uint8_t *uart_txstatus = (volatile uint8_t *)0177564;
+volatile uint8_t *uart_txdata = (volatile uint8_t *)0177566;
 
 unsigned char tbuf1[TTYSIZ];
 
@@ -26,13 +28,14 @@ void kputchar(char c)
 
 ttyready_t tty_writeready(uint8_t minor)
 {
-       uint8_t c = *uart_status;
-       return (c & 2) ? TTY_READY_NOW : TTY_READY_SOON; /* TX DATA empty */
+       uint8_t c = *uart_txstatus;
+       return (c & 0x80) ? TTY_READY_NOW : TTY_READY_SOON;
 }
 
 void tty_putc(uint8_t minor, unsigned char c)
 {
-       *uart_data = c; /* Data */
+       /* Just the console for now */
+       *uart_txdata = c;
 }
 
 void tty_setup(uint8_t minor)
@@ -51,9 +54,9 @@ void tty_sleeping(uint8_t minor)
 /* Currently run off the timer */
 void tty_interrupt(void)
 {
-       uint8_t r = *uart_status;
-       if (r & 1) {
-               r = *uart_data;
+       uint8_t r = *uart_rxstatus;
+       if (r & 0x80) {
+               r = *uart_rxdata;
                tty_inproc(1,r);
        }       
 }