ubee: initial bits cloned from the TRS80 to begin a Microbee 128/256/512 port
authorAlan Cox <alan@linux.intel.com>
Sun, 21 Dec 2014 17:55:15 +0000 (17:55 +0000)
committerAlan Cox <alan@linux.intel.com>
Sun, 21 Dec 2014 17:55:15 +0000 (17:55 +0000)
17 files changed:
Kernel/platform-ubee/Makefile [new file with mode: 0644]
Kernel/platform-ubee/README [new file with mode: 0644]
Kernel/platform-ubee/config.h [new file with mode: 0644]
Kernel/platform-ubee/devfd.c [new file with mode: 0644]
Kernel/platform-ubee/devfd.h [new file with mode: 0644]
Kernel/platform-ubee/devhd.c [new file with mode: 0644]
Kernel/platform-ubee/devhd.h [new file with mode: 0644]
Kernel/platform-ubee/devices.c [new file with mode: 0644]
Kernel/platform-ubee/devlpr.c [new file with mode: 0644]
Kernel/platform-ubee/devlpr.h [new file with mode: 0644]
Kernel/platform-ubee/devtty.c [new file with mode: 0644]
Kernel/platform-ubee/devtty.h [new file with mode: 0644]
Kernel/platform-ubee/floppy.s [new file with mode: 0644]
Kernel/platform-ubee/kernel.def [new file with mode: 0644]
Kernel/platform-ubee/main.c [new file with mode: 0644]
Kernel/platform-ubee/ubee.s [new file with mode: 0644]
Kernel/platform-ubee/uzi.lnk [new file with mode: 0644]

