trs80m1: add initial exatron support
authorAlan Cox <alan@linux.intel.com>
Tue, 3 Jul 2018 15:48:04 +0000 (16:48 +0100)
committerAlan Cox <alan@linux.intel.com>
Tue, 3 Jul 2018 15:48:04 +0000 (16:48 +0100)
We need something to develop tape code against and the stringy floppy is nice
and easy on the Model I because it's a ROM full of nice helpers..

Kernel/platform-trs80m1/Makefile
Kernel/platform-trs80m1/devgfx.c
Kernel/platform-trs80m1/devices.c
Kernel/platform-trs80m1/devstringy.c [new file with mode: 0644]
Kernel/platform-trs80m1/devstringy.h [new file with mode: 0644]
Kernel/platform-trs80m1/fuzix.lnk
Kernel/platform-trs80m1/stringy.s [new file with mode: 0644]
Kernel/platform-trs80m1/trs80.s

index fb75cdb..e878e47 100644 (file)
@@ -1,10 +1,10 @@
 
 CSRCS = devlpr.c devtty.c devfd.c devfd3.c devhd.c devgfx.c
-CSRCS += devices.c main.c
+CSRCS += devices.c main.c devstringy.c
 DISCARD_CSRCS = discard.c devhd_discard.c
 
 ASRCS = trs80.s trs80-bank.s crt0.s vtsupport.s
-ASRCS += tricks.s commonmem.s floppy.s floppy3.s
+ASRCS += tricks.s commonmem.s floppy.s floppy3.s stringy.s
 
 COBJS = $(CSRCS:.c=.rel)
 AOBJS = $(ASRCS:.s=.rel)
index 24f459a..d7feb4d 100644 (file)
@@ -170,7 +170,7 @@ void gfx_init(void)
       max_mode = 1;
       displaymap[1] = 1;
     } else {
-      uint8_t *fb = 0x3C00;
+      uint8_t *fb = (uint8_t *)0x3C00;
       uint8_t c = *fb;
       *fb = 128;
       ioctrl = 0xB2;
index 99ed5bc..16d5829 100644 (file)
@@ -11,6 +11,7 @@
 #include <devtty.h>
 #include <devgfx.h>
 #include <devfd3.h>
+#include <devstringy.h>
 #include <trs80.h>
 
 struct devsw dev_tab[] =  /* The device driver switch table */
@@ -25,6 +26,14 @@ struct devsw dev_tab[] =  /* The device driver switch table */
   {  lpr_open,    lpr_close,    no_rdwr,   lpr_write,  no_ioctl  },
   /* 4: /dev/mem etc   System devices (one offs) */
   {  no_open,     no_close,     sys_read,  sys_write,  sys_ioctl },
+  /* 5: reserved */
+  {  nxio_open,     no_close,   no_rdwr,   no_rdwr,    no_ioctl },
+  /* 6: reserved */
+  {  nxio_open,     no_close,   no_rdwr,   no_rdwr,    no_ioctl },
+  /* 7: reserved */
+  {  nxio_open,     no_close,   no_rdwr,   no_rdwr,    no_ioctl },
+  /* 8: tape (for now - may move to 5 if lots of boxes have tape) */
+  {  tape_open,     tape_close, tape_read, tape_write, tape_ioctl },
 };
 
 bool validdev(uint16_t dev)
@@ -43,5 +52,6 @@ void floppy_setup(void)
     dev_tab[1].dev_open = fd3_open;
     dev_tab[1].dev_read = fd3_read;
     dev_tab[1].dev_write = fd3_write;
+    dev_tab[8].dev_open = nxio_open;
   }
 }
