pentagon: first draft at a port
authorAlan Cox <alan@linux.intel.com>
Fri, 8 Feb 2019 23:03:45 +0000 (23:03 +0000)
committerAlan Cox <alan@linux.intel.com>
Fri, 8 Feb 2019 23:03:45 +0000 (23:03 +0000)
There is lots to do here including writing some bootstrap code so we can
actually test it

19 files changed:
Kernel/platform-pentagon/Makefile [new file with mode: 0644]
Kernel/platform-pentagon/README [new file with mode: 0644]
Kernel/platform-pentagon/commonmem.s [new file with mode: 0644]
Kernel/platform-pentagon/config.h [new file with mode: 0644]
Kernel/platform-pentagon/crt0.s [new file with mode: 0644]
Kernel/platform-pentagon/devices.c [new file with mode: 0644]
Kernel/platform-pentagon/devtty.c [new file with mode: 0644]
Kernel/platform-pentagon/devtty.h [new file with mode: 0644]
Kernel/platform-pentagon/discard.c [new file with mode: 0644]
Kernel/platform-pentagon/fuzix.lnk [new file with mode: 0644]
Kernel/platform-pentagon/kernel.def [new file with mode: 0644]
Kernel/platform-pentagon/loader.s [new file with mode: 0644]
Kernel/platform-pentagon/main.c [new file with mode: 0644]
Kernel/platform-pentagon/pentagon.s [new file with mode: 0644]
Kernel/platform-pentagon/platform_ide.h [new file with mode: 0644]
Kernel/platform-pentagon/rules.mk [new file with mode: 0644]
Kernel/platform-pentagon/target.mk [new file with mode: 0644]
Kernel/platform-pentagon/tricks.s [new file with mode: 0644]
Kernel/platform-pentagon/zxvideo.s [new file with mode: 0644]

