genie-eg64: New platform (in test only)
authorAlan Cox <alan@linux.intel.com>
Sun, 12 Aug 2018 23:39:57 +0000 (00:39 +0100)
committerAlan Cox <alan@linux.intel.com>
Sun, 12 Aug 2018 23:39:57 +0000 (00:39 +0100)
The Video Genie EG64 allows you to take a Video Genie (also known as the
Dick Smith System 80, the TRZ80 and a few other names) with either of the
expansion units and the EG64 fitted up to 96K. It's intended for running CP/M
but it's just about big enough to run Fuzix badly providing you have a swap
device on hard disk.

Another goal of this port is to figure out how to move a lot of TRS80 driver
code into dev/trs80 to share between these two ports, a Genie III port maybe,
and also potentially things like the Lobo-Max, Guepard., SysData III and so on.

23 files changed:
Kernel/platform-genie-eg64/Makefile [new file with mode: 0644]
Kernel/platform-genie-eg64/README [new file with mode: 0644]
Kernel/platform-genie-eg64/config.h [new file with mode: 0644]
Kernel/platform-genie-eg64/devfd.c [new file with mode: 0644]
Kernel/platform-genie-eg64/devfd.h [new file with mode: 0644]
Kernel/platform-genie-eg64/devgfx.c [new file with mode: 0644]
Kernel/platform-genie-eg64/devgfx.h [new file with mode: 0644]
Kernel/platform-genie-eg64/devhd.c [new file with mode: 0644]
Kernel/platform-genie-eg64/devhd.h [new file with mode: 0644]
Kernel/platform-genie-eg64/devhd_discard.c [new file with mode: 0644]
Kernel/platform-genie-eg64/devices.c [new file with mode: 0644]
Kernel/platform-genie-eg64/devinput.c [new file with mode: 0644]
Kernel/platform-genie-eg64/devinput.h [new file with mode: 0644]
Kernel/platform-genie-eg64/devlpr.c [new file with mode: 0644]
Kernel/platform-genie-eg64/devlpr.h [new file with mode: 0644]
Kernel/platform-genie-eg64/devtty.c [new file with mode: 0644]
Kernel/platform-genie-eg64/devtty.h [new file with mode: 0644]
Kernel/platform-genie-eg64/discard.c [new file with mode: 0644]
Kernel/platform-genie-eg64/fuzix.lnk [new file with mode: 0644]
Kernel/platform-genie-eg64/kernel.def [new file with mode: 0644]
Kernel/platform-genie-eg64/main.c [new file with mode: 0644]
Kernel/platform-genie-eg64/platform_ide.h [new file with mode: 0644]
Kernel/platform-genie-eg64/trs80.h [new file with mode: 0644]