diff --git a/Kernel/platform-trs80m1/devstringy.c b/Kernel/platform-trs80m1/devstringy.c
new file mode 100644 (file)
index 0000000..a7c91db
--- /dev/null
@@ -0,0 +1,185 @@
+#include <kernel.h>
+#include <version.h>
+#include <tape.h>
+#include <kdata.h>
+#include <devlpr.h>
+#include <printf.h>
+#include <devstringy.h> 
+
+/*
+ *     Stringy tape wrapper. Note that the asm code uses the ROM which
+ *     also uses some values in 0x40xx (40B1 and 401A in particular)
+ */
+static uint8_t fileid = 255;
+static uint8_t mode;
+static uint8_t inpos = 0;              /* in position */
+static uint8_t inio = 0;
+static int busy = 0;
+uint8_t tape_err;
+
+static int tape_error(void)
+{
+    uint8_t a = tape_err;
+    tape_err = 0;
+
+    /* EOF on read */
+    if (a & 0x80)
+        return 0;
+    /* BREAK */        
+    if (a & 0x02)
+        udata.u_error = EINTR;
+    /* End of tape while writing */
+    else if (a & 0x04)
+        udata.u_error = ENOSPC;
+    /* Buffer too small (read) */
+    else if (a & 0x20)
+        udata.u_error = EINVAL;        /* Not a good error for this really */
+    else
+        udata.u_error = EIO;
+    kprintf("tape: error %x\n", a);
+    return -1;
+}
+
+static int tape_rewind(void)
+{
+    if (!tape_op(0, TAPE_REWIND)) {
+       /* rewind */
+       fileid = 1;
+        inpos = 0;
+        return 0;
+    }
+    return tape_error();
+}
+
+int tape_open(uint8_t minor, uint16_t flag)
+{
+    minor; flag;
+
+    /* Check for the floppy tape ROM */
+    if (*((uint16_t *)0x3034) != 0x3C3C) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    if (busy) {
+        udata.u_error = EBUSY;
+        return -1;
+    }
+
+    if (minor > 15 || tape_op(minor & 0x07, TAPE_SELECT)) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    /* Can't open for mixed read/write at the same time */
+    if (O_ACCMODE(flag) == O_RDWR) {
+        udata.u_error = EINVAL;
+        return -1;
+    }
+    mode = O_ACCMODE(flag);
+
+    if ((minor & 0x08) || fileid == 255)
+        if (tape_rewind())
+            return -1;
+    /* Only one drive can be used at a time */
+    busy = 1;
+    inio = 0;
+    tape_err = 0;
+    return 0;
+}
+
+int tape_close(uint8_t minor)
+{
+    minor;
+    if (mode == O_WRONLY)
+        if (tape_op(fileid, TAPE_CLOSEW))
+            return tape_error();
+    return 0;
+}
+
+static int tape_rw(uint8_t op)
+{
+    if (!inpos) {
+        if (tape_op(fileid, TAPE_FIND) == 0)
+            inpos = 1;
+        else 
+            return tape_error();
+            
+    }
+    inio = 1;
+    udata.u_done = tape_op(fileid, op);
+    if (tape_err)
+        return tape_error();
+    return udata.u_done;
+}
+
+int tape_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    used(minor);
+    used(rawflag);
+    used(flag);
+    return tape_rw(TAPE_READ);
+}
+
+int tape_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    used(minor);
+    used(rawflag);
+    used(flag);
+    return tape_rw(TAPE_WRITE);
+}
+
+static struct mtstatus tapei = {
+    MT_TYPE_EXATRON,
+    0,
+    ~0
+};
+
+int tape_ioctl(uint8_t minor, uarg_t op, char *ptr)
+{
+    used(minor);
+
+    switch(op) {
+        case MTSTATUS:
+            if (inpos)
+                tapei.mt_file = fileid;
+            else
+                tapei.mt_file = ~0;
+            return uput(&tapei, ptr, sizeof(tapei));
+    }
+    /* Now calls we can only make when not mid stream */
+    if (mode || inio)
+        goto bad;
+
+    switch (op) {
+    case MTREWIND:
+        return tape_rewind();
+    case MTSEEKF:
+        if (fileid > 99)
+            goto bad;
+        fileid++;
+        if (tape_op(fileid, TAPE_FIND))
+            goto bad;
+        inpos = 1;
+        return 0;
+    case MTSEEKB:
+        if (fileid < 2)
+            goto bad;
+        fileid--;
+        if (tape_op(fileid, TAPE_FIND))
+            goto bad;
+        inpos = 1;
+        return 0;
+    case MTERASE:
+        /* Erase from this point to the end of tape */
+        if (fileid > 99)
+            goto bad;
+        if (tape_op(fileid, TAPE_ERASE))
+            goto bad;
+        inpos = 0;
+        return 0;
+    default:
+        return -1;
+    }
+bad:
+    udata.u_error = EINVAL;
+    return -1;
+}
diff --git a/Kernel/platform-trs80m1/devstringy.h b/Kernel/platform-trs80m1/devstringy.h
new file mode 100644 (file)
index 0000000..d79cf45
--- /dev/null
@@ -0,0 +1,21 @@
+
+
+/* Must match the order in tape_op in the asm */
+#define TAPE_WRITE     0
+#define TAPE_READ      1
+#define TAPE_CLOSEW    2
+#define TAPE_REWIND    3
+#define TAPE_FIND      4
+#define TAPE_SELECT    5
+#define TAPE_ERASE     6
+
+extern int tape_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int tape_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int tape_ioctl(uint8_t minor, uarg_t op, char *ptr);
+extern int tape_open(uint8_t minor, uint16_t flag);
+extern int tape_close(uint8_t minor);
+
+extern int tape_op(uint8_t id, uint8_t op);
+
+
+
index b07417c..ccb011b 100644 (file)
@@ -27,6 +27,8 @@ platform-trs80m1/floppy3.rel
 platform-trs80m1/devhd.rel
 platform-trs80m1/devhd_discard.rel
 platform-trs80m1/devgfx.rel