diff --git a/Kernel/platform-pentagon/Makefile b/Kernel/platform-pentagon/Makefile
new file mode 100644 (file)
index 0000000..6964769
--- /dev/null
@@ -0,0 +1,52 @@
+CSRCS = devtty.c devices.c main.c
+CDSRCS = discard.c
+DSRCS = ../dev/devide.c ../dev/devsd.c ../dev/blkdev.c
+DDSRCS = ../dev/devide_discard.c ../dev/devsd_discard.c ../dev/mbr.c
+DZSRCS = ../dev/zx/divide.c ../dev/zx/zxmmc.c ../dev/zx/zxkeyboard.c
+DZSRCS += ../dev/zx/devinput.c ../dev/zx/bankbig.c
+DDZSRCS =
+ASRCS = crt0.s pentagon.s zxvideo.s
+ASRCS += tricks.s commonmem.s
+
+COBJS = $(CSRCS:.c=.rel)
+CDOBJS = $(CDSRCS:.c=.rel)
+AOBJS = $(ASRCS:.s=.rel)
+DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS))
+DDOBJS = $(patsubst ../dev/%.c,%.rel, $(DDSRCS))
+DZOBJS = $(patsubst ../dev/zx/%.c,%.rel, $(DZSRCS))
+DDZOBJS = $(patsubst ../dev/zx/%.c,%.rel, $(DDZSRCS))
+OBJS  = $(COBJS) $(CDOBJS) $(AOBJS) $(DOBJS) $(DDOBJS) $(DZOBJS) $(DDZOBJS)
+
+CROSS_CCOPTS += -I../dev/ -I../dev/zx/
+
+CROSS_CC_SEG3 = --codeseg CODE3
+
+all:   $(OBJS)
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG3) -c $<
+
+$(CDOBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(DOBJS): %.rel: ../dev/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG3) -c $<
+
+$(DDOBJS): %.rel: ../dev/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(DZOBJS): %.rel: ../dev/zx/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG3) -c $<
+
+$(DDZOBJS): %.rel: ../dev/zx/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) $<
+
+clean:
+       rm -f $(OBJS) *.lst *.asm *.sym *.rst *.rel core *~ 
+       rm -f BOOT.BIN strap.bin load-esx.ihx load-esx.tmp
+       rm -f FUZIX.BIN FUZIX
+
+image:
diff --git a/Kernel/platform-pentagon/README b/Kernel/platform-pentagon/README
new file mode 100644 (file)
index 0000000..1ed6be8
--- /dev/null
@@ -0,0 +1,93 @@
+Experimental porting work for Pentagon and similar systems that have the ability
+to somehow get the low 16K mapped into page 0 and have at least 256K of RAM.
+
+For now we hardcode 256K and Pentagon style rules (although it seems they
+vary even by pentagon type). As far as I can make out the basic rules for
+each type are
+
+Everyone uses 0x7FFD bits 0-2 = low 128K bank select, and 3 to move video
+
+Then it gets more complicated (and the partial decode ports make it worse)
+
+Pentagon uses bits 7/6 to allow for 512K RAM
+
+Some pentagon designs use 1FFD bit 0 to put RAM 0 into the low 16K, and
+use 1FFD bits 4 and 7 instead of 7FFD bits 7/6
+
+Pentagon 1MB uses EFF7 bit 3 to turn on the RAM mapping
+
+Scorpion 256/Kay 256 uses 1FFD bit 0 to put RAM 0 into the low 16K and then
+uses 1FFD bit 4 for the 256K select. Scoripon uses 4/6/7 if 1MB
+Kay 1MB uses 1FFD 4 and 7 for 256/512 and 7FFD bit 7 for 1MB bank (why!!!)
+
+ZX Profi uses DFFD bits 0-2 to select the upper page bits. Those that
+support it (Profi 1024 ?) bit 4 maps RAM0. There are other weird mappings
+too.
+
+ATM us FDFD bits 0-2 but early ones can't map over ROM. Late ATM goes up to
+4MB and can
+
+What a mess 8)
+
+----
+These machines all have the same basic problem, there is a 16K window at
+C000-FFFF which is pageable but no bigger pageable range.
+
+We run with the following mapping
+
+0000-3FFF      IRQ vectors, common, const, commondata etc
+4000-5FFF      Spectrum screen memory and system variables
+6000-7FFF      Free for now
+8000-83FF      Needed to create the exec of init
+8400-BFFF      _DISCARD area - blown away when we exec init
+               (tons of room in this space)
+C000-FFFF
+       0:      0000-3FFF
+       1:      Kernel CODE (fairly full)
+       2:      Mapped at 0x8000-0xBFFF (holds current process copy)
+       3:      User process
+       4:      User process
+       5:      Mapped at 0x4000-0x7FFF (Sceen, Kernel data/common)
+       6:      Kernel CODE2 (fairly full)
+       7:      CODE3, Video (lots of room)
+
+User processes live in 3/4 and 8+. We have copy stuff back and forth
+to page 2 due to the memory manager liits.
+
+To Do:
+
+-      Why does ls /bin lose the lowest pixel row of the 'yes' command ?
+       (Seems we lose the bottom line of the left most char - off by one bug
+        in zxvid ?)
+-      Enable interrupts during swap
+-      6 or 5bit wide fonts (42, 51 column)
+-      Optimize zxvid - especially scrolling
+-      SMUC and similar IDE options
+-      Move vtborder to common
+-      See if we can in fact keep 6000-7FFF clear. If so we can look at
+       ldir switching another 8K up and down to give 40K program sizes
+       which would be a big improvement. Would need us to allocate 2.5
+       banks per process however so need some allocator changes
+
+Floppy disk interfaces are problematic. The standard Betadisk interface locks
+the I/O ports to its ROM being active, which sucks. Fortunately it appears
+there is a mildy insane stunt we can pull. We can use the ROM to query itself
+to find the address of the out (c),a present in all Beta ROM images.
+
+We can then do a ROP attack on the ROM in order to make it do the "right"
+out (c),a  in it in order to do a bank switch with RAM at 0000-3FFF and catch
+the next instruction. Providing we remain in the RAM below 4000 it'll leave
+the card selected.
+
+Does mean we need to patch our kernel to grab the next instruction, and then
+put it back all under di but it does look doable.
+
+
+TODO
+
+-      Write spectrum style and also disk boot style loaders
+-      Debug the loading
+-      Debug the rest
+-      Write SMUC and Nemo ATA driver code
+-      Work out what we need to do for Pentagon v Scorpion etc
+-      Floppy driver
diff --git a/Kernel/platform-pentagon/commonmem.s b/Kernel/platform-pentagon/commonmem.s
new file mode 100644 (file)
index 0000000..dc31c24
--- /dev/null
@@ -0,0 +1,8 @@
+;
+; Multiple app sizes and the fact the kernel and apps share the same banks
+; means we need to put this somewhere low
+;
+        .module commonmem
+        .area _COMMONDATA
+
+       .include "../cpu-z80/std-commonmem.s"
diff --git a/Kernel/platform-pentagon/config.h b/Kernel/platform-pentagon/config.h
new file mode 100644 (file)
index 0000000..9c15e3b
--- /dev/null
@@ -0,0 +1,74 @@
+#define CONFIG_IDE
+#define CONFIG_SD
+#define SD_DRIVE_COUNT 2
+#define CONFIG_LARGE_IO_DIRECT(x)      1  /* We support direct to user I/O */
+
+/* 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
+/* CP/M emulation */
+#undef CONFIG_CPM_EMU
+
+/* Input layer support */
+#define CONFIG_INPUT
+#define CONFIG_INPUT_GRABMAX   3
+/* Video terminal, not a serial tty */
+#define CONFIG_VT
+/* Keyboard contains non-ascii symbols */
+#define CONFIG_UNIKEY
+#define CONFIG_FONT8X8
+#define CONFIG_FONT8X8SMALL
+
+#define CONFIG_DYNAMIC_BUFPOOL
+#define CONFIG_DYNAMIC_SWAP
+
+/* Custom banking */
+
+/* A 1MB machine has 64 banks and the kernel plus system pages eat
+   0,1,2,5,6,7 */
+#define MAX_MAPS       58
+#define MAP_SIZE       0x4000U
+
+/* Banks as reported to user space */
+#define CONFIG_BANKS   2
+
+/* Vt definitions */
+#define VT_WIDTH       32
+#define VT_HEIGHT      24
+#define VT_RIGHT       31
+#define VT_BOTTOM      23
+
+#define TICKSPERSEC 50   /* Ticks per second */
+#define PROGBASE    0x8000  /* also data base */
+#define PROGLOAD    0x8000  /* also data base */
+#define PROGTOP     0xFE00  /* Top of program, base of U_DATA copy */
+#define PROC_SIZE   32   /* Memory needed per process */
+#define MAXTICKS    10   /* As our task switch is so expensive */
+
+#define BOOT_TTY (513)  /* 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 1
+
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define NBUFS    5       /* Number of block buffers */
+#define NMOUNTS         4        /* Number of mounts at a time */
+#define MAX_BLKDEV 4       /* 2 IDE drives, 2 SD drive */
+
+#define SWAP_SIZE 0x40
+#define MAX_SWAPS      16
+#define SWAPDEV  (swap_dev)  /* Device for swapping (dynamic). */
+
+/* All our pages get mapped into the top 16K bank for swapping use */
+#define swap_map(x)            ((uint8_t *)(x|0xC000))
diff --git a/Kernel/platform-pentagon/crt0.s b/Kernel/platform-pentagon/crt0.s
new file mode 100644 (file)
index 0000000..2de325b
--- /dev/null
@@ -0,0 +1,114 @@
+        .module crt0
+       ;
+       ;       Our common lives low
+       ;
+       .area _COMMONDATA
+        .area _COMMONMEM
+        .area _CONST
+       .area _STUBS
+        .area _INITIALIZED
+       ;
+       ;       Beyond this point we just zero.
+       ;
+        .area _DATA
+        .area _BSEG
+        .area _BSS
+        .area _HEAP
+        .area _GSINIT
+        .area _GSFINAL
+       ;
+       ;       Finally the buffers so they can expand
+       ;
+       .area _BUFFERS
+       ;
+       ;       All our code is banked at 0xC000
+       ;
+        .area _CODE1
+       .area _CODE2
+       ;       We start this bank with FONT so that we have it aligned
+       .area _FONT
+       .area _CODE3
+        .area _VIDEO
+
+       ; Discard is dumped in at 0x8000 and will be blown away later.
+        .area _DISCARD
+       ; Somewhere to throw it out of the way
+        .area _INITIALIZER
+
+        ; imported symbols
+        .globl _fuzix_main
+        .globl init_early
+        .globl init_hardware
+       .globl l__BUFFERS
+       .globl s__BUFFERS
+       .globl l__DATA
+       .globl s__DATA
+        .globl kstack_top
+
+        .globl unix_syscall_entry
+        .globl nmi_handler
+        .globl interrupt_handler
+
+       .include "../kernel.def"
+       .include "kernel.def"
+
+       .area _CODE1
+        ; startup code
+       ;
+       ; Entered from the bootstrap with 0-3FFF mapped and loaded as
+       ; RAM bank 0
+       ;
+        di
+
+       ;  We need to wipe the BSS but the rest of the job is done.
+
+       ld hl, #s__DATA
+       ld de, #s__DATA+1
+       ld bc, #l__DATA-1
+       ld (hl), #0
+       ldir
+       ld hl, #s__BUFFERS
+       ld de, #s__BUFFERS+1
+       ld bc, #l__BUFFERS-1
+       ld (hl), #0
+       ldir
+
+        ld sp, #kstack_top
+
+        ; Configure memory map
+       push af
+        call init_early
+       pop af
+
+        ; Hardware setup
+       push af
+        call init_hardware
+       pop af
+
+        ; Call the C main routine
+       push af
+        call _fuzix_main
+       pop af
+    
+        ; main shouldn't return, but if it does...
+        di
+stop:   halt
+        jr stop
+
+       .area _COMMONDATA
+
+       .area _STUBS
+stubs:
+       .ds 540
+
+       .area _BUFFERS
+;
+; Buffers (we use asm to set this up as we need them in a special segment
+; so we can recover the discard memory into the buffer pool
+;
+
+       .globl _bufpool
+       .area _BUFFERS
+
+_bufpool:
+       .ds BUFSIZE * NBUFS
diff --git a/Kernel/platform-pentagon/devices.c b/Kernel/platform-pentagon/devices.c
new file mode 100644 (file)
index 0000000..90c608d
--- /dev/null
@@ -0,0 +1,45 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devsys.h>
+#include <vt.h>
+#include <devide.h>
+#include <devsd.h>
+#include <blkdev.h>
+#include <devtty.h>
+
+struct devsw dev_tab[] =  /* The device driver switch table */
+{
+  /* 0: /dev/hd                Hard disc block devices */
+  {  blkdev_open,  no_close,     blkdev_read,   blkdev_write,  blkdev_ioctl },
+  /* 1: /dev/fd        Floppy disc block devices: nope */
+  {  no_open,      no_close,     no_rdwr,  no_rdwr,   no_ioctl },
+  /* 2: /dev/tty       TTY devices */
+  {  tty_open,    tty_close,    tty_read,      tty_write,     gfx_ioctl },
+  /* 3: /dev/lpr       Printer devices */
+  {  no_open,      no_close,     no_rdwr,       no_rdwr,       no_ioctl  },
+  /* 4: /dev/mem etc   System devices (one offs) */
+  {  no_open,      no_close,     sys_read,      sys_write,     sys_ioctl  },
+  /* 5: 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) - 1)
+       return false;
+    else
+        return true;
+}
+
+void device_init(void)
+{
+#ifdef CONFIG_IDE
+  devide_init();
+#endif
+#ifdef CONFIG_SD
+  devsd_init();
+#endif
+}
diff --git a/Kernel/platform-pentagon/devtty.c b/Kernel/platform-pentagon/devtty.c
new file mode 100644 (file)
index 0000000..61003df
--- /dev/null
@@ -0,0 +1,149 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <devtty.h>
+#include <keycode.h>
+#include <vt.h>
+#include <tty.h>
+#include <graphics.h>
+#include <input.h>
+#include <devinput.h>
+
+static char tbuf1[TTYSIZ];
+
+uint8_t vtattr_cap = VTA_INVERSE|VTA_FLASH|VTA_UNDERLINE;
+uint8_t vtborder;
+uint8_t curattr = 7;
+
+static tcflag_t console_mask[4] = {
+       _ISYS,
+       _OSYS,
+       _CSYS,
+       _LSYS
+};
+
+tcflag_t *termios_mask[NUM_DEV_TTY + 1] = {
+       NULL,
+       console_mask
+};
+
+
+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},
+};
+
+/* tty1 is the screen */
+
+/* Output for the system console (kprintf etc) */
+void kputchar(char c)
+{
+       if (c == '\n')
+               tty_putc(0, '\r');
+       tty_putc(0, c);
+}
+
+/* Both console and debug port are always ready */
+ttyready_t tty_writeready(uint8_t minor)
+{
+       minor;
+       return TTY_READY_NOW;
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+       minor;
+       vtoutput(&c, 1);
+}
+
+int tty_carrier(uint8_t minor)
+{
+       minor;
+       return 1;
+}
+
+void tty_setup(uint8_t minor, uint8_t flags)
+{
+       minor;
+}
+
+void tty_sleeping(uint8_t minor)
+{
+       minor;
+}
+
+void tty_data_consumed(uint8_t minor)
+{
+}
+
+
+/* This is used by the vt asm code, but needs to live in the kernel */
+uint16_t cursorpos;
+
+static struct display specdisplay = {
+       0,
+       256, 192,
+       256, 192,
+       0xFF, 0xFF,
+       FMT_SPECTRUM,
+       HW_UNACCEL,
+       GFX_VBLANK|GFX_MAPPABLE|GFX_TEXT,
+       0
+};
+
+static struct videomap specmap = {
+       0,
+       0,
+       0x4000,
+       6912,
+       0,
+       0,
+       0,
+       MAP_FBMEM|MAP_FBMEM_SIMPLE
+};
+
+/*
+ *     Graphics ioctls. Very minimal for this platform. It's a single fixed
+ *     mode with direct memory mapping.
+ */
+int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr)
+{
+       if (minor != 1 || arg >> 8 != 0x03)
+               return vt_ioctl(minor, arg, ptr);
+       switch(arg) {
+       case GFXIOC_GETINFO:
+               return uput(&specdisplay, ptr, sizeof(struct display));
+       case GFXIOC_MAP:
+               return uput(&specmap, ptr, sizeof(struct videomap));
+       case GFXIOC_UNMAP:
+               return 0;
+       case GFXIOC_WAITVB:
+               /* Our system clock is vblank */
+               timer_wait++;
+               psleep(&timer_interrupt);
+               timer_wait--;
+               chksigs();
+               if (udata.u_cursig) {
+                       udata.u_error = EINTR;
+                       return -1;
+               }
+               return 0;
+       }
+       return -1;
+}
+
+void vtattr_notify(void)
+{
+       /* Attribute byte fixups: not hard as the colours map directly
+          to the spectrum ones */
+       if (vtattr & VTA_INVERSE)
+               curattr =  ((vtink & 7) << 3) | (vtpaper & 7);
+       else
+               curattr = (vtink & 7) | ((vtpaper & 7) << 3);
+       if (vtattr & VTA_FLASH)
+               curattr |= 0x80;
+       /* How to map the bright bit - we go by either */
+       if ((vtink | vtpaper) & 0x10)
+               curattr |= 0x40;
+}
diff --git a/Kernel/platform-pentagon/devtty.h b/Kernel/platform-pentagon/devtty.h
new file mode 100644 (file)
index 0000000..40a67f5
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+void tty_pollirq(void);
+static void keydecode(void);
+
+#define KEY_ROWS       8
+#define KEY_COLS       5
+extern uint8_t keymap[8];
+extern uint8_t keyboard[8][5];
+extern uint8_t shiftkeyboard[8][5];
+
+extern uint8_t timer_wait;
+
+extern int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr);
+
+extern uint8_t vtborder;
+
+#endif
diff --git a/Kernel/platform-pentagon/discard.c b/Kernel/platform-pentagon/discard.c
new file mode 100644 (file)
index 0000000..162a41e
--- /dev/null
@@ -0,0 +1,100 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <blkdev.h>
+
+extern uint8_t fuller, kempston, kmouse, kempston_mbmask;
+
+void pagemap_init(void)
+{
+       uint8_t i;
+       pagemap_add(3);
+       pagemap_add(4);
+
+       /* Pentagon uses 7FFD as follows
+               7: 256K
+               6: 128K
+               2: 64K
+               1: 32K
+               0: 16K
+               
+          The 1MB one uses bit 5 for 512K */
+       for (i = 8; i < 16; i++)
+               pagemap_add(0x40|i);
+       /* If we deal with Scorpion and friends then we have to use
+          1FFD bits 4-7 for the high bits instead */
+}
+
+/* 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, "kempston") == 0) {
+               kempston = 1;
+               return 1;
+       }
+       if (strcmp(p, "kmouse") == 0) {
+               kmouse = 1;
+               return 1;
+       }
+       if (strcmp(p, "fuller") == 0) {
+               fuller = 1;
+               return 1;
+       }
+       if (strcmp(p, "kmouse3") == 0) {
+               kmouse = 1;
+               kempston_mbmask = 7;
+               return 1;
+       }
+       if (strcmp(p, "kmturbo") == 0) {
+               /* For now rely on the turbo detect - may want to change this */
+               kmouse = 1;
+               return 1;
+       }
+       return 0;
+}
+
+/* Nothing to do for the map of init */
+void map_init(void)
+{
+}
+
+void platform_copyright(void)
+{
+}
+
+/*
+ *     This function is called for partitioned devices if a partition is found
+ *     and marked as swap type. The first one found will be used as swap. We
+ *     only support one swap device.
+ */
+void platform_swap_found(uint8_t letter, uint8_t m)
+{
+       blkdev_t *blk = blk_op.blkdev;
+       uint16_t n;
+       if (swap_dev != 0xFFFF)
+               return;
+       letter -= 'a';
+       kputs("(swap) ");
+       swap_dev = letter << 4 | m;
+       n = blk->lba_count[m - 1] / SWAP_SIZE;
+       if (n > MAX_SWAPS)
+               n = MAX_SWAPS;
+#ifdef SWAPDEV
+       while (n)
+               swapmap_init(n--);
+#endif
+}
diff --git a/Kernel/platform-pentagon/fuzix.lnk b/Kernel/platform-pentagon/fuzix.lnk
new file mode 100644 (file)
index 0000000..b7e5cfd
--- /dev/null
@@ -0,0 +1,54 @@
+-mwxuy
+-r
+-i fuzix.ihx
+-b _COMMONDATA=0x0100
+-b _CODE1=0xC000
+-b _CODE2=0xC000
+-b _FONT=0xC000
+-b _DISCARD=0x8400
+-l z80
+platform-pentagon/crt0.rel
+platform-pentagon/commonmem.rel
+platform-pentagon/pentagon.rel
+platform-pentagon/zxvideo.rel
+platform-pentagon/main.rel
+platform-pentagon/discard.rel
+start.rel
+version.rel
+lowlevel-z80-banked.rel
+usermem_std-z80-banked.rel
+platform-pentagon/tricks.rel
+timer.rel
+kdata.rel
+usermem.rel
+platform-pentagon/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_exec16.rel
+syscall_fs.rel
+syscall_fs2.rel
+syscall_fs3.rel
+syscall_proc.rel
+syscall_other.rel
+tty.rel
+vt.rel
+font8x8.rel
+mm.rel
+platform-pentagon/bankbig.rel
+swap.rel
+devsys.rel
+devinput.rel
+platform-pentagon/devtty.rel
+platform-pentagon/devide.rel
+platform-pentagon/devide_discard.rel
+platform-pentagon/devsd.rel
+platform-pentagon/devsd_discard.rel
+platform-pentagon/divide.rel
+platform-pentagon/zxmmc.rel
+platform-pentagon/mbr.rel
+platform-pentagon/blkdev.rel
+platform-pentagon/devinput.rel
+platform-pentagon/zxkeyboard.rel
+-e
diff --git a/Kernel/platform-pentagon/kernel.def b/Kernel/platform-pentagon/kernel.def
new file mode 100644 (file)
index 0000000..9e311b8
--- /dev/null
@@ -0,0 +1,17 @@
+; UZI mnemonics for memory addresses etc
+
+; We stick it straight after the tag
+U_DATA                      .equ 0x100       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           .equ 0x200        ; 256+256+256 bytes.
+
+U_DATA_STASH               .equ 0xFE00       ; FE00-FFFF
+
+Z80_TYPE                   .equ 1
+
+PROGBASE                   .equ 0x8000
+PROGLOAD                   .equ 0x8000
+
+NBUFS                      .equ 5
+
+BANK_BITS                  .equ 0x10           ; Spectrum ROM select
+                                               ; Doesn't really matter!
\ No newline at end of file
diff --git a/Kernel/platform-pentagon/loader.s b/Kernel/platform-pentagon/loader.s
new file mode 100644 (file)
index 0000000..c991027
--- /dev/null
@@ -0,0 +1,31 @@
+;
+;      Most of the work was done by the BASIC loader. At this point in
+;      time banks 0 6 and 7 are correct, whilst banks 3 and 4 hold the
+;      other stuff we need
+;
+
+               .module loader
+               .area CODE(ABS)
+               .org 0x6000
+
+start:
+               di
+               ; Turn off low ROM
+               ; Some older systems want 0x1FFD bit 0 instead FIXME
+               ld bc,#0xeff7
+               ld a,#0x08
+               out (c),a
+               ; The kernel is loaded into 1,6,7
+               ; The low memory is loaded into bank 3
+               ; The 8000-BFFF range is loaded by the loader
+               ; The 4000-7FFF range is zero
+               ld a,#0x03
+               out (c),a
+               ld hl,#0xc000
+               ld de,#0x0000
+               ld bc,#0x4000
+               ldir
+               ld a,#0x01
+               out (c),a
+               ; FIXME - where is best to start up
+               jp 0xC000
diff --git a/Kernel/platform-pentagon/main.c b/Kernel/platform-pentagon/main.c
new file mode 100644 (file)
index 0000000..8b9869a
--- /dev/null
@@ -0,0 +1,82 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <devinput.h>
+
+uint16_t ramtop = PROGTOP;
+uint16_t swap_dev = 0xFFFF;
+
+/* On idle we spin checking for the terminals. Gives us more responsiveness
+   for the polled ports */
+void platform_idle(void)
+{
+  /* We don't want an idle poll and IRQ driven tty poll at the same moment */
+  __asm
+   halt
+  __endasm;
+}
+
+uint8_t timer_wait;
+
+void platform_interrupt(void)
+{
+ tty_pollirq();
+ timer_interrupt();
+ poll_input();
+ if (timer_wait)
+  wakeup(&timer_interrupt);
+}
+
+/*
+ *     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;
+}
+
+/* This points to the last buffer in the disk buffers. There must be at least
+   four buffers to avoid deadlocks. */
+struct blkbuf *bufpool_end = bufpool + NBUFS;
+
+/*
+ *     We pack discard into the memory image is if it were just normal
+ *     code but place it at the end after the buffers. When we finish up
+ *     booting we turn everything from the buffer pool to the start of
+ *     user space into buffers.
+ *
+ *     We don't touch discard. Discard is just turned into user space.
+ */
+void platform_discard(void)
+{
+       uint16_t discard_size = 0x4000 - (uint16_t)bufpool_end;
+       bufptr bp = bufpool_end;
+
+       discard_size /= sizeof(struct blkbuf);
+
+       kprintf("%d buffers added\n", discard_size);
+
+       bufpool_end += discard_size;
+
+       memset( bp, 0, discard_size * sizeof(struct blkbuf) );
+
+       for( bp = bufpool + NBUFS; bp < bufpool_end; ++bp ){
+               bp->bf_dev = NO_DEVICE;
+               bp->bf_busy = BF_FREE;
+       }
+}
+
+#ifndef SWAPDEV
+/* Adding dummy swapper since it is referenced by tricks.s */
+void swapper(ptptr p)
+{
+  p;
+}
+#endif
diff --git a/Kernel/platform-pentagon/pentagon.s b/Kernel/platform-pentagon/pentagon.s
new file mode 100644 (file)
index 0000000..c7e618f
--- /dev/null
@@ -0,0 +1,453 @@
+;
+;    Pentagon hardware support
+;
+
+        .module pentagon
+
+        ; exported symbols
+        .globl init_early
+        .globl init_hardware
+        .globl _program_vectors
+        .globl platform_interrupt_all
+       .globl interrupt_handler
+       .globl unix_syscall_entry
+       .globl null_handler
+
+        .globl map_kernel
+        .globl map_process_always
+        .globl map_process
+        .globl map_kernel_di
+        .globl map_process_always_di
+        .globl map_save_kernel
+        .globl map_restore
+       .globl map_process_save
+       .globl map_kernel_restore
+       .globl map_for_swap
+       .globl current_map
+       .globl switch_bank
+
+        .globl _need_resched
+       .globl _int_disabled
+
+        ; exported debugging tools
+        .globl _platform_monitor
+       .globl _platform_reboot
+        .globl outchar
+
+        ; imported symbols
+        .globl _ramsize
+        .globl _procmem
+
+       .globl _vtoutput
+       .globl _vtinit
+
+        .globl outcharhex
+        .globl outhl, outde, outbc
+        .globl outnewline
+        .globl outstring
+        .globl outstringhex
+
+       ; banking support
+       .globl __bank_0_1
+       .globl __bank_0_2
+       .globl __bank_0_3
+       .globl __bank_1_2
+       .globl __bank_1_3
+       .globl __bank_2_1
+       .globl __bank_2_3
+       .globl __bank_3_1
+       .globl __bank_3_2
+
+       .globl __stub_0_1
+       .globl __stub_0_2
+       .globl __stub_0_3
+       .globl __stub_1_2
+       .globl __stub_1_3
+       .globl __stub_2_1
+       .globl __stub_2_3
+       .globl __stub_3_1
+       .globl __stub_3_2
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (below 0xC000)
+; -----------------------------------------------------------------------------
+        .area _COMMONMEM
+
+_platform_monitor:
+       ;
+       ;       Not so much a monitor as wait for space
+       ;
+       ld a, #0x7F
+       in a, (0xFE)
+       rra
+       jr c, _platform_monitor
+
+_platform_reboot:
+       di
+       im 1
+       ld bc, #0x7ffd
+       xor a           ; 128K ROM, initial banks, low screen
+       out (c), a
+        rst 0          ; Into the ROM
+
+platform_interrupt_all:
+        ret
+
+       .area _COMMONDATA
+
+_int_disabled:
+       .db 1
+
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (above 0xC000, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+        .area _CODE1
+
+;
+;      The memory banker will deal with the map setting
+;
+init_early:
+        ret
+
+       .area _VIDEO
+
+init_hardware:
+        ; set system RAM size
+       ; FIXME: probe this and map accordingly in discard.c
+        ld hl, #256
+        ld (_ramsize), hl
+       ; We lose the following to the system
+       ; 0: low 16K of kernel
+       ; 1: first kernel bank at C000
+       ; 2: 4000-7FFF (screen and buffers)
+       ; 5: 8000-BFFF (working 16K copy)
+       ; 6: second kernel bank at C000
+       ; 7: third kernel bank at C000
+       ;
+       ; We might be able to squash things up and get 6 or 7 back
+       ; but as we work in pairs it's not actually that interesting. OTOH
+       ; getting 6000-7FFF back might be for program sizes.
+       ;
+        ld hl, #(256 - 96)
+        ld (_procmem), hl
+
+        ; screen initialization
+       push af
+       call _vtinit
+       pop af
+
+        ret
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+        .area _COMMONMEM
+
+_program_vectors:
+       ret
+
+       ; Swap helper. Map the page in A into the address space such
+       ; that swap_map() gave the correct pointer to use. Undone by
+       ; a map_kernel_{restore}
+map_for_swap:
+        ; bank switching procedure. On entrance:
+        ;  A - bank number to set
+       push af
+       ld a, (current_map)
+       ld (ksave_map), a
+       pop af
+       ; Then fall through to set the bank up
+
+switch_bank:
+       ; Write the store first, that way any interrupt will restore
+       ; the new bank and our out will just be a no-op
+        ld (current_map), a
+       push bc
+        ld bc, #0x7ffd
+       or #BANK_BITS      ; Spectrum 48K ROM, Screen in Bank 7
+        out (c), a
+       pop bc
+        ret
+
+
+map_process:
+        ld a, h
+        or l
+        jr z, map_kernel_nosavea
+       push af
+        ld a, (hl)
+       call switch_bank
+       pop af
+       ret
+
+;
+;      We always save here so that existing code works until we have a
+;      clear usage of save/restore forms across the kernel
+;
+map_process_save:
+map_process_always:
+map_process_always_di:
+       push af
+       ld a, (current_map)
+       ld (ksave_map), a
+        ld a, (U_DATA__U_PAGE)
+       call switch_bank
+       pop af
+       ret
+
+;
+;      Save and switch to kernel
+;
+map_save_kernel:
+       push af
+        ld a, (current_map)
+        ld (map_store), a
+       pop af
+;
+;      This may look odd. However the kernel is banked so any
+;      invocation of kernel code in fact runs common code and the
+;      common code will bank in the right kernel bits for us when it calls
+;      out of common into banked code. We do a restore to handle all the
+;      callers who do map_process_always/map_kernel pairs. Probably we
+;      should have some global change to map_process_save/map_kernel_restore
+;
+map_kernel_di:
+map_kernel:
+map_kernel_nosavea:          ; to avoid double reg A saving
+map_kernel_restore:
+       push af
+       ld a, (ksave_map)
+       call switch_bank
+       pop af
+       ret
+
+
+map_restore:
+       push af
+        ld a, (map_store)
+        call switch_bank
+       pop af
+       ret
+
+;
+;      We have no easy serial debug output instead just breakpoint this
+;      address when debugging.
+;
+outchar:
+       ld (_tmpout), a
+       push bc
+       push de
+       push hl
+       push ix
+       ld hl, #1
+       push hl
+       ld hl, #_tmpout
+       push hl
+       push af
+       call _vtoutput
+       pop af
+       pop af
+       pop af
+       pop ix
+       pop hl
+       pop de
+       pop bc
+        ret
+
+_tmpout:
+       .db 1
+
+current_map:                ; place to store current page number. Is needed
+        .db 0               ; because we have no ability to read 7ffd port
+                            ; to detect what page is mapped currently 
+map_store:
+        .db 0
+
+ksave_map:
+        .db 0
+
+_need_resched:
+        .db 0
+
+;
+;      Banking helpers
+;
+;      Logical         Physical
+;      0               COMMON (0x4000)
+;      1               0
+;      2               1
+;      3               7
+;
+;
+__bank_0_1:
+       ld a,#1            ; switch to physical bank 1 (logical 1)
+bankina0:
+       ;
+       ;       Get the target address first, otherwise we will change
+       ;       bank and read it from the wrong spot!
+       ;
+       pop hl             ; Return address (points to true function address)
+       ld e, (hl)         ; DE = function to call
+       inc hl
+       ld d, (hl)
+       inc hl
+       push hl            ; Restore corrected return pointer
+       ld bc, (current_map)    ; get current bank into B
+       call switch_bank   ; Move to new bank
+       ; figure out which bank to map on the return path
+       ld a, c
+       dec a
+       jr z, __retmap1
+       cp #5
+       jr z, __retmap2
+       jr __retmap3
+
+callhl:        jp (hl)
+__bank_0_2:
+       ld a, #6           ; logical 2 -> physical 6
+       jr bankina0
+__bank_0_3:
+       ld a, #7           ; logical 3 -> physical 7
+       jr bankina0
+
+__bank_1_2:
+       ld a, #1
+bankina1:
+       pop hl             ; Return address (points to true function address)
+       ld e, (hl)         ; DE = function to call
+       inc hl
+       ld d, (hl)
+       inc hl
+       push hl            ; Restore corrected return pointer
+       call switch_bank   ; Move to new bank
+__retmap1:
+       ex de, hl
+       call callhl        ; call the function
+       ld a,#1            ; return to bank 1 (physical 0)
+       jp switch_bank
+
+__bank_1_3:
+       ld a, #7
+       jr bankina1
+__bank_2_1:
+       ld a,#1
+bankina2:
+       pop hl             ; Return address (points to true function address)
+       ld e, (hl)         ; DE = function to call
+       inc hl
+       ld d, (hl)
+       inc hl
+       push hl            ; Restore corrected return pointer
+       call switch_bank   ; Move to new bank
+__retmap2:
+       ex de, hl
+       call callhl        ; call the function
+       ld a, #6           ; return to bank 2
+       jp switch_bank
+__bank_2_3:
+       ld a, #7
+       jr bankina2
+__bank_3_1:
+       ld a, #1
+bankina3:
+       pop hl             ; Return address (points to true function address)
+       ld e, (hl)         ; DE = function to call
+       inc hl
+       ld d, (hl)
+       inc hl
+       push hl            ; Restore corrected return pointer
+       call switch_bank   ; Move to new bank
+__retmap3:
+       ex de, hl
+       call callhl        ; call the function
+       ld a, #7           ; return to bank 0
+       jp switch_bank
+
+__bank_3_2:
+       ld a, #1
+       jr bankina3
+
+;
+;      Stubs need some stack munging and use DE
+;
+
+__stub_0_1:
+       ld a,#1
+__stub_0_a:
+       pop hl          ; the return
+       ex (sp), hl     ; write it over the discard
+       ld bc, (current_map)
+       call switch_bank
+       ld a, c
+       dec a
+       jr z, __stub_1_ret
+       cp #5           ; bank 6
+       jr z, __stub_2_ret
+       jr __stub_3_ret ; bank 7
+__stub_0_2:
+       ld a, #6
+       jr __stub_0_a
+__stub_0_3:
+       ld a, #7
+       jr __stub_0_a
+
+__stub_1_2:
+       ld a, #6
+__stub_1_a:
+       pop hl          ; the return
+       ex (sp), hl     ; write it over the discad
+       call switch_bank
+__stub_1_ret:
+       ex de, hl
+       call callhl
+       ld a,#1
+       call switch_bank
+       pop de
+       push de         ; dummy the caller will discard
+       push de         ; FIXME don't we need to use BC and can't we get
+       ret             ; rid of all non 0_x stubs ?
+__stub_1_3:
+       ld a, #7
+       jr __stub_1_a
+
+__stub_2_1:
+       ld a,#1
+__stub_2_a:
+       pop hl          ; the return
+       ex (sp), hl     ; write it over the discad
+       call switch_bank
+__stub_2_ret:
+       ex de, hl       ; DE is our target
+       call callhl
+       ld a,#6
+       call switch_bank
+       pop de
+       push de         ; dummy the caller will discard
+       push de
+       ret
+__stub_2_3:
+       ld a, #7
+       jr __stub_2_a
+
+__stub_3_1:
+       ld a,#1
+__stub_3_a:
+       pop hl          ; the return
+       ex (sp), hl     ; write it over the discad
+       call switch_bank
+__stub_3_ret:
+       ex de, hl
+       call callhl
+       ld a,#7
+       call switch_bank
+       pop de
+       push de         ; dummy the caller will discard
+       push de
+       ret
+__stub_3_2:
+       ld a, #6
+       jr __stub_3_a
diff --git a/Kernel/platform-pentagon/platform_ide.h b/Kernel/platform-pentagon/platform_ide.h
new file mode 100644 (file)
index 0000000..2141fda
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ *     DivIDE interface
+ *
+ *     This is a 16bit interface with a latched data port. Each read
+ *     from A3 fetches a word then returns low then high etc. In the other
+ *     direction it latches then writes.
+ *
+ *     The latch is reset to the first state by any other port access in the
+ *     IDE space (so the command write sets it up nicely for us)
+ */
+
+#define ide_select(x)
+#define ide_deselect()
+
+#define IDE_DRIVE_COUNT        2
+
+#define IDE_REG_DATA           0xA3
+#define IDE_REG_ERROR          0xA7
+#define IDE_REG_FEATURES       0xA7
+#define IDE_REG_SEC_COUNT      0xAB
+#define IDE_REG_LBA_0          0xAF
+#define IDE_REG_LBA_1          0xB3
+#define IDE_REG_LBA_2          0xB7
+#define IDE_REG_LBA_3          0xBB
+#define IDE_REG_DEVHEAD                0xBB
+#define IDE_REG_STATUS         0xBF
+#define IDE_REG_COMMAND                0xBF
+
+#define IDE_NONSTANDARD_XFER
diff --git a/Kernel/platform-pentagon/rules.mk b/Kernel/platform-pentagon/rules.mk
new file mode 100644 (file)
index 0000000..58567b3
--- /dev/null
@@ -0,0 +1,17 @@
+#
+#      ZX128 uses banked kernel images
+#
+CROSS_CCOPTS += --external-banker
+#
+# Tell the core code we are using the banked helpers
+#
+export BANKED=-banked
+#
+export CROSS_CC_SEG1=--codeseg CODE2
+export CROSS_CC_SEG3=--codeseg CODE1
+export CROSS_CC_SEG4=--codeseg CODE1
+export CROSS_CC_SYS1=--codeseg CODE1
+export CROSS_CC_SYS2=--codeseg CODE1
+export CROSS_CC_SYS3=--codeseg CODE1
+export CROSS_CC_SYS4=--codeseg CODE3
+export CROSS_CC_SYS5=--codeseg CODE3
diff --git a/Kernel/platform-pentagon/target.mk b/Kernel/platform-pentagon/target.mk
new file mode 100644 (file)
index 0000000..3bffcde
--- /dev/null
@@ -0,0 +1 @@
+export CPU = z80
diff --git a/Kernel/platform-pentagon/tricks.s b/Kernel/platform-pentagon/tricks.s
new file mode 100644 (file)
index 0000000..024f078
--- /dev/null
@@ -0,0 +1,2 @@
+
+       .include "../dev/zx/tricks-big.s"
diff --git a/Kernel/platform-pentagon/zxvideo.s b/Kernel/platform-pentagon/zxvideo.s
new file mode 100644 (file)
index 0000000..950cb76
--- /dev/null
@@ -0,0 +1,28 @@
+;
+;        zx128 vt primitives
+;
+
+        .module zxvideo
+
+        ; exported symbols
+        .globl _plot_char
+        .globl _scroll_down
+        .globl _scroll_up
+        .globl _cursor_on
+        .globl _cursor_off
+       .globl _cursor_disable
+        .globl _clear_lines
+        .globl _clear_across
+        .globl _do_beep
+       .globl _fontdata_8x8
+       .globl _curattr
+       .globl _vtattr
+
+       ; Build the video library as the only driver
+
+ZXVID_ONLY     .equ    1
+
+        .area _VIDEO
+
+       .include "../dev/zx/video-banked.s"
+