From b9a209c0c0fdec34c2dde0efc151490fb7e251ce Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 8 Feb 2019 23:03:45 +0000 Subject: [PATCH] pentagon: first draft at a port There is lots to do here including writing some bootstrap code so we can actually test it --- Kernel/platform-pentagon/Makefile | 52 +++ Kernel/platform-pentagon/README | 93 +++++ Kernel/platform-pentagon/commonmem.s | 8 + Kernel/platform-pentagon/config.h | 74 ++++ Kernel/platform-pentagon/crt0.s | 114 ++++++ Kernel/platform-pentagon/devices.c | 45 +++ Kernel/platform-pentagon/devtty.c | 149 ++++++++ Kernel/platform-pentagon/devtty.h | 19 + Kernel/platform-pentagon/discard.c | 100 ++++++ Kernel/platform-pentagon/fuzix.lnk | 54 +++ Kernel/platform-pentagon/kernel.def | 17 + Kernel/platform-pentagon/loader.s | 31 ++ Kernel/platform-pentagon/main.c | 82 +++++ Kernel/platform-pentagon/pentagon.s | 453 ++++++++++++++++++++++++ Kernel/platform-pentagon/platform_ide.h | 29 ++ Kernel/platform-pentagon/rules.mk | 17 + Kernel/platform-pentagon/target.mk | 1 + Kernel/platform-pentagon/tricks.s | 2 + Kernel/platform-pentagon/zxvideo.s | 28 ++ 19 files changed, 1368 insertions(+) create mode 100644 Kernel/platform-pentagon/Makefile create mode 100644 Kernel/platform-pentagon/README create mode 100644 Kernel/platform-pentagon/commonmem.s create mode 100644 Kernel/platform-pentagon/config.h create mode 100644 Kernel/platform-pentagon/crt0.s create mode 100644 Kernel/platform-pentagon/devices.c create mode 100644 Kernel/platform-pentagon/devtty.c create mode 100644 Kernel/platform-pentagon/devtty.h create mode 100644 Kernel/platform-pentagon/discard.c create mode 100644 Kernel/platform-pentagon/fuzix.lnk create mode 100644 Kernel/platform-pentagon/kernel.def create mode 100644 Kernel/platform-pentagon/loader.s create mode 100644 Kernel/platform-pentagon/main.c create mode 100644 Kernel/platform-pentagon/pentagon.s create mode 100644 Kernel/platform-pentagon/platform_ide.h create mode 100644 Kernel/platform-pentagon/rules.mk create mode 100644 Kernel/platform-pentagon/target.mk create mode 100644 Kernel/platform-pentagon/tricks.s create mode 100644 Kernel/platform-pentagon/zxvideo.s diff --git a/Kernel/platform-pentagon/Makefile b/Kernel/platform-pentagon/Makefile new file mode 100644 index 00000000..69647690 --- /dev/null +++ b/Kernel/platform-pentagon/Makefile @@ -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 index 00000000..1ed6be8c --- /dev/null +++ b/Kernel/platform-pentagon/README @@ -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 index 00000000..dc31c24e --- /dev/null +++ b/Kernel/platform-pentagon/commonmem.s @@ -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 index 00000000..9c15e3b0 --- /dev/null +++ b/Kernel/platform-pentagon/config.h @@ -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 index 00000000..2de325be --- /dev/null +++ b/Kernel/platform-pentagon/crt0.s @@ -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 index 00000000..90c608d1 --- /dev/null +++ b/Kernel/platform-pentagon/devices.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 index 00000000..61003df9 --- /dev/null +++ b/Kernel/platform-pentagon/devtty.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 index 00000000..40a67f5c --- /dev/null +++ b/Kernel/platform-pentagon/devtty.h @@ -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 index 00000000..162a41ef --- /dev/null +++ b/Kernel/platform-pentagon/discard.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include + +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 + * 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 index 00000000..b7e5cfd2 --- /dev/null +++ b/Kernel/platform-pentagon/fuzix.lnk @@ -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 index 00000000..9e311b86 --- /dev/null +++ b/Kernel/platform-pentagon/kernel.def @@ -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 index 00000000..c991027e --- /dev/null +++ b/Kernel/platform-pentagon/loader.s @@ -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 index 00000000..8b9869a3 --- /dev/null +++ b/Kernel/platform-pentagon/main.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include + +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 index 00000000..c7e618f6 --- /dev/null +++ b/Kernel/platform-pentagon/pentagon.s @@ -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 index 00000000..2141fda7 --- /dev/null +++ b/Kernel/platform-pentagon/platform_ide.h @@ -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 index 00000000..58567b35 --- /dev/null +++ b/Kernel/platform-pentagon/rules.mk @@ -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 index 00000000..3bffcde0 --- /dev/null +++ b/Kernel/platform-pentagon/target.mk @@ -0,0 +1 @@ +export CPU = z80 diff --git a/Kernel/platform-pentagon/tricks.s b/Kernel/platform-pentagon/tricks.s new file mode 100644 index 00000000..024f078f --- /dev/null +++ b/Kernel/platform-pentagon/tricks.s @@ -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 index 00000000..950cb76c --- /dev/null +++ b/Kernel/platform-pentagon/zxvideo.s @@ -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" + -- 2.34.1