+platform-trs80m1/devstringy.rel
+platform-trs80m1/stringy.rel
 platform-trs80m1/devices.rel
 devio.rel
 filesys.rel
diff --git a/Kernel/platform-trs80m1/stringy.s b/Kernel/platform-trs80m1/stringy.s
new file mode 100644 (file)
index 0000000..eb3a95f
--- /dev/null
@@ -0,0 +1,95 @@
+       .module stringy
+
+       .globl  _tape_op
+       .globl  _tape_err
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+       .area _COMMONMEM
+
+       .globl _tape_op
+
+       .globl go_slow
+       .globl go_fast
+
+_tape_op:
+       call go_slow
+       pop bc
+       pop de
+       push de         ; file ID in D op in E
+       push bc
+       ld hl,(U_DATA__U_BASE)
+       ld bc,(U_DATA__U_COUNT)
+       xor a
+       ld (_tape_err),a
+       ld a,e
+       or a
+       jr z, write_op
+       dec a
+       jr z, read_op
+       dec a
+       jr z, closew_op
+       dec a
+       jr z, rewind_op
+       dec a
+       jr z, seekf_op
+       dec a
+       jr z, select_op
+       dec a
+       jr z, erase_op
+       ld hl,#0xFFFF
+       call go_fast
+       ret
+find_op:
+       ld a,d
+       call 0x300F
+       jr tape_error
+select_op:
+       ld a,d                  ; not a file ID but a drive ID this time
+       call 0x3012
+       jr tape_error
+seekf_op:
+       ld a,d
+       call 0x300F             ; find file A
+tape_error:
+       push af
+       call go_fast
+       pop af
+       ld hl,#0                ; return 0 if good or -1 if bad and save err
+       ret z
+       dec hl
+       ld (_tape_err),a
+       ret
+closew_op:
+       ld a,d
+       ld bc,#0
+       call 0x3027             ; Write an EOF and the marker for the next
+       jr tape_error           ; file ID
+rewind_op:
+       call 0x3000             ; Go back to start of tape (does not find
+       jr tape_error           ; file 0 itself)
+read_op:
+       call 0x3003
+       push af
+       call go_fast
+       pop af
+       ld h,b
+       ld l,c                  ; actual bytes fetched
+       ret z
+rwerr:
+       ld (_tape_err),a
+       ld hl,#0xffff
+       ret
+write_op:
+       call 0x3006
+       push af
+       call go_fast
+       pop af
+       ld hl,(U_DATA__U_COUNT)
+       ret z
+       jr rwerr
+erase_op:
+       ld a,d
+       call 0x3024
+       jr tape_error
index 31c35ea..da89ba7 100644 (file)
@@ -133,6 +133,8 @@ not_vg:
 ;      The Model 3 sprinter type card uses port 95h the same way but
 ;      also does automatic slow down when needed
 ;
+;      Only allowed to mess with AF
+;
 go_slow:
            ld a,(_trs80_model)
            or a