diff --git a/Kernel/platform-genie-eg64/Makefile b/Kernel/platform-genie-eg64/Makefile
new file mode 100644 (file)
index 0000000..877e86f
--- /dev/null
@@ -0,0 +1,60 @@
+
+CSRCS =
+DISCARD_CSRCS = discard.c devhd_discard.c
+NSRCS = ../dev/net/net_native.c
+
+ASRCS = trs80.s trs80-bank.s crt0.s
+ASRCS += tricks.s commonmem.s floppy.s ide.s
+
+CSRCS = devfd.c devhd.c
+CSRCS += devices.c main.c devinput.c
+CSRCS += devlpr.c devtty.c devgfx.c
+DSRCS = ../dev/blkdev.c ../dev/devide.c ../dev/mbr.c
+DISCARD_DSRCS = ../dev/devide_discard.c
+
+COBJS = $(CSRCS:.c=.rel)
+DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS))
+AOBJS = $(ASRCS:.s=.rel)
+NOBJS = $(patsubst ../dev/net/%.c,%.rel, $(NSRCS))
+DISCARD_COBJS = $(DISCARD_CSRCS:.c=.rel)
+DISCARD_DOBJS = $(patsubst ../dev/%.c,%.rel, $(DISCARD_DSRCS))
+OBJS  = $(COBJS) $(AOBJS) $(DISCARD_COBJS) $(DOBJS) $(DISCARD_DOBJS) $(NOBJS)
+
+CROSS_CCOPTS += -I../dev/
+
+all:   $(OBJS) trs80load.bin
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG1) -c $<
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) $<
+
+$(DISCARD_COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(DOBJS): %.rel: ../dev/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG2) -c $<
+
+$(DISCARD_DOBJS): %.rel: ../dev/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(NOBJS): %.rel: ../dev/net/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG2) -c $<
+
+clean:
+       rm -f *.rel *.lst *.asm *.lst *.sym *.adb *.rst *.ihx core *~ boot.raw
+
+image: trs80load.bin
+       dd if=/dev/zero of=boot.raw bs=256 count=400
+       # Boot block at 0,0
+       dd if=trs80load.bin of=boot.raw bs=256 count=1 conv=notrunc
+       # With the image straight afterwards
+       dd if=../fuzix.bin of=boot.raw bs=256 skip=1 conv=notrunc
+       ../tools/makejv3 -s -t sd40s -d boot.raw boot.jv3
+
+trs80load.bin: trs80load.s
+       sdasz80 -o trs80load.s
+       sdldz80 -i trs80load.rel
+       makebin -s 17152 trs80load.ihx trs80load.tmp
+       dd if=trs80load.tmp of=trs80load.bin bs=256 skip=66 count=1
diff --git a/Kernel/platform-genie-eg64/README b/Kernel/platform-genie-eg64/README
new file mode 100644 (file)
index 0000000..142a3bc
--- /dev/null
@@ -0,0 +1,104 @@
+Video Genie With EG 64 banking option, or the TRS80 'Lubomir Soft Banker'
+clone of the EG 64
+
+This port supports the following configurations currently
+
+       Video Genie & Video Genie I/II  / Dick Smith System 80 MkI & MkII /
+       PMC-80/81 / TRZ-80 with EG3014/X-4010/X-4020 and EG64
+
+       Options:
+               Floppy Disk (somewhat basic support, no format tool yet)
+               Lower case mod or built in lower case
+               EG3016 printer interface
+               EG3020 RS232 interface
+               EG3022 S100 adapter (but no specific card drivers)
+               Percom compatible double density kit
+               HRG1B Graphics Card
+               Lowe Electronics LE18 graphics adapter
+               Tandy style RTC at 0xB0 (only usable for time locking)
+               Anything on the model I list that works with a Genie/System-80
+               to TRS80 expansion convertor (*)
+               IDE CF at 0x40
+
+       Planned:
+               Lowe Electronics FRED
+               Tandy compatible double density kit
+
+       Unsupported:
+               TRS80 mapped serial/printer port on Video Genie (BUG)
+               Genie IIs/III: These are CP/M capable systems with a different
+               memory model.
+               Any non memory S100 cards that don't match the TRS80/VG
+               devices (ie the X-4010 S100 printer card should work)
+
+       TRS80 model I with the Lubomir Soft Banker clone of the EG64
+
+       Options:
+               Floppy Disk (somewhat basic support, no format tool yet)
+               RS-232-C Interface(26-1145, or compatible)
+               Hard Disk (Tandy compatible 26-1132)
+               Lower Case Kit (either Tandy 26-1104 or the simple mods)
+               Percom Compatible Doubler
+               Holmes style speed up board (anything using port 254 bit 0)
+               Real Time Clock (supported for time locking, can't do dates as
+                                is not Y2K capable, must be at 0xB0)
+               HRG1B Graphics Card
+               Alpha Products Joystick
+               ChromaTRS (as joystick and a graphics device only - need a VDP
+                       emulation in xtrs to do console support)
+               Lo-tech or similar IDE CF at 0x40
+               Tandy HRG (user defined graphics 26-9800) [boot opt micro]
+               Orcim PCG80 [boot opt pcg80]
+               Progamma  Intl. 80 Grafix [boot opt 80gfx]
+
+       Planned:
+               Orchestra 80 sound card
+               Tandy Model I Double Density Kit (26-1143)
+               Support for the FreHD extra features (clock, volume switches)
+
+       Unsupported:
+               M1SE/M1RE/FreHD (except as far as compatibility features go)
+
+Generally Not Supported:
+       Alpha Supermem and other big bankers (use the trs80m1 port)
+       Various 64K only CP/M adapters
+       (Unless someone knows one that stacks with the supermem!)
+
+Would Be Nice To Do Better
+       80-Grafix               -       need docs, example apps to debug
+                                       an emulator
+       TRS80 Model 1 Hires     -       The UK 'hires' actually a font
+                                       adapter also needs emulation support
+
+User Space:
+       The TRS80 Model I/III have ROM in the low 16K. The EG 64 allows this
+       space to be mapped out and the upper 32K to be bank switched. Because
+       the switching is in the upper 32K binaries must be linked at 0x8000
+       as with the TRS80 model 1 port. This limit should go away when binaries
+       become relocatable
+
+To Do:
+       Faster user copiers once it works
+       Fast block copy routines for uget/uput
+       Hint based pre-fetching uget
+       When we have > 512K or so RAM use the rest as a ramdisc
+       Orchestra
+       M3SE video at least
+
+Memory Map:
+       0000-3BFF       Kernel data and boot area
+       37C0-3FFF       I/O and ROM
+       4000-7FFF       Kernel code
+       8000-FFFF       Kernel code and some data/bss areas
+
+       8000-FFFF       User space
+
+       Note that the current build is an over featured one. Turning off
+       the  IDE support will shrink it loads/
+
+       Unfortunately right now some core changes are needed to get to the
+       point we can have configurable options done properly.
+
+Floppy boot requires a single density disk. The Level II ROM reads
+disk 0 side 0 track 0 sector 0 (TRS80 disks are 0 offset sector count)
+into 4200-42FF and then does a JP 4200 (stack is around 407D)
diff --git a/Kernel/platform-genie-eg64/config.h b/Kernel/platform-genie-eg64/config.h
new file mode 100644 (file)
index 0000000..5e545eb
--- /dev/null
@@ -0,0 +1,79 @@
+/* Set if you want RTC support and have an RTC on ports 0xB0-0xBC */
+#define CONFIG_RTC
+#define CONFIG_RTC_FULL
+/* 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) */
+#undef 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
+/* Memory set up */
+#define CONFIG_SWAP_ONLY
+#define CONFIG_SPLIT_UDATA
+#define UDATA_BLKS 1
+#define UDATA_SIZE 0x200
+/* Direct I/O support */
+#define CONFIG_LARGE_IO_DIRECT
+/* Raw input layer */
+#define CONFIG_INPUT
+/* Full keycode level grabbing supported */
+#define CONFIG_INPUT_GRABMAX   3
+/* And our buffer pool is dynamically sized */
+#define CONFIG_DYNAMIC_BUFPOOL
+/* And IDE */
+#define MAX_BLKDEV     2
+#define CONFIG_IDE
+
+#define MAP_SIZE       0x8000
+
+#define CONFIG_BANKS   1       /* 32K */
+
+/* Vt definitions */
+#define CONFIG_VT_SIMPLE
+#define VT_BASE                ((uint8_t *)0x3C00)
+#define VT_MAP_CHAR(x) vt_map_char(x)
+#define VT_WIDTH       64
+#define VT_HEIGHT      16
+#define VT_RIGHT       63
+#define VT_BOTTOM      15
+
+extern unsigned char vt_map_char(unsigned char);
+
+/* Keyboard bitmap definitions */
+#define KEY_ROWS       8
+#define KEY_COLS       8
+
+#define TICKSPERSEC 40     /* Ticks per second */
+#define PROGBASE    0x8000  /* Base of user  */
+#define PROGLOAD    0x8000  /* Load and run here */
+#define PROGTOP     0xFFFF  /* Top of program */
+#define PROC_SIZE   32             /* Memory needed per process */
+
+#define SWAP_SIZE   0x41       /* 32.5K in blocks */
+#define SWAPBASE    0x8000     /* We swap the lot in one, include the */
+#define SWAPTOP            0x10000UL   /* vectors so its a round number of sectors */
+
+#define MAX_SWAPS      16      /* Should be plenty (512K!) */
+
+#define swap_map(x)    ((uint8_t *)(x))
+
+#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 3
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define SWAPDEV  (swap_dev)  /* Device for swapping (dynamic). */
+#define NBUFS    4         /* Number of block buffers - keep in sync with asm! */
+#define NMOUNTS         4         /* Number of mounts at a time */
+
+extern void platform_discard(void);
diff --git a/Kernel/platform-genie-eg64/devfd.c b/Kernel/platform-genie-eg64/devfd.c
new file mode 100644 (file)
index 0000000..7a15485
--- /dev/null
@@ -0,0 +1,102 @@
+#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;
+
+/* 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];
+
+/*
+ *     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)
+{
+    int ct = 0;
+    int tries;
+    uint8_t err = 0;
+    uint8_t *driveptr = fd_tab + minor;
+
+    if(rawflag == 2)
+        goto bad2;
+
+    /* FIXME: We force DD for now */
+    err = fd_motor_on(selmap[minor]|0x80);
+    if (err)
+        goto bad;
+
+    if (*driveptr == 0xFF)
+        fd_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;
+
+    while (ct < udata.u_nblock) {
+        for (tries = 0; tries < 4 ; tries++) {
+            err = fd_operation(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;
+        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 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 fd_transfer(minor, false, rawflag);
+}
diff --git a/Kernel/platform-genie-eg64/devfd.h b/Kernel/platform-genie-eg64/devfd.h
new file mode 100644 (file)
index 0000000..672cf90
--- /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 *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-genie-eg64/devgfx.c b/Kernel/platform-genie-eg64/devgfx.c
new file mode 100644 (file)
index 0000000..96bd634
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ *     Graphics logic for the TRS80 model I, III and friends
+ *
+ *     - Need to figure out how to interact with console switches
+ *     - Need to add LNW80 graphics modes
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <tty.h>
+#include <vt.h>
+#include <graphics.h>
+#include <devgfx.h>
+#include "trs80.h"
+
+__sfr __at 0x00 hrg_off;
+__sfr __at 0x04 hrg_data;
+__sfr __at 0x79 vdps;
+__sfr __at 0x7C chromajs0;
+__sfr __at 0x82 gfx_data;
+__sfr __at 0x83 gfx_ctrl;
+__sfr __at 0xEC le18_data;
+__sfr __at 0xEF le18_ctrl;
+__sfr __at 0xFF ioctrl;
+
+uint8_t trs80_udg;
+
+uint8_t has_hrg1;
+uint8_t has_chroma;    /* and thus 2 joystick ports */
+uint8_t video_mode;
+static uint8_t max_mode = 0;
+
+static struct display trsdisplay[6] = {
+  /* Text mode */
+  {
+    0,
+    128, 48,
+    64, 16,
+    255, 255,
+    FMT_6PIXEL_128,
+    HW_UNACCEL,
+    GFX_MAPPABLE|GFX_MULTIMODE|GFX_TEXT,
+    1,
+    0
+  },
+  /* Tandy Graphics */
+  {
+    1,
+    640, 240,
+    640, 240,
+    255, 255,
+    FMT_MONO_WB,
+    HW_TRS80GFX,
+    GFX_MULTIMODE|GFX_MAPPABLE,        /* No overlay control on Model 3 */
+    32,
+    0                  /* For now lets just worry about map */
+  },
+  /* Microlabs Grafyx */
+  {
+    1,
+    512, 192,
+    512, 192,
+    255, 255,
+    FMT_MONO_WB,
+    HW_MICROLABS,
+    GFX_MULTIMODE|GFX_MAPPABLE,
+    12,
+    0
+  },
+  /* HRG1B */
+  {
+    1,
+    384, 192,
+    384, 192,
+    255, 255,
+    FMT_MONO_WB,
+    HW_HRG1B,
+    GFX_MULTIMODE|GFX_MAPPABLE|GFX_TEXT,
+    9,
+    0
+  },
+  /* CHROMAtrs */
+  {
+    1,
+    256, 192,
+    256, 192,
+    255, 255,
+    FMT_VDP,
+    HW_VDP_9918A,
+    GFX_MULTIMODE|GFX_MAPPABLE,        /* We don't support it as a console yet */
+    16,
+    0
+  },
+  /* Lowe Electronics LE-18 */
+  {
+    1,
+    384, 192,
+    384, 192,
+    255, 255,
+    FMT_MONO_WB,
+    HW_LOWE_LE18,
+    GFX_MULTIMODE|GFX_MAPPABLE|GFX_TEXT,
+    16,
+    0
+  }
+};
+
+static struct videomap trsmap[6] = {
+  {
+    0,
+    0,
+    0x3C00,
+    0x0400,    /* Directly mapped */
+    0, 0,      /* No segmentation */
+    1,         /* Standard spacing */
+    MAP_FBMEM_SIMPLE|MAP_FBMEM
+  },
+  /* Tandy board */
+  {
+    0,
+    0x80,      /* I/O ports.. 80-83 + 8C-8E */
+    0, 0,              /* Not mapped into main memory */
+    0, 0,      /* No segmentation */
+    1,         /* Standard spacing */
+    MAP_PIO
+  },
+  /* Microlabs */
+  {
+    0,
+    0xFF,
+    0x3C00, 0x0400,
+    0, 0,
+    1,
+    MAP_FBMEM|MAP_PIO
+  },
+  /* HRG1B */
+  {
+    0,
+    0x00,      /* I/O ports.. 0-5 */
+    0, 0,      /* Not mapped into main memory */
+    0, 0,      /* No segmentation */
+    1,         /* Standard spacing */
+    MAP_PIO
+  },
+  /* CHROMAtrs */
+  {
+    0,
+    0x78,      /* I/O ports 0x78/79 */
+    0, 0,
+    0, 0,
+    1,
+    MAP_PIO    /* VDP is I/O mapped */
+  },
+  /* Lowe Electronics LE-18 */
+  {
+    0,
+    0xEC,      /* I/O ports 0xEC-0xEF */
+    0, 0,
+    0, 0,
+    1,
+    MAP_PIO    /* VDP is I/O mapped */
+  }
+};
+
+static uint8_t displaymap[4] = {0, 0, 0, 0};
+
+static int8_t udg_ioctl(uarg_t arg, char *ptr);
+
+/* TODO: Arbitrate graphics between tty 1 and tty 2 */
+int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr)
+{
+  uint8_t m;
+
+  if (minor <= 2 && (arg == VTFONTINFO || arg == VTSETFONT || arg == VTSETUDG))
+    return udg_ioctl(arg, ptr);
+
+  if (minor > 2 || (arg >> 8 != 0x03))
+    return vt_ioctl(minor, arg, ptr);
+
+  switch(arg) {
+  case GFXIOC_GETINFO:
+    return uput(&trsdisplay[video_mode], ptr, sizeof(struct display));
+  case GFXIOC_GETMODE:
+  case GFXIOC_SETMODE:
+    m = ugetc(ptr);
+    if (m > max_mode)
+      break;
+    m = displaymap[m];
+    if (arg == GFXIOC_GETMODE)
+      return uput(&trsdisplay[m], ptr, sizeof(struct display));
+    video_mode = m;
+    /* Going back to text mode we need to turn off graphics cards. Going the
+       other way we let the applications handle it as they may want to do
+       memory wipes and the like first */
+    if (video_mode == 0) {
+      if (displaymap[1] == 1)
+        gfx_ctrl = 0;
+      else if (displaymap[1] == 2)
+        ioctrl = 0x20;
+      else if (displaymap[1] == 3)
+        hrg_off = 1;
+      else if (displaymap[1] == 5)
+        le18_ctrl = 0;
+    }
+    return 0;
+  case GFXIOC_UNMAP:
+    return 0;
+  /* Users can "map" 8) the framebuffer into their process and use the
+     card directly */
+  case GFXIOC_MAP:
+    return uput(&trsmap[video_mode], ptr, sizeof(struct videomap));
+  }
+  return -1;
+}
+
+void gfx_init(void)
+{
+  if (trs80_model == TRS80_MODEL1 || trs80_model == VIDEOGENIE) {
+    /* HRG1B support. Might be good to also support 80-Grafix as a UDG
+       module */
+    if (hrg_data != 0xFF) {    /* We ought to test more carefully */
+      max_mode = 1;
+      displaymap[1] = 3;
+      has_hrg1 = 1;
+    }
+    /* LE-18 */
+    if(trs80_model == VIDEOGENIE && le18_data != 0xFF) {
+      displaymap[++max_mode] = 5;
+      trsdisplay[5].mode = max_mode;
+    }
+  } else if (trs80_model == TRS80_MODEL3) {
+    /* The model 3 might have an 80-Grafix UDG card, or a Graphyx
+       or a Tandy card */
+    uint8_t *fb = (uint8_t *)0x3C00;
+    uint8_t c = *fb;
+    *fb = 128;
+    ioctrl = 0xB2;
+    if (*fb != 128) {
+      /* Hopeful */
+      *fb = 128;
+      if (*fb == 128) { /* 80 Grafix only has 6bit wide RAM but wants
+                           the top bit set on writes.. */
+        displaymap[1] = 2;
+        max_mode = 1;
+      } /* else add UDG support FIXME */
+    }
+    ioctrl = 0x20;
+    *fb = c;
+    if (max_mode == 0 && gfx_data != 0xFF) {
+      max_mode = 1;
+      displaymap[1] = 1;
+    }
+  }
+  /* It's possible to have a CHROMAtrs and other adapters as it fits
+     on the external bus. 70-7C is also a common location for RTC clocks
+     which makes detection trickier. The clock will show 0 in the upper
+     bits, the joystick port will not */
+  if (vdps != 0xFF && (chromajs0 & 0xC0) == 0xC0) {
+    displaymap[++max_mode] = 4;
+    trsdisplay[4].mode = max_mode;
+    has_chroma = 1;
+  }
+}
+
+/*
+ *     UDG drivers
+ *
+ *     We don't currently address UDG fitted without lower case. That gets
+ *     deeply weird because you get disjoint ranges with one bit magically
+ *     invented by logic. For the UDG only ones we just halve the range, but
+ *     for the PCG80 what about full font ?
+ *
+ *     (The Tandy (Microfirma) one requires lowercase is fitted according
+ *     to the manual)
+ *
+ *     One other corner case to consider is that if you have no lower case
+ *     we ought to requisition the UDG and load a font into it then use
+ *     128-159 for lower case.
+ */
+
+static struct fontinfo fonti[4] = {
+  { 0, },
+  { 0, 255, 0, 255, FONT_INFO_6X12P16 },
+  { 128, 191, 128, 191, FONT_INFO_6X12P16 },
+  { 128, 255, 128, 255, FONT_INFO_6X12P16 }
+};
+
+__sfr __at 130 trshg_nowrite;
+__sfr __at 140 trshg_write;
+__sfr __at 150 trshg_gfxoff;
+__sfr __at 155 trshg_gfxon;
+__sfr __at 0xFE pcg80;
+__sfr __at 0xFF p80gfx;
+
+static uint8_t old_pcg80;
+static uint8_t old_p80gfx;
+static uint8_t udgflag;                /* So we know what fonts are loaded */
+#define SOFTFONT_UDG   1
+#define SOFTFONT_ALL   2
+
+static void load_char_pcg80(uint8_t ch, uint8_t *cdata)
+{
+  uint8_t bank = ch >> 6;
+  uint8_t *addr = (uint8_t *)0x3C00 + ((ch & 0x3F) << 4);
+  uint8_t i;
+  
+  pcg80 = old_pcg80 | 0x60 | bank;     /* Programming mode on */
+  
+  for (i = 0; i < 16; i++)
+    *addr++ = *cdata++ << 1 | 0x80;
+  pcg80 = old_pcg80;
+}
+
+static void load_char_80gfx(uint8_t ch, uint8_t *cdata)
+{
+  uint8_t *addr = (uint8_t *)0x3C00 + ((ch & 0x3F) << 4);
+  uint8_t i;
+
+  p80gfx = old_p80gfx | 0x60;
+  for (i = 0; i < 16; i++)
+    *addr++ = *cdata++ << 1 | 0x80;
+  p80gfx = old_p80gfx;
+}
+
+static void load_char_trs(uint8_t ch, uint8_t *cdata)
+{
+  uint8_t *addr = (uint8_t *)0x3C00 + ((ch & 0x3F) << 4);
+  uint8_t i;
+
+  trshg_write = 1;
+  for (i = 0; i < 16; i++)
+    *addr++ = *cdata++ << 1 | 0x80;
+  trshg_nowrite = 1;
+}
+
+void (*load_char[4])(uint8_t, uint8_t *) = {
+  NULL,
+  load_char_pcg80,
+  load_char_80gfx,
+  load_char_trs,
+};
+
+static void udg_config(void)
+{
+  switch(trs80_udg) {
+  case UDG_PCG80:
+    if (udgflag & SOFTFONT_UDG)
+      old_pcg80 |= 0x80;       /* 128-255 soft font */
+    if (udgflag & SOFTFONT_ALL)
+      old_pcg80 |= 0x88;
+    pcg80 = old_pcg80 | 0x20;
+    break;
+  case UDG_80GFX:
+    if (udgflag & SOFTFONT_UDG)
+      old_p80gfx |= 0x80;
+    p80gfx = old_p80gfx | 0x20;
+    break;
+  case UDG_MICROFIRMA:
+    if (udgflag & SOFTFONT_UDG)
+      trshg_gfxon = 1;
+    break;
+  }
+}
+
+static int8_t udg_ioctl(uarg_t arg, char *ptr)
+{
+  uint8_t base = fonti[trs80_udg].udg_low;
+  uint8_t limit = fonti[trs80_udg].udg_high;
+  int i;
+
+  /* Not supported */
+  if (trs80_udg == UDG_NONE) {
+    udata.u_error = EOPNOTSUPP;
+    return -1;
+  }
+  /* No lower case available */
+  if (!video_lower)
+    limit = 191;
+
+  switch(arg) {
+  case VTFONTINFO:
+    return uput(fonti + trs80_udg, ptr, sizeof(struct fontinfo));
+  case VTSETFONT:
+    base = fonti[trs80_udg].font_low;
+    limit = fonti[trs80_udg].font_high;
+    /* Fall through */
+  case VTSETUDG:
+    for (i = base; i <= limit; i++) {
+      uint8_t c[16];
+      if (uget(c, ptr, 16) == -1)
+        return -1;
+      ptr += 16;
+      load_char[trs80_udg](i, c);
+    }
+    if (arg == VTSETUDG)
+      udgflag |= SOFTFONT_UDG;
+    else
+      udgflag |= SOFTFONT_ALL;
+    udg_config();
+    return 0;
+  }
+  return -1;
+}
diff --git a/Kernel/platform-genie-eg64/devgfx.h b/Kernel/platform-genie-eg64/devgfx.h
new file mode 100644 (file)
index 0000000..185c3c5
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _DEV_GFX_H
+#define _DEV_GFX_H
+
+#include <graphics.h>
+
+extern int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr);
+extern void gfx_init(void);
+
+extern uint8_t video_mode;
+extern uint8_t has_hrg1;
+extern uint8_t has_chroma;
+
+#endif
diff --git a/Kernel/platform-genie-eg64/devhd.c b/Kernel/platform-genie-eg64/devhd.c
new file mode 100644 (file)
index 0000000..702fb8c
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *     WD1010 hard disk driver
+ */
+
+#define _HD_PRIVATE
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devhd.h>
+#include <diskgeom.h>
+
+/* Used by the asm helpers */
+uint8_t hd_page;
+
+/* Swap is scanned for so not constant */
+uint16_t swap_dev;
+
+/* Seek and restore low 4 bits are the step rate, read/write support
+   multi-sector mode but not all emulators do .. */
+
+struct minipart parts[MAX_HD];
+
+/* Wait for the drive to show ready */
+uint8_t hd_waitready(void)
+{
+       uint8_t st;
+       do {
+               st = hd_status;
+       } while (!(st & 0x40));
+       return st;
+}
+
+/* Wait for DRQ or an error */
+uint8_t hd_waitdrq(void)
+{
+       uint8_t st;
+       do {
+               st = hd_status;
+       } while (!(st & 0x09));
+       return st;
+}
+
+uint8_t hd_xfer(bool is_read)
+{
+       /* Error ? */
+       if (hd_status & 0x01)
+               return hd_status;
+       if (is_read)
+               hd_xfer_in(udata.u_dptr);
+       else
+               hd_xfer_out(udata.u_dptr);
+       /* Should be returning READY, and maybe SEEKDONE */
+       return hd_status;
+}
+
+int hd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+       uint16_t ct = 0;
+       staticfast uint8_t tries;
+       uint8_t err = 0;
+       uint8_t cmd = HDCMD_READ;
+       uint8_t head;
+       uint8_t sector;
+       staticfast uint16_t cyl;
+       uint8_t dev = minor >> 4;
+       staticfast struct minipart *p;
+
+       p = &parts[dev];
+
+       /* FIXME: We only support 512 byte access chunks even for raw I/O */
+       hd_page = 0;
+       if (rawflag == 1) {
+               if (d_blkoff(BLKSHIFT))
+                       return -1;
+               hd_page = udata.u_page;         /* User space */
+       } else if (rawflag == 2)
+               hd_page = swappage;
+
+       udata.u_nblock *= 2;
+
+       if (!is_read)
+               cmd = HDCMD_WRITE;
+
+       /* TRS80 hard disk are 32 sectors/track, 256 byte sectors */
+
+       hd_precomp = p->g.precomp;
+       hd_seccnt = 1;
+
+       sector = udata.u_block;
+       sector = (sector << 1) & 0x1E;
+
+       cyl = udata.u_block >> 4;
+
+       /* Do the maths once and on 16 bit numbers */
+       head = cyl % p->g.head;
+       cyl /= p->g.head;
+       if (minor)
+               cyl += p->cyl[(minor-1)&0x0F];
+
+       while (ct < udata.u_nblock) {
+               /* Head next bits, plus drive */
+               hd_sdh = 0x80 | head | (dev << 3);
+               hd_secnum = sector;
+               /* cylinder bits */
+               hd_cyllo = cyl & 0xFF;
+               hd_cylhi = cyl >> 8;
+
+               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);
+                               /* Ready, no error ? */
+                               if ((err & 0x41) == 0x40)
+                                       break;
+                       } else
+                               kprintf("hd%d: err %x\n", minor, err);
+
+                       if (tries > 1) {
+                               hd_cmd = HDCMD_RESTORE | p->g.seek;
+                               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++;
+               udata.u_dptr += 256;
+               sector++;
+               /* Cheaper than division! */
+               if (sector == 32) {
+                       sector = 0;
+                       head++;
+                       if (head == p->g.head) {
+                               head = 0;
+                               cyl++;
+                       }
+               }
+       }
+       return ct << 8;
+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)
+{
+       uint8_t dev = minor >> 4;
+       flag;
+       if (dev > MAX_HD || parts[dev].g.head == 0 ||
+               (minor && parts[dev].cyl[(minor-1)&0x0F] == 0xFFFF)) {
+               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-genie-eg64/devhd.h b/Kernel/platform-genie-eg64/devhd.h
new file mode 100644 (file)
index 0000000..2f06e0b
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef __DEVHD_DOT_H__
+#define __DEVHD_DOT_H__
+
+/* public interface */
+extern int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+extern int hd_open(uint8_t minor, uint16_t flag);
+
+extern void hd_probe(void);
+
+#ifdef _HD_PRIVATE
+
+__sfr __at 0xC0 hd_wpbits;     /* Write protect and IRQ (not used) */
+__sfr __at 0xC1 hd_ctrl;       /* Reset and enable bits */
+__sfr __at 0xC8 hd_data;
+__sfr __at 0xC9 hd_precomp;    /* W/O */
+__sfr __at 0xC9 hd_err;                /* R/O */
+__sfr __at 0xCA hd_seccnt;
+__sfr __at 0xCB hd_secnum;
+__sfr __at 0xCC hd_cyllo;
+__sfr __at 0xCD hd_cylhi;
+__sfr __at 0xCE hd_sdh;
+__sfr __at 0xCF hd_status;     /* R/O */
+__sfr __at 0xCF hd_cmd;
+
+#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 RATE_4MS       0x08    /* 4ms step rate for hd (conservative) */
+
+#define HDCTRL_SOFTRESET       0x10
+#define HDCTRL_ENABLE          0x08
+#define HDCTRL_WAITENABLE      0x04
+
+#define HDSDH_ECC256           0x80
+
+/* 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
+
+extern struct minipart parts[MAX_HD];
+
+extern uint8_t hd_waitready(void);
+extern uint8_t hd_waitdrq(void);
+extern uint8_t hd_xfer(bool is_read);
+
+/* helpers in common memory for the block transfers */
+extern int hd_xfer_in(uint8_t *addr);
+extern int hd_xfer_out(uint8_t *addr);
+
+#endif
+#endif /* __DEVHD_DOT_H__ */
diff --git a/Kernel/platform-genie-eg64/devhd_discard.c b/Kernel/platform-genie-eg64/devhd_discard.c
new file mode 100644 (file)
index 0000000..313b968
--- /dev/null
@@ -0,0 +1,96 @@
+#define _HD_PRIVATE
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devhd.h>
+#include <diskgeom.h>
+
+/*
+ *     Mini part processing. This and mbr and other things all one day
+ *     need to become a bit more unified.
+ */
+static void hd_swapon(struct minipart *p, unsigned int d, unsigned int i)
+{
+       uint16_t cyls;
+       if (i == 14 || p->cyl[i+1] == 0xFFFF)
+               cyls = p->g.cyl;
+       else
+               cyls = p->cyl[i+1];
+       cyls -= p->cyl[i];
+       cyls *= p->g.head;
+       /* This is now the number of sets of 32 sectors (16K) in swap.
+          We need 32K per process: hardwire it here - FIX if you change
+          the mapping model */
+
+       swap_dev = (d << 4) + i + 1;
+
+       if (cyls >= MAX_SWAPS)
+               cyls = MAX_SWAPS - 1;
+       for (i = 0; i < cyls; i++) {
+               swapmap_init(i);
+       }
+       kputs("swap-");
+}
+
+void hd_probe(void)
+{
+       unsigned int dev = 0;
+       unsigned int i;
+       /* Second half of second block */
+       struct minipart *p;
+
+       udata.u_dptr = tmpbuf();
+       p = (struct minipart *)(udata.u_dptr + 128);
+
+       for (dev = 0; dev < 4; dev++) {
+               hd_sdh = 0x80 | (dev << 3);
+               hd_cmd = HDCMD_RESTORE | RATE_4MS;
+               if (hd_waitready() & 1) {
+                       if ((hd_err & 0x12) == 0x12)
+                               continue;
+               }
+               hd_seccnt = 1;
+               hd_sdh = 0x80 | (dev << 3);
+               hd_secnum = 1;
+               hd_cyllo = 0;
+               hd_cylhi = 0;
+               hd_cmd = HDCMD_READ;
+               if (hd_waitdrq() & 1)
+                       continue;
+               if((hd_xfer(1) & 0x41) != 0x40)
+                       continue;
+               kprintf("hd%c: ", dev + 'a');
+               if (p->g.magic != MP_SIG_0) {
+                       p->g.cyl = 1;
+                       p->g.head = 1;
+                       p->g.sec = 32;
+                       p->g.precomp = 0;
+                       p->g.seek = 10;
+                       p->g.secsize = 8;
+                       for (i = 0; i < 15; i++)
+                               p->cyl[i] = 0xFFFFU;
+                       kputs("(unlabelled)\n");
+               } else {
+                       for (i = 0; i < 15; i++) {
+                               if (p->cyl[i] != 0xFFFFU) {
+                                       if (p->type[i] == 0x56) {
+                                               /* Configure swap */
+                                               hd_swapon(p, dev, i);
+                                       }
+                                       kprintf("hd%c%d ", dev + 'a', i + 1);
+                               }
+                       }
+                       kputs("\n");
+               }
+               if (p->g.seek) {
+                       p->g.seek /= 2;
+                       if (p->g.seek == 0)
+                               p->g.seek = 1;
+               }
+               /* Set the step rate */
+               hd_cmd = HDCMD_SEEK | p->g.seek;
+               hd_waitready();
+               memcpy(&parts[dev], p, sizeof(parts[dev]));
+       }
+       tmpfree(udata.u_dptr);
+}
diff --git a/Kernel/platform-genie-eg64/devices.c b/Kernel/platform-genie-eg64/devices.c
new file mode 100644 (file)
index 0000000..8fa27aa
--- /dev/null
@@ -0,0 +1,47 @@
+#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 <vt.h>
+#include <devtty.h>
+#include <devgfx.h>
+#include <blkdev.h>
+#include <trs80.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+  /* 0: /dev/hd                Hard disc block devices */
+  {  hd_open,     no_close,     hd_read,   hd_write,   no_ioctl  },
+  /* 1: /dev/fd                Floppy disc block devices */
+  {  fd_open,     no_close,     fd_read,   fd_write,   no_ioctl  },
+  /* 2: /dev/tty       TTY devices */
+  {  trstty_open, trstty_close, tty_read,  tty_write,  gfx_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 },
+  /* 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: no tape */
+  {  nxio_open,     no_close,   no_rdwr,   no_rdwr,    no_ioctl },
+  /* 9: ide block devices (temporarily until we make /dev/hd a blkdev device */
+  {  blkdev_open, no_close,     blkdev_read,   blkdev_write,   blkdev_ioctl  },
+};
+
+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) - 1)
+       return false;
+    else
+        return true;
+}
diff --git a/Kernel/platform-genie-eg64/devinput.c b/Kernel/platform-genie-eg64/devinput.c
new file mode 100644 (file)
index 0000000..8385055
--- /dev/null
@@ -0,0 +1,112 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <input.h>
+#include <devgfx.h>
+#include <devinput.h>
+
+__sfr __at 0x00 stick;
+static uint8_t old_stick;
+
+__sfr __at 0x7C chroma0;
+__sfr __at 0x7E chroma1;
+static uint8_t old_cj[2];
+
+static char buf[32];
+static struct s_queue kqueue = {
+ buf, buf, buf, sizeof(buf), 0, sizeof(buf) / 2
+};
+
+/* Queue a character to the input device */
+void queue_input(uint8_t c)
+{
+    insq(&kqueue, c);
+    wakeup(&kqueue);
+}
+
+/* If both are present number the Chroma joysticks 1 and 2 */
+static int chroma_js(uint8_t *slot, uint8_t n, uint8_t v)
+{
+    uint8_t k = 0;
+    if (v == old_cj[n])
+        return 0;
+    old_cj[n] = v;
+    if (v & 1)
+        k = STICK_DIGITAL_L;
+    if (v & 2)
+        k = STICK_DIGITAL_R;
+    if (v & 4)
+        k = STICK_DIGITAL_U;
+    if (v & 8)
+        k = STICK_DIGITAL_D;
+    if (v & 16)
+        k = BUTTON(0);
+    *slot++ = STICK_DIGITAL | (n + 1);
+    *slot = k;
+    return 2;
+}
+     
+int platform_input_read(uint8_t *slot)
+{
+    uint8_t r, k;
+    if (remq(&kqueue, &r)) {
+        remq(&kqueue, &k);
+       *slot++ = KEYPRESS_CODE | r;
+       *slot++ = k;
+       return 2;
+    }
+
+    if (has_chroma) {
+        if (chroma_js(slot, 0, ~chroma0))
+           return 2;
+        if (chroma_js(slot, 1, ~chroma1))
+           return 2;
+    }
+    /* Clashes with Alpha joystick */
+    if (has_hrg1)
+        return 0;
+
+    r = ~stick;
+    if (r == old_stick)
+        return 0;
+
+    old_stick = r;
+
+    k = 0;
+    /* Legacy joystick encoding U|D = FIRE */
+    if ((r & 3) == 3) {
+        r &= ~3;
+        r |= 16;
+    }
+    if (r & 1)
+        k = STICK_DIGITAL_U;
+    if (r & 2)
+        k |= STICK_DIGITAL_D;
+    if (r & 4)
+        k |= STICK_DIGITAL_L;
+    if (r & 8)
+        k |= STICK_DIGITAL_R;
+    if (r & 16)
+        k |= BUTTON(0);
+    *slot++ = STICK_DIGITAL;
+    *slot = k;
+    return 2;
+}
+
+void platform_input_wait(void)
+{
+    psleep(&kqueue);   /* We wake this on timers so it works for sticks */
+}
+
+int platform_input_write(uint8_t flag)
+{
+    flag;
+    udata.u_error = EINVAL;
+    return -1;
+}
+
+void poll_input(void)
+{
+    if ((!has_hrg1 && ~stick != old_stick) || 
+       (has_chroma && (old_cj[0] != ~chroma0 || old_cj[1] != ~chroma1)))
+           wakeup(&kqueue);
+}
diff --git a/Kernel/platform-genie-eg64/devinput.h b/Kernel/platform-genie-eg64/devinput.h
new file mode 100644 (file)
index 0000000..5d79a9e
--- /dev/null
@@ -0,0 +1,4 @@
+
+extern void queue_input(uint8_t c);
+extern void poll_input(void);
+extern uint8_t vblank;
diff --git a/Kernel/platform-genie-eg64/devlpr.c b/Kernel/platform-genie-eg64/devlpr.c
new file mode 100644 (file)
index 0000000..717c8f3
--- /dev/null
@@ -0,0 +1,62 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devlpr.h>
+#include <trs80.h>
+
+#define lp     *((volatile uint8_t *)0x37E8)
+
+__sfr __at 0xFD vg_lp;
+
+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;
+}
+
+static uint8_t iopoll(void)
+{
+       /* Ought to be a core helper for this lot ? */
+       if (need_reschedule())
+               _sched_yield();
+       if (chksigs()) {
+               if (!udata.u_done) {
+                       udata.u_error = EINTR;
+                       udata.u_done = (usize_t)-1;
+                }
+                return 1;
+       }
+       return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+    char *p = udata.u_base;
+    minor; rawflag; flag; // shut up compiler
+
+    while(udata.u_done < udata.u_count) {
+        if (trs80_model == VIDEOGENIE) {
+            while (vg_lp & 0x80) {
+                if (iopoll())
+                    return udata.u_done;
+            }
+            /* FIXME: tidy up ugetc and sysio checks globally */
+            vg_lp = ugetc(p++);
+        } else {
+            while (lp & 0x80) {
+                if (iopoll())
+                    return udata.u_done;
+            }
+            /* FIXME: tidy up ugetc and sysio checks globally */
+            lp = ugetc(p++);
+        }
+        udata.u_done++;
+    }
+    return udata.u_done;
+}
diff --git a/Kernel/platform-genie-eg64/devlpr.h b/Kernel/platform-genie-eg64/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-genie-eg64/devtty.c b/Kernel/platform-genie-eg64/devtty.c
new file mode 100644 (file)
index 0000000..f6408a1
--- /dev/null
@@ -0,0 +1,432 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <vt.h>
+#include <devtty.h>
+#include <input.h>
+#include <devinput.h>
+#include <devgfx.h>
+#include <stdarg.h>
+#include <trs80.h>
+
+/* FIXME: move to external tty buffers and bank them */
+static char tbuf1[TTYSIZ];
+static char tbuf2[TTYSIZ];
+static char tbuf3[TTYSIZ];
+
+uint8_t curtty;                        /* output side */
+static uint8_t inputtty;       /* input side */
+static struct vt_switch ttysave[2];
+struct vt_repeat keyrepeat;
+extern uint8_t *vtbase[2];
+
+/* Default to having /dev/tty and the two consoles openable. Our probe
+   routine will add tty2/tty3 as appropriate */
+
+static uint8_t ports = 3;
+
+/* The Video Genie EG3020 is similar but the TR1865 is
+   data in: F8, status out F8, data out: F9 status in F9,
+   baud by switches.
+
+   Or at least it probably does. In theory you can use an adapter
+   cable and Tandy bits so we treat them as two ports */
+
+__sfr __at 0xE8 tr1865_ctrl;
+static uint8_t tr1865_ctrl_save;
+__sfr __at 0xE9 tr1865_baud;
+__sfr __at 0xEA tr1865_status;
+__sfr __at 0xEB tr1865_rxtx;
+
+__sfr __at 0xF8 vg_tr1865_wrst;
+__sfr __at 0xF9 vg_tr1865_ctrd;
+static uint8_t vg_tr1865_ctrd_save;
+
+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},
+       {tbuf3, tbuf3, tbuf3, TTYSIZ, 0, TTYSIZ / 2},
+};
+
+static uint8_t trs_flow;               /* RTS/CTS */
+
+/* Write to system console */
+void kputchar(char c)
+{
+       if (c == '\n')
+               tty_putc(1, '\r');
+       tty_putc(1, c);
+}
+
+ttyready_t tty_writeready(uint8_t minor)
+{
+       uint8_t reg;
+       if (minor == 1)
+               return TTY_READY_NOW;
+       /* RTS/CTS is supported by the hardware. We assume delays will be
+          short as with our rather limited serial if we go off and schedule
+          something else each flow control it will get horribly slow */
+       if (minor == 2) {
+               if (ttydata[2].termios.c_cflag & CRTSCTS) {
+                       reg = tr1865_ctrl;
+                       if (!(reg & 0x80))
+                               return TTY_READY_SOON;
+               }
+               reg = tr1865_status;
+               return (reg & 0x40) ? TTY_READY_NOW : TTY_READY_SOON;
+       }
+       /* minor == 3 */
+       reg = vg_tr1865_wrst;
+       if (ttydata[3].termios.c_cflag & CRTSCTS) {
+               /* CTS ? */
+               if (!(reg & 0x40))
+                       return TTY_READY_SOON;
+       }
+       return (reg & 0x80) ? TTY_READY_NOW : TTY_READY_SOON;
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+       if (minor == 2)
+               tr1865_rxtx = c;
+       else if (minor == 3)
+               vg_tr1865_wrst = c;
+       else
+               vtoutput(&c,1);
+}
+
+void tty_data_consumed(uint8_t minor)
+{
+       if (trs_flow & (1 << minor)) {
+               if (minor == 2) {
+                       /* We have space.. raise RTS */
+                       if (!fullq(&ttyinq[2]))
+                               tr1865_ctrl = tr1865_ctrl_save|0x01;
+               }
+               if (minor == 3) {
+                       /* We have space.. raise RTS */
+                       if (!fullq(&ttyinq[3]))
+                               vg_tr1865_ctrd = vg_tr1865_ctrd_save|0x01;
+               }
+       }
+}
+
+/* Only the Model III has this as an actual interrupt */
+void tty_interrupt(void)
+{
+       uint8_t reg = tr1865_status;
+       if (reg & 0x80) {
+               reg = tr1865_rxtx;
+               tty_inproc(2, reg);
+       }
+       if ((trs_flow & 8) && fullq(&ttyinq[2]))
+               tr1865_ctrl = tr1865_ctrl_save & ~1;
+}
+
+void tty_poll(void)
+{
+       uint8_t reg;
+
+       /* Do the VG port */
+       if (ports & 0x10) {
+               reg = vg_tr1865_wrst;
+               if (reg & 0x01) {
+                       reg = vg_tr1865_ctrd;
+                       tty_inproc(3, reg);
+               }
+               if ((trs_flow & 0x10) && fullq(&ttyinq[3]))
+                       vg_tr1865_ctrd = vg_tr1865_ctrd_save & ~1;
+       }
+       /* Do the Model I/III port */
+       if (ports & 0x08)
+               tty_interrupt();
+}
+
+/* Called to set baud rate etc */
+static const uint8_t trsbaud[] = {
+       0, 0, 1, 2, 3, 4, 5, 6, 7, 10, 14, 15
+};
+
+static const uint8_t trssize[4] = {
+       0x00, 0x40, 0x20, 0x60
+};
+
+void tty_setup(uint8_t minor)
+{
+       uint8_t baud;
+       uint8_t ctrl = 3;               /* DTR|RTS */
+       struct tty *t = ttydata + minor;
+       
+       if (minor == 1)
+               return;
+
+       if (minor != 2 || trs80_model == LNW80) {
+               baud = ttydata[2].termios.c_cflag & CBAUD;
+               if (baud > B19200) {
+                       ttydata[2].termios.c_cflag &= ~CBAUD;
+                       ttydata[2].termios.c_cflag |= B19200;
+                       baud = B19200;
+               } else
+                       baud = trsbaud[baud];
+
+               tr1865_baud = baud | (baud << 4);
+
+       }
+       if (t->termios.c_cflag & PARENB) {
+               if (t->termios.c_cflag & PARODD)
+                       ctrl |= 0x80;
+       } else
+               ctrl |= 0x8;    /* No parity */
+       ctrl |= trssize[(t->termios.c_cflag & CSIZE) >> 4];
+
+       if (t->termios.c_cflag & CRTSCTS)
+               trs_flow |= (1 << minor);
+       else
+               trs_flow &- ~(1 << minor);
+       if (minor == 3) {
+               tr1865_ctrl_save = ctrl;
+               tr1865_ctrl = ctrl;
+       } else {
+               vg_tr1865_ctrd_save = ctrl;
+               vg_tr1865_ctrd = ctrl;
+       }
+}
+
+int trstty_open(uint8_t minor, uint16_t flags)
+{
+       /* Serial port cards are optional */
+       if (minor < 8 && !(ports & (1 << minor))) {
+               udata.u_error = ENODEV;
+               return -1;
+       }
+       return tty_open(minor, flags);
+}
+
+int trstty_close(uint8_t minor)
+{
+       if (ttydata[minor].users == 0) {
+               trs_flow &= ~(1 << minor);
+               if (minor == 2)
+                       tr1865_ctrl = 0;        /* Drop carrier and rts */
+               else if (minor == 3)
+                       vg_tr1865_ctrd = 0;
+       }
+       return tty_close(minor);
+}
+
+int tty_carrier(uint8_t minor)
+{
+       if (minor == 1)
+               return 1;
+       if (minor == 2) {
+               if (tr1865_ctrl & 0x80)
+                       return 1;
+       } else if (vg_tr1865_ctrd & 0x10)
+               return 1;
+       return 0;
+}
+
+void tty_sleeping(uint8_t minor)
+{
+       used(minor);
+}
+
+void trstty_probe(void)
+{
+       if (vg_tr1865_wrst != 0xFF)
+               ports |= (1 << 3);
+       if (tr1865_status != 0xFF)
+               ports |= (1 << 2);
+}
+
+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 *) (0x3800 | (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)) {
+                                               if (keyboard_grab == 3) {
+                                                       queue_input(KEYPRESS_UP);
+                                                       queue_input(keyboard[i][n]);
+                                               }
+                                               keysdown--;
+                                       }
+                               }
+                               if ((key & m) && !(keymap[i] & m)) {
+                                       if (!(shiftmask[i] & m)) {
+                                               keysdown++;
+                                               newkey = 1;
+                                               keybyte = i;
+                                               keybit = n;
+                                       }
+                               }
+                               m += m;
+
+                       }
+               }
+               keymap[i] = keyin[i];
+       }
+}
+
+/*
+ *     The TRS80 keyboard is a little lacking in some rather useful symbols
+ *
+ *     There are conventions for some of these
+ *     shift-0 is capslock
+ *     downarrow-xx is ctrl
+ *     There was also a popular keyboard mod
+ *
+ *     We also map as follows
+ *     left arrow - backspace
+ *     right arrow - delete
+ *     shift left/right arrow - switch vt
+ *     stop - ^C
+ *     control-shift-brackets give curly brackets
+ *     control-shift minus gives underscore
+ *     control-shift slash gives backquote
+ *     control-shift les-than gives hat
+ *     control-brackets gives square brackets
+ *     control-minus gives pipe
+ *
+ *     We may want to add others if need be
+ *
+ *     TODO: Where does the LNW80 hide F1/F2 ?
+ */
+
+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'},
+       /* F1-F4 are only present on Video Genie II/Dick Smith II */
+       {'x', 'y', 'z', 0, KEY_F2, KEY_F3, KEY_F4, KEY_F1},
+       {'0', '1', '2', '3', '4', '5', '6', '7'},
+       {'8', '9', ':', ';', ',', '-', '.', '/'},
+       {KEY_ENTER, KEY_CLEAR, KEY_STOP, KEY_UP, 0 /*KEY_DOWN */ , KEY_BS, KEY_DEL, ' '},
+       /* The Model 1 only has bit 0 of this for its shift key. The Model 3
+          has bit 2 for right shift. Some add-ons used bit 4 for control,
+          other things borrowed the down arrow
+          The VideoGenie has MS on bit 1, RPT on 3 and CTRL on 4 */
+       {0, 0, 0, 0, KEY_CAPSLOCK, 0, 0, 0}
+};
+
+uint8_t shiftkeyboard[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, 0, 0, 0, 0},
+       {KEY_CAPSLOCK, '!', '"', '#', '$', '%', '&', '\''},
+       {'(', ')', '*', '+', '<', '=', '>', '?'}        ,
+       {KEY_ENTER, KEY_CLEAR, KEY_STOP, KEY_UP, 0 /*KEY_DOWN */ , KEY_LEFT, KEY_RIGHT, ' '},
+       {0, 0, 0, 0, KEY_CAPSLOCK, 0, 0, 0}
+};
+
+static uint8_t capslock = 0;
+static uint8_t kbd_timer;
+
+static void keydecode(void)
+{
+       uint8_t c;
+       uint8_t m = 0;
+
+       /* Convention for capslock or the mod */
+       /* Only the model 3 has right shift (2) */
+       if (keymap[7] & 3) {    /* shift (left/right) */
+               m = KEYPRESS_SHIFT;
+               c = shiftkeyboard[keybyte][keybit];
+       } else
+               c = keyboard[keybyte][keybit];
+
+       if (c == KEY_CAPSLOCK) {
+               capslock = 1 - capslock;
+               return;
+       }
+       /* The keyboard lacks some rather important symbols so remap them
+          with control (down arrow) */
+       if ((keymap[6] | keymap[7]) & 16) {     /* control */
+               m |= KEYPRESS_CTRL;
+               if (keymap[7] & 3) {    /* shift */
+                       if (c == '(')
+                               c = '{';
+                       if (c == ')')
+                               c = '}';
+                       if (c == '-')
+                               c = '_';
+                       if (c == '/')
+                               c = '``';
+                       if (c == '<')
+                               c = '^';
+               } else {
+                       if (c == '8' /*'(' */ )
+                               c = '[';
+                       else if (c == '9' /*')' */ )
+                               c = ']';
+                       else if (c == '-')
+                               c = '|';
+                       else if (c > 31 && c < 127)
+                               c &= 31;
+               }
+       } else if (capslock && c >= 'a' && c <= 'z')
+               c -= 'a' - 'A';
+       if (c) {
+               switch (keyboard_grab) {
+               case 0:
+                       vt_inproc(1, c);
+                       break;
+               case 1:
+                       if (!input_match_meta(c)) {
+                               vt_inproc(1, c);
+                               break;
+                       }
+                       /* Fall through */
+               case 2:
+                       queue_input(KEYPRESS_DOWN);
+                       queue_input(c);
+                       break;
+               case 3:
+                       /* Queue an event giving the base key (unshifted)
+                          and the state of shift/ctrl/alt */
+                       queue_input(KEYPRESS_DOWN | m);
+                       queue_input(keyboard[keybyte][keybit]);
+                       break;
+               }
+       }
+}
+
+/* Polled 40 times a second */
+void kbd_interrupt(void)
+{
+       newkey = 0;
+       keyproc();
+       if (keysdown && keysdown < 3) {
+               if (newkey) {
+                       keydecode();
+                       kbd_timer = keyrepeat.first;
+               } else if (!--kbd_timer) {
+                       keydecode();
+                       kbd_timer = keyrepeat.continual;
+               }
+       }
+       poll_input();
+}
diff --git a/Kernel/platform-genie-eg64/devtty.h b/Kernel/platform-genie-eg64/devtty.h
new file mode 100644 (file)
index 0000000..f85d2db
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _DEVTTY_H
+#define _DEVTTY_H
+
+extern void tty_interrupt(void);
+extern void tty_poll(void);
+extern void kbd_interrupt(void);
+extern int trstty_open(uint8_t minor, uint16_t flags);
+extern int trstty_close(uint8_t minor);
+extern void trstty_probe(void);
+extern void vtbuf_init(void);
+
+/* And from the asm helper */
+extern void vtswap(void);
+
+#define KEY_ROWS       8
+#define KEY_COLS       8
+extern uint8_t keymap[8];
+extern uint8_t keyboard[8][8];
+extern uint8_t shiftkeyboard[8][8];
+
+extern uint8_t *vtbase[2];
+extern uint8_t curtty;
+#endif
diff --git a/Kernel/platform-genie-eg64/discard.c b/Kernel/platform-genie-eg64/discard.c
new file mode 100644 (file)
index 0000000..0646021
--- /dev/null
@@ -0,0 +1,62 @@
+#include <kernel.h>
+#include <devhd.h>
+#include <devtty.h>
+#include <tty.h>
+#include <kdata.h>
+#include "devgfx.h"
+#include <devide.h>
+#include "trs80.h"
+
+static void vt_check_lower(void)
+{
+  *VT_BASE = 'a';
+  if (*VT_BASE == 'a')
+    video_lower = 1;
+}
+
+void device_init(void)
+{
+  vt_check_lower();
+#ifdef CONFIG_RTC
+  /* Time of day clock */
+  inittod();
+#endif
+  hd_probe();
+  devide_init();
+  trstty_probe();
+  gfx_init();
+}
+
+void map_init(void)
+{
+}
+
+/* string.c
+ * Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+static int strcmp(const char *d, const char *s)
+{
+       register char *s1 = (char *) d, *s2 = (char *) s, c1, c2;
+
+       while ((c1 = *s1++) == (c2 = *s2++) && c1);
+       return c1 - c2;
+}
+
+uint8_t platform_param(char *p)
+{
+    if (strcmp(p, "pcg80") == 0) {
+     trs80_udg = UDG_PCG80;
+     return 1;
+    }
+    if (strcmp(p, "80gfx") == 0) {
+     trs80_udg = UDG_80GFX;
+     return 1;
+    }
+    if (strcmp(p, "micro") == 0) {
+     trs80_udg = UDG_MICROFIRMA;
+     return 1;
+    }
+    return 0;
+}
diff --git a/Kernel/platform-genie-eg64/fuzix.lnk b/Kernel/platform-genie-eg64/fuzix.lnk
new file mode 100644 (file)
index 0000000..504ae9f
--- /dev/null
@@ -0,0 +1,53 @@
+-mwxuy
+-i fuzix.ihx
+-b _INITIALIZER=0x37C0
+-b _BOOT=0x0100
+-b _CODE=0x4000
+-b _COMMONMEM=0x0200
+-l z80
+platform-genie-eg64/crt0.rel
+platform-genie-eg64/commonmem.rel
+platform-genie-eg64/trs80.rel
+platform-genie-eg64/trs80-bank.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+usermem.rel
+platform-genie-eg64/tricks.rel
+platform-genie-eg64/main.rel
+timer.rel
+kdata.rel
+platform-genie-eg64/devfd.rel
+platform-genie-eg64/floppy.rel
+platform-genie-eg64/devhd.rel
+platform-genie-eg64/devhd_discard.rel
+platform-genie-eg64/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_exec16.rel
+syscall_fs.rel
+syscall_fs2.rel
+syscall_fs3.rel
+syscall_net.rel
+syscall_proc.rel
+syscall_other.rel
+tty.rel
+mm.rel
+swap.rel
+simple.rel
+vt.rel
+devsys.rel
+devinput.rel
+platform-genie-eg64/blkdev.rel
+platform-genie-eg64/devgfx.rel
+platform-genie-eg64/devide.rel
+platform-genie-eg64/devide_discard.rel
+platform-genie-eg64/devinput.rel
+platform-genie-eg64/devlpr.rel
+platform-genie-eg64/devtty.rel
+platform-genie-eg64/discard.rel
+platform-genie-eg64/mbr.rel
+usermem_std-z80.rel
+-e
diff --git a/Kernel/platform-genie-eg64/kernel.def b/Kernel/platform-genie-eg64/kernel.def
new file mode 100644 (file)
index 0000000..dcb7d3d
--- /dev/null
@@ -0,0 +1,15 @@
+; UZI mnemonics for memory addresses etc
+
+U_DATA                      .equ 0x0200       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           .equ 0x200        ; 256+256 (we don't save istack)
+
+PROGBASE                   .equ 0x8000
+PROGLOAD                   .equ 0x8000
+
+Z80_TYPE                   .equ 1
+
+NBUFS                      .equ 4
+
+Z80_MMU_HOOKS              .equ 0
+
+CONFIG_SWAP                .equ 1
diff --git a/Kernel/platform-genie-eg64/main.c b/Kernel/platform-genie-eg64/main.c
new file mode 100644 (file)
index 0000000..440e45e
--- /dev/null
@@ -0,0 +1,180 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <rtc.h>
+#include <devtty.h>
+#include <trs80.h>
+
+uint16_t ramtop = PROGTOP;
+uint8_t trs80_model;
+uint8_t vtattr_cap;
+uint8_t need_resched;
+
+/*
+ *     Called when there is no work to do. On the models without serial
+ *     interrupts we poll here so that the normal case of idling while
+ *     waiting for input feels ok.
+ */
+void platform_idle(void)
+{
+  irqflags_t irq;
+  irq = di();
+  tty_poll();
+  irqrestore(irq);
+}
+
+void do_beep(void)
+{
+}
+
+/* Work around SDCC bugs */
+uint8_t sdcc_bug_2753(uint8_t v) __z88dk_fastcall
+{
+  return v;
+}
+
+__sfr __at 0xE0 irqstat3;
+__sfr __at 0xEC irqack3;
+
+/* We assign these to dummy to deal with an sdcc bug (should be fixed in next
+   SDCC) */
+void platform_interrupt(void)
+{
+  uint8_t dummy;
+  uint8_t irq = *((volatile uint8_t *)0x37E0);
+
+  tty_interrupt();
+  kbd_interrupt();
+
+  if (irq & 0x40)
+    dummy = sdcc_bug_2753(*((volatile uint8_t *)0x37EC));
+  if (irq & 0x80) {    /* FIXME??? */
+    timer_interrupt();
+    dummy = sdcc_bug_2753(*((volatile uint8_t *)0x37E0));      /* Ack the timer */
+  }
+}
+
+struct blkbuf *bufpool_end = &bufpool[NBUFS];
+
+void platform_discard(void)
+{
+       bufptr bp;
+       uint16_t space = (uint8_t *)0x37E0 - (uint8_t *)bufpool_end;
+       space /= BLKSIZE;
+       bufpool_end += space;
+       kprintf("Reclaiming memory.. total buffers %d\n",
+         bufpool_end - bufpool);
+       for( bp = bufpool + NBUFS; bp < bufpool_end; ++bp ){
+               bp->bf_dev = NO_DEVICE;
+               bp->bf_busy = BF_FREE;
+       }
+}
+
+#ifdef CONFIG_RTC
+
+__sfr __at 0xB0 rtc_secl;
+__sfr __at 0xB1 rtc_sech;
+__sfr __at 0xB2 rtc_minl;
+__sfr __at 0xB3 rtc_minh;
+__sfr __at 0xB4 rtc_hourl;
+__sfr __at 0xB5 rtc_hourh;
+/* day of week is B6 */
+__sfr __at 0xB7 rtc_dayl;
+__sfr __at 0xB8 rtc_dayh;
+__sfr __at 0xB9 rtc_monl;
+__sfr __at 0xBA rtc_monh;
+__sfr __at 0xBB rtc_yearl;
+__sfr __at 0xBC rtc_yearh;
+
+/* FIXME: the RTC is optional so we should test for it first */
+uint8_t platform_rtc_secs(void)
+{
+    uint8_t sl, rv;
+    /* BCD encoded */
+    do {
+        sl = rtc_secl;
+        /* RTC may be absent */
+        if (sl == 255)
+          return 255;
+        rv = sl + rtc_sech * 10;
+    } while (sl != rtc_secl);
+    return rv;
+}
+
+/* If the compiler segfaults here you need at least SDCC #10471 */
+
+int platform_rtc_read(void)
+{
+    uint16_t len = sizeof(struct cmos_rtc);
+    struct cmos_rtc cmos;
+    uint8_t *p;
+    uint8_t r, y;
+
+    if (udata.u_count < len)
+        len = udata.u_count;
+
+    if (rtc_secl == 255) {
+      udata.u_error = EOPNOTSUPP;
+      return -1;
+    }
+
+    /* We do a full set of reads and if the seconds change retry - we
+       need to retry the lost as we might read as the second changes for
+       new year */
+    do {
+      p = cmos.data.bytes;
+      r = rtc_secl;
+      y  = (rtc_yearh << 4) | rtc_yearl;
+      if (y > 70)
+          *p++ = 19;
+      else
+          *p++ = 20;
+      *p++ = y;
+      *p++ = ((rtc_monh  & 1)<< 4) | rtc_monl;
+      *p++ = ((rtc_dayh & 3) << 4) | rtc_dayl;
+      *p++ = ((rtc_hourh & 3) << 4) | rtc_hourl;
+      *p++ = ((rtc_minh & 7) << 4) | rtc_minl;
+      *p++ = ((rtc_sech & 7) << 4) | rtc_secl;
+    } while ((r ^ rtc_secl) & 0x0F);
+
+    cmos.type = CMOS_RTC_BCD;
+    if (uput(&cmos, udata.u_base, len) == -1)
+        return -1;
+    return len;
+}
+
+/* Yes I'm a slacker .. this wants adding but it's ugly
+   because the seconds is always just set to 0 on any change. We
+   also need to deal with leap years here */
+int platform_rtc_write(void)
+{
+       udata.u_error = EOPNOTSUPP;
+       return -1;
+}
+
+#endif
+
+/*
+ *     So that we don't suck in a library routine we can't use from
+ *     the runtime
+ */
+
+int strlen(const char *p)
+{
+  int len = 0;
+  while(*p++)
+    len++;
+  return len;
+}
+
+uint8_t video_lower;
+
+uint8_t vt_map_char(uint8_t x)
+{
+  if (video_lower)
+    return x;
+  if (x >= 96 && x <= 127)
+    return x - 32;
+  return x;
+}
diff --git a/Kernel/platform-genie-eg64/platform_ide.h b/Kernel/platform-genie-eg64/platform_ide.h
new file mode 100644 (file)
index 0000000..baf7842
--- /dev/null
@@ -0,0 +1,6 @@
+#define IDE_DRIVE_COUNT                2
+#define IDE_REG_CS1_BASE       0x40
+#define IDE_8BIT_ONLY
+
+#define ide_select(x)
+#define ide_deselect()
diff --git a/Kernel/platform-genie-eg64/trs80.h b/Kernel/platform-genie-eg64/trs80.h
new file mode 100644 (file)
index 0000000..f6d4eb7
--- /dev/null
@@ -0,0 +1,43 @@
+
+extern uint8_t trs80_model;
+#define TRS80_MODEL1   0
+#define TRS80_MODEL3   1
+#define LNW80          2       /* Need to handle LNW80 model II.. */
+#define VIDEOGENIE     3       /* But colour genie is way too different.. */
+
+extern uint8_t trs80_mapper;
+#define MAP_SUPERMEM   0       /* Alpha Supermem and compatibles */
+#define MAP_SELECTOR   1       /* Selector */
+
+extern uint8_t trs80_udg;      /* User defined graphics module */
+#define UDG_NONE       0
+#define UDG_PCG80      1       /* Orcim PCG80 */
+#define UDG_80GFX      2       /* Programma 80-Grafix */
+#define UDG_MICROFIRMA 3       /* External box option for UK TRS80 Model 1 */
+
+extern uint8_t video_lower;    /* Lowercase available */
+
+/*
+ *     Differences versus model 1
+ *
+ *     LNW80           Port 0xFE control for memory, extra graphics modes,
+ *                     (not currently supported). 4MHz CPU mode. Memory
+ *                     expansions include the selector.
+ *     LNW80 II        Adds 4 banks of graphics memory it seems. Also adds
+ *                     port 0x1f which controls low system RAM
+ *                     (bit 1 - ROM off if set, bit 2 blocks IRQ if set)
+ *     VideoGenie      Printer at 0xFD not memory mapped. The earlier
+ *                     expansion unit is a 3 slot S100 backplane so can be
+ *                     fitted with banked S100 memory (only the upper 32K
+ *                     seems to map to the S100). Some had lower case.
+ *     Model 3         Floppy moves to 0xF0-F4/F7 except for status, Sound
+ *                     click moves to 0x90 printer to 0xFB. 0xEF control
+ *                     register, NMI control, Interrupt mask register.
+ *                     Interrupt latch doesn't ack timer and is inverted.
+ *                     Lower case !!
+ *
+ *     Note that the Colour Genie is a very different beast.
+ *     
+ */
+
+extern void bufsetup(void);