diff --git a/Kernel/platform-ubee/Makefile b/Kernel/platform-ubee/Makefile
new file mode 100644 (file)
index 0000000..7f90738
--- /dev/null
@@ -0,0 +1,25 @@
+
+CSRCS = devlpr.c devtty.c devfd.c devhd.c
+CSRCS += devices.c main.c
+
+ASRCS = ubee.s crt0.s
+ASRCS += tricks.s commonmem.s floppy.s
+
+COBJS = $(CSRCS:.c=.rel)
+AOBJS = $(ASRCS:.s=.rel)
+OBJS  = $(COBJS) $(AOBJS)
+
+JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst)
+
+all:   $(OBJS)
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) $<
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ 
+
+image:
diff --git a/Kernel/platform-ubee/README b/Kernel/platform-ubee/README
new file mode 100644 (file)
index 0000000..6428881
--- /dev/null
@@ -0,0 +1 @@
+uBee draft code
diff --git a/Kernel/platform-ubee/config.h b/Kernel/platform-ubee/config.h
new file mode 100644 (file)
index 0000000..63d3962
--- /dev/null
@@ -0,0 +1,53 @@
+/* Enable to make ^Z dump the inode table for debug */
+#undef CONFIG_IDUMP
+/* Enable to make ^A drop back into the monitor */
+#undef CONFIG_MONITOR
+/* Profil syscall support (not yet complete) */
+#define CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#define CONFIG_MULTI
+/* Single tasking */
+#undef CONFIG_SINGLETASK
+/* Video terminal, not a serial tty */
+#define CONFIG_VT
+/* Simple character addressed device */
+#define CONFIG_VT_SIMPLE
+/* Banked memory set up */
+#define CONFIG_BANK_FIXED
+#define MAX_MAPS       32              /* 1MByte... */
+#define MAP_SIZE       0x8000
+
+#define CONFIG_BANKS   2       /* 2 x 32K */
+
+/* Vt definitions */
+#define VT_BASE                ((uint8_t *)0xF000)
+#define VT_WIDTH       80
+#define VT_HEIGHT      24
+#define VT_RIGHT       79
+#define VT_BOTTOM      23
+
+#define TICKSPERSEC 60   /* Ticks per second */
+#define PROGBASE    0x0000  /* Base of user  */
+#define PROGLOAD    0x0100  /* Load and run here */
+#define PROGTOP     0x7D00  /* Top of program, base of U_DATA stash */
+#define PROC_SIZE   32             /* Memory needed per process */
+
+#define SWAP_SIZE   0x40       /* 32K in blocks */
+#define SWAPBASE    0x0000     /* We swap the lot in one, include the */
+#define SWAPTOP            0x8000      /* vectors so its a round number of sectors */
+
+#define MAX_SWAPS      16      /* Should be plenty */
+
+#define BOOT_TTY (512 + 1)      /* Set this to default device for stdio, stderr */
+                          /* In this case, the default is the first TTY device */
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE        NULL      /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 2
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define SWAPDEV  (256)   /* Device for swapping (1st hd). */
+#define NBUFS    10       /* Number of block buffers */
+#define NMOUNTS         4        /* Number of mounts at a time */
+
diff --git a/Kernel/platform-ubee/devfd.c b/Kernel/platform-ubee/devfd.c
new file mode 100644 (file)
index 0000000..9b08ebc
--- /dev/null
@@ -0,0 +1,104 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devfd.h>
+
+#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;
+static uint8_t fd_selected = 0xFF;
+static uint8_t fd_tab[MAX_FD] = { 0xFF, 0xFF, 0xFF, 0xFF };
+
+/*
+ *     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 fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+    blkno_t block;
+    uint16_t dptr;
+    int ct = 0;
+    int tries;
+    uint8_t err = 0;
+    uint8_t *driveptr = fd_tab + minor;
+    uint8_t cmd[6];
+
+    if(rawflag)
+        goto bad2;
+
+    if (fd_selected != minor) {
+        uint8_t err;
+        /* FIXME: We force DD for now */
+        err = fd_motor_on(selmap[minor]|0x80);
+        if (err)
+            goto bad;
+    }
+
+    if (*driveptr == 0xFF)
+        fd_reset(driveptr);
+
+    dptr = (uint16_t)udata.u_buf->bf_data;
+    block = udata.u_buf->bf_blk;
+
+    cmd[0] = is_read ? FD_READ : FD_WRITE;
+    cmd[1] = block / 9;                /* 2 sectors per block */
+    cmd[2] = ((block % 9) << 1) + 1;   /*eww.. */
+    cmd[3] = is_read ? OPDIR_READ: OPDIR_WRITE;
+    cmd[4] = dptr & 0xFF;
+    cmd[5] = dptr >> 8;
+
+    while (ct < 2) {
+        for (tries = 0; tries < 4 ; tries++) {
+            err = fd_operation(cmd, driveptr);
+            if (err == 0)
+                break;
+            if (tries > 1)
+                fd_reset(driveptr);
+        }
+        /* FIXME: should we try the other half and then bale out ? */
+        if (tries == 4)
+            goto bad;
+        cmd[5]++;      /* Move on 256 bytes in the buffer */
+        cmd[2]++;      /* Next sector for 2nd block */
+        ct++;
+    }
+    return 1;
+bad:
+    kprintf("fd%d: error %x\n", minor, err);
+bad2:
+    udata.u_error = EIO;
+    return -1;
+}
+
+int fd_open(uint8_t minor, uint16_t flag)
+{
+    flag;
+    if(minor >= MAX_FD) {
+        udata.u_error = ENODEV;
+        return -1;
+    }
+    return 0;
+}
+
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;
+    return fd_transfer(minor, true, rawflag);
+}
+
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    flag;rawflag;minor;
+//    return 0;
+    return fd_transfer(minor, false, rawflag);
+}
diff --git a/Kernel/platform-ubee/devfd.h b/Kernel/platform-ubee/devfd.h
new file mode 100644 (file)
index 0000000..5f94507
--- /dev/null
@@ -0,0 +1,15 @@
+#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 flag);
+
+/* low level interface */
+uint16_t fd_reset(uint8_t *driveptr);
+uint16_t fd_operation(uint8_t *cmd, uint8_t *driveptr);
+uint16_t fd_motor_on(uint16_t drivesel);
+uint16_t fd_motor_off(uint16_t driveptr);
+
+#endif /* __DEVFD_DOT_H__ */
diff --git a/Kernel/platform-ubee/devhd.c b/Kernel/platform-ubee/devhd.c
new file mode 100644 (file)
index 0000000..9539704
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ *     WD1010 hard disk driver
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devhd.h>
+
+__sfr __at 0x40 hd_data;
+__sfr __at 0x41 hd_precomp;    /* W/O */
+__sfr __at 0x41 hd_err;                /* R/O */
+__sfr __at 0x42 hd_seccnt;
+__sfr __at 0x43 hd_secnum;
+__sfr __at 0x44 hd_cyllo;
+__sfr __at 0x45 hd_cylhi;
+__sfr __at 0x46 hd_sdh;
+__sfr __at 0x47 hd_status;     /* R/O */
+__sfr __at 0x47 hd_cmd;
+__sfr __at 0x48 hd_fdcside;    /* Side select for FDC */
+
+#define HDCMD_RESTORE  0x10
+#define HDCMD_READ     0x20
+#define HDCMD_WRITE    0x30
+#define HDCMD_VERIFY   0x40    /* Not on the 1010 later only */
+#define HDCMD_FORMAT   0x50
+#define HDCMD_INIT     0x60    /* Ditto */
+#define HDCMD_SEEK     0x70
+
+#define HDSDH_ECC256           0x80
+
+/* Used by the asm helpers */
+uint8_t hd_page;
+
+/* Seek and restore low 4 bits are the step rate, read/write support
+   multi-sector mode but not all emulators do .. */
+
+#define MAX_HD 4
+
+/* Wait for the drive to show ready */
+static uint8_t hd_waitready(void)
+{
+       uint8_t st;
+       do {
+               st = hd_status;
+       } while (!(st & 0x40));
+       return st;
+}
+
+/* Wait for DRQ or an error */
+static uint8_t hd_waitdrq(void)
+{
+       uint8_t st;
+       do {
+               st = hd_status;
+       } while (!(st & 0x09));
+       return st;
+}
+
+/* FIXME: move this to asm in _COMMONMEM and support banks and swap */
+static uint8_t hd_xfer(bool is_read, uint16_t addr)
+{
+       /* Error ? */
+       if (hd_status & 0x01)
+               return hd_status;
+       if (is_read)
+               hd_xfer_in(addr);
+       else
+               hd_xfer_out(addr);
+       /* Should be returning READY, and maybe SEEKDONE */
+       return hd_status;
+}
+
+/*
+ *     We only support normal block I/O for the moment. We do need to
+ *     add swapping!
+ */
+
+static int hd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+       blkno_t block;
+       uint16_t dptr;
+       uint16_t ct = 0;
+       int tries;
+       uint8_t err = 0;
+       uint8_t cmd = HDCMD_READ;
+       uint8_t head;
+       uint8_t sector;
+       uint16_t nblock;
+
+       if (rawflag == 0) {
+               dptr = (uint16_t)udata.u_buf->bf_data;
+               block = udata.u_buf->bf_blk;
+               nblock = 2;
+               hd_page = 0;            /* Kernel */
+       } else if (rawflag == 2) {
+               nblock = swapcnt >> 8;  /* in 256 byte chunks */
+               dptr = (uint16_t)swapbase;
+               hd_page = swapproc->p_page;
+               block = swapblk;
+       } else
+               goto bad2;
+
+       if (!is_read)
+               cmd = HDCMD_WRITE;
+
+
+       /* We assume 32 sectors per track for now. From our 512 byte
+          PoV that's 16 */
+
+       /* For our test purposes we use a disk with 32 sectors, 4 heads so
+          our blocks map out as   00cccccc ccCCCCCC CCHHSSSS
+
+          This matches a real ST506 which is 153 cyls, 4 heads, 32 sector */
+
+       hd_precomp = 0x20;      /* For now, matches an ST506 */
+       hd_seccnt = 1;
+       block <<= 1;            /* Into 256 byte blocks, limits us to 32MB
+                                  so ought to FIXME */
+
+       while (ct < nblock) {
+               /* 32 sectors per track assumed for now */
+               sector = (block & 31) + 1;
+               head = (block >> 5) & 3;
+               /* Head next bits, plus drive */
+               hd_sdh = 0x80 | head | (minor << 3);
+               hd_secnum = sector;
+               /* cylinder bits */
+               hd_cyllo = (block >> 7) & 0xFF;
+               hd_cylhi = (block >> 15) & 0xFF;
+
+               for (tries = 0; tries < 4; tries++) {
+                       /* issue the command */
+                       hd_cmd = cmd;
+                       /* DRQ will go high once the controller is ready
+                          for us */
+                       err = hd_waitdrq();
+                       if (!(err & 1)) {
+                               err = hd_xfer(is_read, dptr);
+                               /* Ready, no error ? */
+                               if ((err & 0x41) == 0x40)
+                                       break;
+                       } else
+                               kprintf("hd%d: err %x\n", minor, err);
+
+                       if (tries > 1) {
+                               hd_cmd = HDCMD_RESTORE;
+                               if (hd_waitready() & 1)
+                                       kprintf("hd%d: restore error %z\n", minor, err);
+                       }
+               }
+               /* FIXME: should we try the other half and then bale out ? */
+               if (tries == 3)
+                       goto bad;
+               ct++;
+               dptr += 256;
+               block ++;
+       }
+       return 1;
+bad:
+       if (err & 1)
+               kprintf("hd%d: error %x\n", minor, hd_err);
+       else
+               kprintf("hd%d: status %x\n", minor, err);
+bad2:
+       udata.u_error = EIO;
+       return -1;
+}
+
+int hd_open(uint8_t minor, uint16_t flag)
+{
+       flag;
+       if (minor >= MAX_HD) {
+               udata.u_error = ENODEV;
+               return -1;
+       }
+
+       return 0;
+}
+
+int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       flag;
+       return hd_transfer(minor, true, rawflag);
+}
+
+int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+       flag;
+       return hd_transfer(minor, false, rawflag);
+}
diff --git a/Kernel/platform-ubee/devhd.h b/Kernel/platform-ubee/devhd.h
new file mode 100644 (file)
index 0000000..41200a7
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __DEVHD_DOT_H__
+#define __DEVHD_DOT_H__
+
+/* public interface */
+int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int hd_open(uint8_t minor, uint16_t flag);
+
+/* helpers in common memory for the block transfers */
+int hd_xfer_in(uint16_t addr);
+int hd_xfer_out(uint16_t addr);
+
+#endif /* __DEVHD_DOT_H__ */
diff --git a/Kernel/platform-ubee/devices.c b/Kernel/platform-ubee/devices.c
new file mode 100644 (file)
index 0000000..fdb13ac
--- /dev/null
@@ -0,0 +1,42 @@
+#include <kernel.h>
+#include <tty.h>
+#include <version.h>
+#include <kdata.h>
+#include <devfd.h>
+#include <devhd.h>
+#include <devsys.h>
+#include <devlpr.h>
+#include <devtty.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+  /* 0: /dev/fd                Floppy disc block devices */
+  {  fd_open,     no_close,     fd_read,   fd_write,   no_ioctl  },
+  /* 1: /dev/hd                Hard disc block devices */
+  {  hd_open,     no_close,     hd_read,   hd_write,   no_ioctl  },
+  /* 2: /dev/tty       TTY devices */
+  {  tty_open,    tty_close,    tty_read,  tty_write,  tty_ioctl },
+  /* 3: /dev/lpr       Printer devices */
+  {  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 },
+  /* Pack to 7 with nxio if adding private devices and start at 8 */
+};
+
+bool validdev(uint16_t dev)
+{
+    /* This is a bit uglier than needed but the right hand side is
+       a constant this way */
+    if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) + 255)
+       return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+  int i;
+  /* Add 64 swaps (2MB) */
+  for (i = MAX_SWAPS - 1 ; i >= 0; i--)
+    swapmap_add(i);
+}
diff --git a/Kernel/platform-ubee/devlpr.c b/Kernel/platform-ubee/devlpr.c
new file mode 100644 (file)
index 0000000..65d8c43
--- /dev/null
@@ -0,0 +1,38 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devlpr.h>
+
+__sfr __at 0x02 lpstat;                /* I/O 2 and 3 */
+__sfr __at 0x03 lpdata;
+
+int lpr_open(uint8_t minor, uint16_t flag)
+{
+    minor; flag; // shut up compiler
+    return 0;
+}
+
+int lpr_close(uint8_t minor)
+{
+    minor; // shut up compiler
+    return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    int c = udata.u_count;
+    char *p = udata.u_base;
+    minor; rawflag; flag; // shut up compiler
+
+    while(c) {
+        /* Note; on real hardware it might well be necessary to
+           busy wait a bit just to get acceptable performance */
+        while (lpstat != 0xFF) {
+//            if (psleep_flags(&clocktick, flag))
+//                return -1;
+        }
+        /* FIXME: tidy up ugetc and sysio checks globally */
+        lpdata = ugetc(p++);
+    }
+    return (-1);
+}
diff --git a/Kernel/platform-ubee/devlpr.h b/Kernel/platform-ubee/devlpr.h
new file mode 100644 (file)
index 0000000..7765c18
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __DEVLPR_DOT_H__
+#define __DEVLPR_DOT_H__
+
+int lpr_open(uint8_t minor, uint16_t flag);
+int lpr_close(uint8_t minor);
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+#endif
diff --git a/Kernel/platform-ubee/devtty.c b/Kernel/platform-ubee/devtty.c
new file mode 100644 (file)
index 0000000..9ec6ac5
--- /dev/null
@@ -0,0 +1,177 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <vt.h>
+#include <devtty.h>
+#include <stdarg.h>
+
+char tbuf1[TTYSIZ];
+char tbuf2[TTYSIZ];
+
+__sfr __at 0xE8 tr1865_ctrl;
+__sfr __at 0xE9 tr1865_baud;
+__sfr __at 0xEA tr1865_status;
+__sfr __at 0xEB tr1865_rxtx;
+
+struct s_queue ttyinq[NUM_DEV_TTY + 1] = {     /* ttyinq[0] is never used */
+       {NULL, NULL, NULL, 0, 0, 0},
+       {tbuf1, tbuf1, tbuf1, TTYSIZ, 0, TTYSIZ / 2},
+       {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2}
+};
+
+/* Write to system console */
+void kputchar(char c)
+{
+       if (c == '\n')
+               tty_putc(1, '\r');
+       tty_putc(1, c);
+}
+
+static bool tty_writeready(uint8_t minor)
+{
+       minor;
+       return 1;
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+       minor;
+       vtoutput(&c, 1);
+}
+
+void tty_setup(uint8_t minor)
+{
+       minor;
+}
+
+int tty_carrier(uint8_t minor)
+{
+        minor;
+       return 1;
+}
+
+#if 0
+static uint8_t keymap[8];
+static uint8_t keyin[8];
+static uint8_t keybyte, keybit;
+static uint8_t newkey;
+static int keysdown = 0;
+static uint8_t shiftmask[8] = {
+       0, 0, 0, 0, 0, 0, 0, 7
+};
+
+static void keyproc(void)
+{
+       int i;
+       uint8_t key;
+
+       for (i = 0; i < 8; i++) {
+               /* Set one of A0 to A7, and read the byte we get back.
+                  Invert that to get a mask of pressed buttons */
+               keyin[i] = *(uint8_t *) (0xF400 | (1 << i));
+               key = keyin[i] ^ keymap[i];
+               if (key) {
+                       int n;
+                       int m = 1;
+                       for (n = 0; n < 8; n++) {
+                               if ((key & m) && (keymap[i] & m)) {
+                                       if (!(shiftmask[i] & m))
+                                               keysdown--;
+                               }
+                               if ((key & m) && !(keymap[i] & m)) {
+                                       if (!(shiftmask[i] & m))
+                                               keysdown++;
+                                       keybyte = i;
+                                       keybit = n;
+                                       newkey = 1;
+                               }
+                               m += m;
+
+                       }
+               }
+               keymap[i] = keyin[i];
+       }
+}
+
+static uint8_t keyboard[8][8] = {
+       {'@', 'a', 'b', 'c', 'd', 'e', 'f', 'g'},
+       {'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'},
+       {'p', 'q', 'r', 's', 't', 'u', 'v', 'w'},
+       {'x', 'y', 'z', '[', '\\', ']', '^', '_'},
+       {'0', '1', '2', '3', '4', '5', '6', '7'},
+       {'8', '9', ':', ';', ',', '-', '.', '/'},
+       {13, 12, 3, 0 /*up */ , 0 /*down */ , 8 /* left */ , 0 /*right */ ,
+        ' '},
+       {0, 0, 0, 0, 0xF1, 0xF2, 0xF3, 0}
+};
+
+static uint8_t shiftkeyboard[8][10] = {
+       {'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G'},
+       {'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'},
+       {'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W'},
+       {'X', 'Y', 'Z', '{', '|', '}', '^', '_'},
+       {'0', '!', '"', '#', '$', '%', '&', '\''},
+       {'(', ')', '*', '+', '<', '=', '>', '?'},
+       {13, 12, 3, 0 /*up */ , 0 /*down */ , 8 /* left */ , 0 /*right */ ,
+        ' '},
+       {0, 0, 0, 0, 0xF1, 0xF2, 0xF3, 0}
+};
+
+static uint8_t capslock = 0;
+
+static void keydecode(void)
+{
+       uint8_t c;
+
+       if (keybyte == 7 && keybit == 3) {
+               capslock = 1 - capslock;
+               return;
+       }
+
+       if (keymap[7] & 3)      /* shift */
+               c = shiftkeyboard[keybyte][keybit];
+       else
+               c = keyboard[keybyte][keybit];
+
+       /* The keyboard lacks some rather important symbols so remap them
+          with control */
+       if (keymap[7] & 4) {    /* control */
+               if (c > 31 && c < 96)
+                       c &= 31;
+               if (keymap[7] & 3) {
+                       if (c == '(')
+                               c = '{';
+                       if (c == ')')
+                               c = '}';
+                       if (c == '-')
+                               c = '_';
+                       if (c == '/')
+                               c = '``';
+                       if (c == '<')
+                               c = '^';
+               } else {
+                       if (c == '(')
+                               c = '[';
+                       if (c == ')')
+                               c = ']';
+                       if (c == '-')
+                               c = '|';
+               }
+       }
+       if (capslock && c >= 'a' && c <= 'z')
+               c -= 'a' - 'A';
+       if (c)
+               tty_inproc(1, c);
+}
+
+void kbd_interrupt(void)
+{
+       newkey = 0;
+       keyproc();
+       if (keysdown < 3 && newkey)
+               keydecode();
+}
+
+#endif
diff --git a/Kernel/platform-ubee/devtty.h b/Kernel/platform-ubee/devtty.h
new file mode 100644 (file)
index 0000000..300ecd6
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _DEVTTY_H
+#define _DEVTTY_H
+
+extern void tty_interrupt(void);
+extern void kbd_interrupt(void);
+extern int trstty_close(uint8_t minor);
+
+#endif
diff --git a/Kernel/platform-ubee/floppy.s b/Kernel/platform-ubee/floppy.s
new file mode 100644 (file)
index 0000000..9c61c03
--- /dev/null
@@ -0,0 +1,390 @@
+;
+;      Core floppy routines for the TRS80 1791 FDC
+;      Based on the 6809 code
+;
+;      FIXME: better drive spin up wait
+;      FIXME: double sided media
+;      FIXME: correct step rates (per drive ?)
+;      FIXME: precompensation
+;              - not on single density
+;              - track dependant for double density based on trsdos dir pos
+;
+;
+       .globl _fd_reset
+       .globl _fd_operation
+       .globl _fd_motor_on
+       .globl _fd_motor_off
+       .globl fd_nmi_handler
+
+FDCREG .equ    0xF0
+FDCTRK .equ    0xF1
+FDCSEC .equ    0xF2
+FDCDATA        .equ    0xF3
+FDCCTRL        .equ    0xF4
+FDCINT .equ    0xE4
+;
+;      interrupt register reports 0x80 for interrut, 0x40 for drq
+;      (0x20 is the unrelated reset button)
+;
+
+;
+;      Structures we use
+;
+;
+;      Per disk structure to hold device state
+;
+TRKCOPY        .equ    0
+
+;
+;      Command issue
+;
+CMD    .equ    0
+TRACK  .equ    1
+SECTOR .equ    2
+DIRECT .equ    3               ; 0 = read 2 = write 1 = status
+DATA   .equ    4
+
+       .area   _COMMONMEM
+;
+;      Simple routine for pauses
+;
+nap:   dec     bc
+       ld      a, b
+       or      c
+       jr      nz, nap
+       ret
+;
+;      The motor off logic is driven from hardware
+;
+fd_nmi_handler:
+       push    af
+       push    bc
+       ld      a, (fdc_active)
+       or      a
+       jr      z, boring_nmi
+       xor     a
+       out     (FDCINT), a
+       ld      bc, #100
+       call    nap
+       pop     bc
+       pop     af
+       pop     af              ; discard return address
+       jp      fdio_nmiout     ; and jump
+
+;
+;      FIXME: check for motor off here
+;
+boring_nmi:
+       pop     bc
+       pop     af
+       retn
+;
+;      Wait for the drive controller to become ready
+;      Preserve HL, DE
+;
+waitdisk:
+       ld      bc, #0
+waitdisk_l:
+       in      a, (FDCREG)
+       bit     0, a
+       ret     z
+       ;
+       ;       Keep poking fdcctrl to avoid a hardware motor timeout
+       ;
+       ld      a, (fdcctrl)
+       out     (FDCCTRL), a
+       djnz    waitdisk_l
+       dec     c
+       jr      nz, waitdisk_l
+       ld      a, #0xD0        ; reset
+       out     (FDCREG), a
+       ex      (sp),hl
+       ex      (sp),hl
+       ex      (sp),hl
+       ex      (sp),hl
+       in      a, (FDCREG)             ; read to reset int status
+       bit     0, a
+       ret
+;
+;      Set up and perform a disk operation
+;
+;      IX points to the command block
+;      HL points to the buffer
+;      DE points to the track reg copy
+;
+fdsetup:
+       ld      a, (de)
+       out     (FDCTRK), a
+       cp      TRACK(ix)
+;      jr      z, fdiosetup
+
+       ;
+       ;       So we can verify
+       ;
+       ld      a, TRACK(ix)
+       out     (FDCDATA), a
+       ld      a, SECTOR(ix)
+       out     (FDCSEC), a
+       ;
+       ;       Need to seek the disk
+       ;
+       ld      a, #0x18        ; seek
+       out     (FDCREG), a
+       ld      b, #100
+seekwt:        djnz    seekwt
+       call    waitdisk
+       jr      nz, setuptimeout
+       and     #0x18           ; error bits
+       jr      z, fdiosetup
+       ; seek failed, not good
+setuptimeout:                  ; NE = bad
+       ld      a, #0xff        ; we have no idea where we are, force a seek
+       ld      (de), a         ; zap track info
+       ret
+;
+;      Head in the right place
+;
+fdiosetup:
+       ld      a, TRACK(ix)
+       ld      (de), a         ; save track
+;      cmp     #22             ; FIXME
+;      jr      nc, noprecomp
+;      ld      a, (fdcctrl)
+;      or      #0x10           ; Precomp on
+;      jr      precomp1
+;noprecomp:
+       ld      a, (fdcctrl)
+;precomp1:
+       out     (FDCCTRL), a
+       ld      a, SECTOR(ix)
+       out     (FDCSEC), a
+       in      a, (FDCREG)     ; Clear any pending status
+
+       ld      a, CMD(ix)
+
+       ld      de, #0          ; timeout handling
+       
+       out     (FDCREG), a     ; issue the command
+       ld      b, #0
+rwiowt:        djnz    rwiowt
+       ld      a, DIRECT(ix)
+       dec     a
+       ld      a, (fdcctrl)
+       ld      d, a                    ; we need this in a register
+                                       ; to meet timing
+       ld      a, #1
+       ld      (fdc_active), a         ; NMI pop and jump
+       jr      z, fdio_in
+       jr      nc, fdio_out
+;
+;      Status registers
+;
+fdxferdone:
+       ei
+fdxferdone2:
+       xor     a
+       ld      (fdc_active), a
+       in      a, (FDCREG)
+       and     #0x19           ; Error bits + busy
+       bit     0, a            ; Wait for busy to drop, return in a
+       ret     z
+       ld      a, (fdcctrl)
+       out     (FDCCTRL), a
+       jr      fdxferdone2
+;
+;      Read from the disk - HL points to the target buffer
+;
+fdio_in:
+       ld      e, #0x16                ; bits to check
+       ld      bc, #FDCDATA            ; 256 bytes/sector, c is our port
+fdio_inl:
+       in      a, (FDCREG)
+       and     e
+       jr      z, fdio_inl
+       ini
+       di
+       ld      a, d
+fdio_inbyte:
+       out     (FDCCTRL), a            ; stalls
+       ini
+       jr      nz, fdio_inbyte
+       jr      fdxferdone
+
+;
+;      Read from the disk - HL points to the target buffer
+;
+fdio_out:
+       set     6,d                     ; halt mode bit
+       ld      c, #FDCDATA             ; C is our port
+       ld      e, #0x76
+fdio_outl:
+       in      a, (FDCREG)             ; Wait for DRQ (or error)
+       and     e
+       jr      z, fdio_outl
+       outi                            ; Stuff byte into FDC while we think
+       di
+       in      a, (FDCREG)             ; No longer busy ??
+       rra
+       jr      nc, fdxferbad           ; Bugger... 
+       ld      a, #0xC0                ; Turn on magic floppy NMI interface
+       out     (FDCINT), a
+       ld      b, #50                  ; Spin for it
+spin1: djnz    spin1
+       ld      b, (hl)                 ; Next byte
+       inc     hl
+fdio_waitlock:
+       ld      a, d
+       out     (FDCCTRL), a            ; wait states on
+       in      a, (FDCREG)
+       and     e
+       jr      z, fdio_waitlock
+       out     (c), b
+       ld      a, d
+fdio_outbyte:
+       out     (FDCCTRL), a            ; stalls
+       outi
+       jr      fdio_outbyte
+fdio_nmiout:
+;
+;      Now tidy up
+;
+       jr      fdxferdone
+
+fdxferbad:
+       ld      a, #0xff
+       ret
+
+;
+;      C glue interface.
+;
+;      Because of the brain dead memory paging we dump the bits into
+;      kernel space always. The thought of taking an NMI while in the
+;      user memory and bank flipping to recover is just too odious !
+;
+
+;
+;      Reset to track 0, wait for the command then idle
+;
+;      fd_reset(uint8_t *drvptr)
+;
+_fd_reset:
+       pop     de
+       pop     hl
+       push    hl
+       push    de
+       ld      a, (fdcctrl)
+       out     (FDCCTRL), a
+       ld      a, #1
+       out     (FDCSEC), a
+       xor     a
+       out     (FDCTRK), a
+       ld      a, #0x0C
+       out     (FDCREG), a     ; restore
+       ld      a, #0xFF
+       ld      (hl), a         ; Zap track pointer
+       ld      b, #0
+_fdr_wait:
+       djnz    _fdr_wait
+       
+       call    waitdisk
+       cp      #0xff
+       ret     z
+       and     #0x99           ; Error bit from the reset
+       ret     nz
+       ld      (hl), a         ; Track 0 correctly hit (so 0)
+       ret
+;
+;      fd_operation(uint16_t *cmd, uint16_t *drive)
+;
+;      The caller must ensure the drive has been selected and the motor is
+;      running.
+;
+_fd_operation:
+       pop     bc              ; return address
+       pop     hl              ; command
+       pop     de              ; drive track ptr
+       push    de
+       push    hl
+       push    bc
+       push    ix
+       push    hl
+       pop     ix
+       ld      l, DATA(ix)
+       ld      h, DATA+1(ix)
+       call    fdsetup         ; Set up for a command
+       ld      l, a
+       ld      h, #0
+       pop     ix
+       ret
+;
+;      C interface fd_motor_on(uint16_t drivesel)
+;
+;      Selects this drive and turns on the motors. Also pass in the
+;      choice of density
+;
+;      bits 0-3:       select that drive
+;      bit 4:          side (must rewrite each drive change)
+;      bit 5:          precompensation (not set here but in the I/O ops)
+;      bit 6:          synchronize I/O by stalling the CPU (don't set this)
+;      bit 7:          set for double density (MFM)
+;
+;
+_fd_motor_on:
+       pop     de
+       pop     hl
+       push    hl
+       push    de
+       ;
+       ;       Select drive B, turn on motor if needed
+       ;
+       ld      a,(motor_running)       ; nothing selected
+       or      a
+       jr      z, notsel
+
+       cp      l
+       jr      z,  motor_was_on
+;
+;      Select our drive
+;
+notsel:
+       ld      a, l
+       out     (FDCCTRL), a
+       out     (FDCCTRL), a    ; TRS80 erratum apparently needs this
+       ld      (fdcctrl), a
+       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)
+       
+       call    waitdisk
+;
+;      All is actually good
+;
+motor_was_on:
+       ld      hl, #0
+       ret
+
+;
+;      C interface fd_motor_off(void)
+;
+;      Turns off the drive motors, deselects all drives
+;
+_fd_motor_off:
+       ld      a, (motor_running)
+       or      a
+       ret     z
+       ; Should we seek to track 0 ?
+       in      a, (FDCCTRL)
+       and     #0xF0           ; clear drive bits
+       out     (FDCCTRL), a
+       xor     a
+       ld      (motor_running), a
+       ret
+
+curdrive:
+       .db     0xff
+motor_running:
+       .db     0
+fdcctrl:
+       .db     0
+fdc_active:
+       .db     0
diff --git a/Kernel/platform-ubee/kernel.def b/Kernel/platform-ubee/kernel.def
new file mode 100644 (file)
index 0000000..c6bc875
--- /dev/null
@@ -0,0 +1,10 @@
+; UZI mnemonics for memory addresses etc
+
+U_DATA                      .equ 0xE000       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           .equ 0x300        ; 256+256+256 bytes.
+
+U_DATA_STASH               .equ 0x7D00       ; BD00-BFFF
+
+PROG_BASE                  .equ 0x0000
+
+NMOS_Z80                   .equ 1
diff --git a/Kernel/platform-ubee/main.c b/Kernel/platform-ubee/main.c
new file mode 100644 (file)
index 0000000..08dae68
--- /dev/null
@@ -0,0 +1,59 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+uint16_t ramtop = PROGTOP;
+
+/* On idle we spin checking for the terminals. Gives us more responsiveness
+   for the polled ports */
+void platform_idle(void)
+{
+       __asm halt __endasm;
+}
+
+void do_beep(void)
+{
+}
+
+void platform_interrupt(void)
+{
+       timer_interrupt();
+}
+
+void map_init(void)
+{
+}
+
+/* Toggle bit 1, set the no ROM bits */
+#define PAGE_MAP(page) (((page) | 0x04)^0x02)
+
+/* Kernel in 0/1. We don't pull video tricks with 0xF000 yet to save memory
+   but we should eventually */
+
+void pagemap_init(void)
+{
+       /* This is model dependent */
+       pagemap_add(PAGE_MAP(2));
+       pagemap_add(PAGE_MAP(3));
+#if defined(CONFIG_UB256) || defined(CONFIG_UB512)
+       pagemap_add(PAGE_MAP(0) | 0x40);
+       pagemap_add(PAGE_MAP(1) | 0x40);
+       pagemap_add(PAGE_MAP(2) | 0x40);
+       pagemap_add(PAGE_MAP(3) | 0x40);
+#endif
+#if defined(CONFIG_UB256TC) || defined(CONFIG_UB512)
+       pagemap_add(PAGE_MAP(0) | 0x80);
+       pagemap_add(PAGE_MAP(1) | 0x80);
+       pagemap_add(PAGE_MAP(2) | 0x80);
+       pagemap_add(PAGE_MAP(3) | 0x80);
+#endif
+#if defined(CONFIG_UB512)
+       pagemap_add(PAGE_MAP(0) | 0xC0);
+       pagemap_add(PAGE_MAP(1) | 0xC0);
+       pagemap_add(PAGE_MAP(2) | 0xC0);
+       pagemap_add(PAGE_MAP(3) | 0xC0);
+#endif
+/* and if we ever poke at the 1024 stuff its bit 7-5/1-0 */
+}
diff --git a/Kernel/platform-ubee/ubee.s b/Kernel/platform-ubee/ubee.s
new file mode 100644 (file)
index 0000000..4929dd9
--- /dev/null
@@ -0,0 +1,258 @@
+;
+;          TRS 80  hardware support
+;
+
+            .module ubee
+
+            ; exported symbols
+            .globl init_early
+            .globl init_hardware
+            .globl interrupt_handler
+            .globl _program_vectors
+            .globl _system_tick_counter
+           .globl map_kernel
+           .globl map_process
+           .globl map_process_a
+           .globl map_process_always
+           .globl map_save
+           .globl map_restore
+           .globl platform_interrupt_all
+           .globl _kernel_flag
+
+           ; hard disk helpers
+           .globl _hd_xfer_in
+           .globl _hd_xfer_out
+           ; and the page from the C code
+           .globl _hd_page
+
+            ; exported debugging tools
+            .globl _trap_monitor
+            .globl outchar
+
+            ; imported symbols
+            .globl _ramsize
+            .globl _procmem
+            .globl istack_top
+            .globl istack_switched_sp
+            .globl unix_syscall_entry
+            .globl trap_illegal
+            .globl outcharhex
+           .globl fd_nmi_handler
+           .globl null_handler
+
+           .globl s__COMMONMEM
+           .globl l__COMMONMEM
+
+            .include "kernel.def"
+            .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xE800 upwards)
+; -----------------------------------------------------------------------------
+            .area _COMMONMEM
+
+_trap_monitor:
+           di
+           call map_kernel
+           jp to_monitor
+
+platform_interrupt_all:
+           in a,(0xef)
+           ret
+
+_trap_reboot:
+           di
+           call map_kernel
+           jp to_reboot
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below 0xE800, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+            .area _CODE
+
+; These two must be below 32K and not use the stack until they hit ROM space
+;
+to_monitor:
+           xor a                       ; 0 or 1 to keep low 32K right ? */
+           out (0x50), a               ; ROMS please
+           jp 0xE003                   ; Monitor
+
+to_reboot:
+           xor a
+           out (0x50), a
+           jp 0xE000
+       
+;_ctc6845:                             ; registers in reverse order
+;          .db 99, 80, 85, 10, 25, 4, 24, 24, 0, 9, 101, 9, 0, 0, 0, 0
+init_early:
+;
+;            ; load the 6845 parameters
+;          ld hl, #_ctc6845
+;          ld bc, #1588
+;ctcloop:    out (c), b                        ; register
+;          ld a, (hl)
+;          out (0x89), a               ; data
+;          inc hl
+;          djnz ctcloop
+
+           ; clear screen
+           ld hl, #0xF000
+           ld (hl), #'*'               ; debugging aid in top left
+           inc hl
+           ld de, #0xF002
+           ld bc, #1998
+           ld (hl), #' '
+           ldir
+            ret
+
+init_hardware:
+            ; set system RAM size
+            ld hl, #128                        ; FIXME according to platform
+            ld (_ramsize), hl
+            ld hl, #(128-64)           ; 64K for kernel
+            ld (_procmem), hl
+
+            ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused)
+            ld hl, #0
+            push hl
+            call _program_vectors
+            pop hl
+
+            im 1 ; set CPU interrupt mode
+
+            ret
+
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+            .area _COMMONMEM
+
+mapreg:    .db 0
+mapsave:   .db 0
+
+_kernel_flag:
+           .db 1       ; We start in kernel mode
+
+_program_vectors:
+            ; we are called, with interrupts disabled, by both newproc() and crt0
+           ; will exit with interrupts off
+            di ; just to be sure
+            pop de ; temporarily store return address
+            pop hl ; function argument -- base page number
+            push hl ; put stack back as it was
+            push de
+
+           call map_process
+
+            ; write zeroes across all vectors
+            ld hl, #0
+            ld de, #1
+            ld bc, #0x007f ; program first 0x80 bytes only
+            ld (hl), #0x00
+            ldir
+
+            ; now install the interrupt vector at 0x0038
+            ld a, #0xC3 ; JP instruction
+            ld (0x0038), a
+            ld hl, #interrupt_handler
+            ld (0x0039), hl
+
+            ; set restart vector for UZI system calls
+            ld (0x0030), a   ;  (rst 30h is unix function call vector)
+            ld hl, #unix_syscall_entry
+            ld (0x0031), hl
+
+            ld (0x0000), a   
+            ld hl, #null_handler   ;   to Our Trap Handler
+            ld (0x0001), hl
+
+            ld (0x0066), a  ; Set vector for NMI
+            ld hl, #fd_nmi_handler
+            ld (0x0067), hl
+
+;
+;      Mapping set up for the TRS80 4/4P
+;
+;      The top 32K bank holds kernel code and pieces of common memory
+;      The lower 32K is switched between the various user banks. On a
+;      4 or 4P without add in magic thats 0x62 and 0x63 mappings.
+;
+map_kernel:
+           push af
+           ld a, #0x04         ; bank 0, 1 no ROM - FIXME: map video over kernel
+           ld (mapreg), a
+           out (0x50), a
+           pop af
+           ret
+;
+;      Userspace mapping is mode 3, U64K/L32 mapped at L64K/L32
+;
+map_process:
+           ld a, h
+           or l
+           jr z, map_kernel
+map_process_hl:
+           ld a, (hl)
+map_process_a:                 ; used by bankfork
+           ld (mapreg), a
+           out (0x50), a
+            ret
+
+map_process_always:
+           push af
+           push hl
+           ld hl, #U_DATA__U_PAGE
+           call map_process_hl
+           pop hl
+           pop af
+           ret
+
+map_save:   push af
+           ld a, (mapreg)
+           ld (mapsave), a
+           pop af
+           ret
+
+map_restore:
+           push af
+           ld a, (mapsave)
+           ld (mapreg), a
+           out (0x50), a
+           pop af
+           ret
+           
+; No UART (could use printer port ?)
+outchar:
+            ret
+
+;
+;      Swap helpers
+;
+_hd_xfer_in:
+          pop de
+          pop hl
+          push hl
+          push de
+          ld a, (_hd_page)
+          or a
+          call nz, map_process_a
+          ld bc, #0x48                 ; 512 bytes from 0x48
+          inir
+          inir
+          call map_kernel
+          ret
+
+_hd_xfer_out:
+          pop de
+          pop hl
+          push hl
+          push de
+          ld a, (_hd_page)
+          or a
+          call nz, map_process_a
+          ld bc, #0x48                 ; 512 bytes to 0x48
+          otir
+          otir
+          call map_kernel
+          ret
diff --git a/Kernel/platform-ubee/uzi.lnk b/Kernel/platform-ubee/uzi.lnk
new file mode 100644 (file)
index 0000000..b678a97
--- /dev/null
@@ -0,0 +1,40 @@
+-mwxuy
+-i uzi.ihx
+-b _CODE=0x0100
+-b _DISCARD=0xD000
+-b _COMMONMEM=0xE800
+-l z80
+platform-ubee/crt0.rel
+platform-ubee/commonmem.rel
+platform-ubee/ubee.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+usermem.rel
+usermem_std-z80.rel
+platform-ubee/tricks.rel
+platform-ubee/main.rel
+timer.rel
+kdata.rel
+platform-ubee/devfd.rel
+platform-ubee/floppy.rel
+platform-ubee/devhd.rel
+platform-ubee/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_exec.rel
+syscall_fs.rel
+syscall_fs2.rel
+syscall_proc.rel
+syscall_other.rel
+tty.rel
+mm.rel
+swap.rel
+bankfixed.rel
+vt.rel
+devsys.rel
+platform-ubee/devlpr.rel
+platform-ubee/devtty.rel
+-e