From: Alan Cox Date: Fri, 11 Jan 2019 00:45:57 +0000 (+0000) Subject: zx evolution: initial port sketch X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=3dc0d85792cb0b04aa767c9ee48c8f42dc63920d;p=FUZIX.git zx evolution: initial port sketch Whilst quite different to tbblue in some ways it's useful to be thinking about both at the same time. This is for baseconf. tsconf might be even more interesting ? --- diff --git a/Kernel/platform-zxevo/Makefile b/Kernel/platform-zxevo/Makefile new file mode 100644 index 00000000..ad855d31 --- /dev/null +++ b/Kernel/platform-zxevo/Makefile @@ -0,0 +1,63 @@ +ASRCS = crt0.s zxevo.s video.s +ASRCS += tricks.s commonmem.s +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/evommc.c ../dev/zx/zxkeyboard.c ../dev/zx/devinput.c +DDZSRCS = +NSRCS = ../dev/net/net_native.c + +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)) +NOBJS = $(patsubst ../dev/net/%.c,%.rel, $(NSRCS)) + +OBJS = $(COBJS) $(CDOBJS) $(AOBJS) $(DOBJS) $(DDOBJS) $(DZOBJS) $(DDZOBJS) $(NOBJS) + +CROSS_CCOPTS += -I../dev/ -I../dev/zx/ -I../dev/net/ + +all: $(OBJS) + +$(COBJS): %.rel: %.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(CDOBJS): %.rel: %.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(DOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(DDOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(DZOBJS): %.rel: ../dev/zx/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(DDZOBJS): %.rel: ../dev/zx/%.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(NOBJS): %.rel: ../dev/net/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(AOBJS): %.rel: %.s + $(CROSS_AS) $(ASOPTS) $< + +clean: + rm -f $(OBJS) *.lst *.asm *.sym *.rst *.rel core *~ + rm -f FUZIX FUZIX.BIN load-esx.ihx load-esx.tmp + +image: + # Build an esxdos friendly setup + sdasz80 -o load-esx.s + sdldz80 -i load-esx.rel + makebin -s 8704 load-esx.ihx load-esx.tmp + # Generate the image file we need + dd if=load-esx.tmp of=FUZIX bs=8192 skip=1 + + dd if=/dev/zero bs=256 count=1 >FUZIX.BIN + cat ../fuzix.bin >>FUZIX.BIN diff --git a/Kernel/platform-zxevo/README b/Kernel/platform-zxevo/README new file mode 100644 index 00000000..2c8d6b44 --- /dev/null +++ b/Kernel/platform-zxevo/README @@ -0,0 +1,53 @@ +First draft only + +ZX Evolution (baseconf) + +I/O Mapping + +The ZX Evolution has two oddities here. Firstly it inherits a lot of the +ZX Spectrum 16bit wide port decode hacks. Secondly it has a shadow and non +shadow mode and some ports are present only in one mode. + +- Implementation rule for Fuzix, you must have DI on for shadow mode. Also + standard sys functions may turn shadow off if used (notably mapping) + +Memory + +512K ROM, 4MB RAM. + + +Memory Map: + +0000-BFFF: Kernel +C000-FFFF: Kernel/Common (we stick to 48K apps to get a bigger kernel) + +0000-BFFF: User +C000-FFFF: Kernel/Common + +We will need to push disk buffers into their own bank and we have banks for +video as well. But we have 4MB so who cares. Reworking the port for bigger +user apps can occur later + +More interesting question: would we be better off using bankfixed or thunked ? + + +TODO +- Figure out how the boot logic works +- Write a boot loader +- Correct the set up code to set turbo and video etc right +- Look at the other bits of port BF and how to use without getting in a mess +- xx77 is even worse +- Go through and sort out shadow v non shadow +- Set up the IDE and SD ports and code +- Add external buffer support to devsd +- External buffers +- Graphics modes setting and mapping +- UDG and font loads +- Floppy driver including adding external buffer support +- RTC +- PS/2 config and keyboard control ? +- What to do with all that RAM ? +- Video mapping into user space - do we support a top at 0x7FFF and direct + video map choice ? +- Longer term look at memory options - thunked might be worth it to get big + user processes diff --git a/Kernel/platform-zxevo/commonmem.s b/Kernel/platform-zxevo/commonmem.s new file mode 100644 index 00000000..dc31c24e --- /dev/null +++ b/Kernel/platform-zxevo/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-zxevo/config.h b/Kernel/platform-zxevo/config.h new file mode 100644 index 00000000..3841149e --- /dev/null +++ b/Kernel/platform-zxevo/config.h @@ -0,0 +1,115 @@ +/* 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 + +/* Select a banked memory set up */ +#define CONFIG_BANK16 /* 16K pages */ +#define MAX_MAPS 255 /* 4MB FIXME cut this down by reserved pages */ +/* How many banks do we have in our address space */ +#define CONFIG_BANKS 4 /* 8 x 8K will fix when do paging */ + +/* 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 +/* Vt definitions */ +#define VT_WIDTH 64 +#define VT_HEIGHT 24 +#define VT_RIGHT 63 +#define VT_BOTTOM 23 + + +/* + * Define the program loading area (needs to match kernel.def) + */ +#define PROGBASE 0x0000 /* Base of user */ +#define PROGLOAD 0x0100 /* Load and run here */ +#define PROGTOP 0xC000 /* Top of program, base of U_DATA */ +#define PROC_SIZE 48 /* Memory needed per process */ + +/* + * Definitions for swapping - we don't need swap! + */ + +/* What is the maximum number of /dev/hd devices we have. In theory right now + it's actually 3 - the two HD and the SD interface */ +#define MAX_BLKDEV 3 +/* SD card, single card only */ +#define CONFIG_SD +#define SD_DRIVE_COUNT 1 +#define CONFIG_IDE + +#define BOOTDEVICENAMES "hd#" + +/* We will resize the buffers available after boot. This is the normal setting */ +#define CONFIG_DYNAMIC_BUFPOOL +/* Larger transfers (including process execution) should go directly not via + the buffer cache. For all small (eg bit) systems this is the right setting + as it avoids polluting the small cache with data when it needs to be full + of directory and inode information */ +#define CONFIG_LARGE_IO_DIRECT(x) 1 + +/* Specify this if there is a real time clock capable of reporting seconds. It + will be used to lock the kernel time better to reality. Other details like + Y2K support, or even supporting dates as well don't matter */ + /* FIXME: there is one but its weird! */ +#undef CONFIG_RTC +/* Specify that there is a full real time clock that can supply the date and + time to the system. */ +#undef CONFIG_RTC_FULL + +/* + * How fast does the clock tick (if present), or how many times a second do + * we simulate if not. For a machine without video 10 is a good number. If + * you have video you probably want whatever vertical sync/blank interrupt + * rate the machine has. For many systems it's whatever the hardware gives + * you. + * + * Note that this needs to be divisible by 10 and at least 10. If your clock + * is a bit slower you may need to fudge things somewhat so that the kernel + * gets 10 timer interrupt calls per second. + */ +#define TICKSPERSEC 50 /* Ticks per second */ + +/* Core networking support */ +#define CONFIG_NET +/* Or native (eg SLIP) */ +#define CONFIG_NET_NATIVE + +/* + * The device (major/minor) for the console and boot up tty attached to + * init at start up. 512 is the major 2, so all the tty devices are + * 512 + n where n is the tty. + */ +#define BOOT_TTY (512 + 1) /* Set this to default device for stdio, stderr */ + /* In this case, the default is the first TTY device */ +/* + * If you have a mechanism to pass in a root device configuration then + * this holds the address of the buffer (eg a CP/M command line or similar). + * If the configuration is fixed then this can be a string holding the + * configuration. NULL means 'prompt the user'. + */ +#define CMDLINE NULL /* Location of root dev name */ + +/* Device parameters */ +#define NUM_DEV_TTY 2 /* How many tty devices does the platform support */ +#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ +#define NBUFS 5 /* Number of block buffers. Must be 4+ and must match + kernel.def */ +#define NMOUNTS 4 /* Number of mounts at a time */ + +/* This can optionally be set to force a default baud rate, eg if the system + console should match a firmware set rate */ +#define TTY_INIT_BAUD B115200 /* Console is 'fast' */ diff --git a/Kernel/platform-zxevo/crt0.s b/Kernel/platform-zxevo/crt0.s new file mode 100644 index 00000000..a58fa8f6 --- /dev/null +++ b/Kernel/platform-zxevo/crt0.s @@ -0,0 +1,114 @@ + .module crt0 + + .area _CODE + .area _CODE2 + .area _CODE3 + .area _VIDEO + .area _INITIALIZED + .area _HOME + .area _CONST + + ; + ; 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 + .area _INITIALIZER + + .area _DISCARD + ; Somewhere to throw it out of the way + + + ; Our common is mapped high + .area _COMMONDATA + .area _COMMONMEM + .area _FONT + + + + ; 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" + + ; + ; startup code. Runs from 0x100. The kernel is mapped into pages + ; 16-23 and 16-22 are currently mapped. Stack is not valid on entry + ; and interrupts are off. + ; + + .area _CODE + + .globl _start + +_start: + ; Map in the top page (it couldn't be mapped by the loader as the + ; loader is living in it) + ld a,#0x57 ; MMU E000-FFFF + ld bc,#0x243B + out (c),a + ld a,#23 ; Top kernel page + inc b + out (c),a + + ; 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 + call init_early + + ; Hardware setup + call init_hardware + + ; Call the C main routine + call _fuzix_main + + ; main shouldn't return, but if it does... + di +stop: halt + jr stop + + .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-zxevo/devices.c b/Kernel/platform-zxevo/devices.c new file mode 100644 index 00000000..5ff35cbb --- /dev/null +++ b/Kernel/platform-zxevo/devices.c @@ -0,0 +1,46 @@ +#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 */ + /* FIXME: we need to add the fd eventually */ + { 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-zxevo/devtty.c b/Kernel/platform-zxevo/devtty.c new file mode 100644 index 00000000..a3447a22 --- /dev/null +++ b/Kernel/platform-zxevo/devtty.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char tbuf1[TTYSIZ]; +static char tbuf2[TTYSIZ]; + +uint8_t vtattr_cap = VTA_INVERSE|VTA_FLASH|VTA_UNDERLINE; +extern uint8_t curattr; + +static tcflag_t console_mask[4] = { + _ISYS, + _OSYS, + _CSYS, + _LSYS +}; + +static tcflag_t serial_mask[4] = { + _ISYS, + _OSYS, + CSIZE|CBAUD|CSTOPB|PARENB|PARODD|_CSYS, + _LSYS +}; + +tcflag_t *termios_mask[NUM_DEV_TTY + 1] = { + NULL, + console_mask, + serial_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}, + {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2}, +}; + +/* tty1 is the screen, tty2 is a 16x50 clone */ + +__sfr __banked __at 0xF8EF uart_rx; +__sfr __banked __at 0xF8EF uart_tx; +__sfr __banked __at 0xF8EF uart_ls; +__sfr __banked __at 0xF9EF uart_ier; +__sfr __banked __at 0xF9EF uart_ms; +__sfr __banked __at 0xFAEF uart_fcr; +__sfr __banked __at 0xFBEF uart_lcr; +__sfr __banked __at 0xFCEF uart_mcr; +__sfr __banked __at 0xFDEF uart_lsr; +__sfr __banked __at 0xFEEF uart_msr; +__sfr __banked __at 0xFFEF uart_scr; + + +/* Output for the system console (kprintf etc) */ +void kputchar(char c) +{ + if (c == '\n') + tty_putc(0, '\r'); + tty_putc(0, c); +} + +ttyready_t tty_writeready(uint8_t minor) +{ + if (minor == 1) + return TTY_READY_NOW; + if (uart_lsr & 0x20) + return TTY_READY_NOW; + return TTY_READY_SOON; +} + +void tty_putc(uint8_t minor, unsigned char c) +{ + if (minor == 1) + vtoutput(&c, 1); + else + uart_tx = c; +} + +void tty_polluart(void) +{ + uint8_t msr; + + while (uart_lsr & 0x01) + tty_inproc(2, uart_rx); + msr = uart_msr; + /* DCD changed - tell the kernel so it can hangup or open ports */ + if (msr & 0x08) { + if (msr & 0x80) + tty_carrier_raise(2); + else + tty_carrier_drop(2); + } + /* TODO: CTS/RTS */ +} + +int tty_carrier(uint8_t minor) +{ + if (minor == 2) + return uart_msr & 0x80; + return 1; +} + +/* + * 16x50 conversion betwen a Bxxxx speed rate (see tty.h) and the values + * to stuff into the chip. + * + * FIXME: update for this board + */ +static uint16_t clocks[] = { + 12, /* Not a real rate */ + 2304, + 1536, + 1047, + 857, + 768, + 384, + 192, + 96, + 48, + 24, + 12, + 6, + 3, + 2, + 1 +}; + +/* + * This function is called whenever the terminal interface is opened + * or the settings changed. It is responsible for making the requested + * changes to the port if possible. Strictly speaking it should write + * back anything that cannot be implemented to the state it selected. + * + * That needs tidying up in many platforms and we also need a proper way + * to say 'this port is fixed config' before making it so. + */ +void tty_setup(uint8_t minor, uint8_t flags) +{ + uint8_t d; + uint16_t w; + + if (minor == 1) + return; + + /* 16x50. Can actually be configured */ + d = 0x80; /* DLAB (so we can write the speed) */ + d |= (ttydata[2].termios.c_cflag & CSIZE) >> 4; + if(ttydata[2].termios.c_cflag & CSTOPB) + d |= 0x04; + if (ttydata[2].termios.c_cflag & PARENB) + d |= 0x08; + if (!(ttydata[2].termios.c_cflag & PARODD)) + d |= 0x10; + uart_lcr = d; + w = clocks[ttydata[2].termios.c_cflag & CBAUD]; + uart_ls = w; + uart_ms = w >> 8; + uart_lcr = d & 0x7F; + /* FIXME: CTS/RTS support */ + d = 0x03; /* DTR RTS */ + uart_mcr = d; + uart_ier = 0x0D; /* We don't use tx ints */ +} + +void tty_sleeping(uint8_t minor) +{ + used(minor); +} + +void tty_data_consumed(uint8_t minor) +{ + used(minor); +} + +/* This gfx stuff needs a major revisit for all the modes */ + +/* This is used by the vt asm code, but needs to live in the kernel */ +uint16_t cursorpos; + +/* For now we only support 64 char mode - we should add the mode setting + logic and other modes FIXME */ +static struct display specdisplay = { + 0, + 512, 192, + 512, 192, + 0xFF, 0xFF, + FMT_TIMEX64, + HW_UNACCEL, + GFX_VBLANK|GFX_MAPPABLE|GFX_TEXT, + 0 +}; + +/* + * Graphics ioctls. Not yet updated to reflect TBBlue at all + */ +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_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-zxevo/devtty.h b/Kernel/platform-zxevo/devtty.h new file mode 100644 index 00000000..a6355bcd --- /dev/null +++ b/Kernel/platform-zxevo/devtty.h @@ -0,0 +1,21 @@ +#ifndef __DEVTTY_DOT_H__ +#define __DEVTTY_DOT_H__ + +void tty_pollirq(void); +static void keydecode(void); + +extern void tty_polluart(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-zxevo/discard.c b/Kernel/platform-zxevo/discard.c new file mode 100644 index 00000000..98202235 --- /dev/null +++ b/Kernel/platform-zxevo/discard.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include + +extern uint8_t kempston, kmouse, kempston_mbmask; + +uint8_t platform_param(char *p) +{ + return 0; +} + +/* Nothing to do for the map of init */ +void map_init(void) +{ +} + +void pagemap_init(void) +{ + uint8_t i; + /* We have 256 pages 0-255 but we need to work with the complement */ + /* In addition certain pages are magic + 5 / 2 / 0 are the classic spectrum pages + 0-7 are the 128K spectrum pages + then above that the compat ones for Pentagon etc + + This effectively means we need to consider special: + page 5/7 for the Spectrum video modes + page 4/6 for 256x192 16 colour + page 1/5 for 640x200 and 320x200 mode + page 1/3/5/7 for ATM text mode without it being packed + In one page mode it ends up in page 8 or 10 ! + + So we do + 0 / 1 / 2 / 3 Kernel + 4-8 Video + 9 Buffers (eventually) + 10 Video alt + 11 Init + + We could in theory reduce it a bit by shuffling the buffers + around on a video change + + We have 4MB, we actually can't use even 1MB with 16 processes! + + Might want to move the kernel a bit so we can run a ZX spectrum + as a process ? + + */ + for (i = 12; i < 255; i++) { + pagemap_add(~i); + i++; + } + /* Common for init */ + pagemap_add(~10); +} + +void platform_copyright(void) +{ + /* We always have the kempston interfaces present */ + kempston = 1; + kmouse = 1; + kempston_mbmask = 7; + /* FIXME: do we need to tweak dev/zx/devinput to allow us to force + 'turbo' features or make mbmask tell us - the Evo has 3 buttons + and wheel on 4-7 */ +} + diff --git a/Kernel/platform-zxevo/fuzix.lnk b/Kernel/platform-zxevo/fuzix.lnk new file mode 100644 index 00000000..687d505d --- /dev/null +++ b/Kernel/platform-zxevo/fuzix.lnk @@ -0,0 +1,52 @@ +-mwxuy +-i fuzix.ihx +-l z80 +-b _CODE=0x0100 +-b _COMMONDATA=0xF200 +-b _DISCARD=0xE200 +platform-zxevo/crt0.rel +platform-zxevo/commonmem.rel +platform-zxevo/zxevo.rel +platform-zxevo/video.rel +platform-zxevo/main.rel +platform-zxevo/discard.rel +start.rel +version.rel +lowlevel-z80.rel +usermem_std-z80.rel +platform-zxevo/tricks.rel +timer.rel +kdata.rel +usermem.rel +platform-zxevo/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 +syscall_net.rel +tty.rel +vt.rel +font8x8.rel +mm.rel +bank16k.rel +swap.rel +devsys.rel +devinput.rel +platform-zxevo/devtty.rel +platform-zxevo/devide.rel +platform-zxevo/devide_discard.rel +platform-zxevo/devsd.rel +platform-zxevo/devsd_discard.rel +platform-zxevo/evommc.rel +platform-zxevo/mbr.rel +platform-zxevo/blkdev.rel +platform-zxevo/devinput.rel +platform-zxevo/zxkeyboard.rel +platform-zxevo/net_native.rel +-e diff --git a/Kernel/platform-zxevo/kernel.def b/Kernel/platform-zxevo/kernel.def new file mode 100644 index 00000000..849a7684 --- /dev/null +++ b/Kernel/platform-zxevo/kernel.def @@ -0,0 +1,11 @@ +U_DATA .equ 0xF000 ; (this is struct u_data from kernel.h) +U_DATA__TOTALSIZE .equ 0x200 ; 256+256 bytes. + +Z80_TYPE .equ 1 + +PROGBASE .equ 0x0000 +PROGLOAD .equ 0x0100 + +NBUFS .equ 5 + +Z80_MMU_HOOKS .equ 0 diff --git a/Kernel/platform-zxevo/main.c b/Kernel/platform-zxevo/main.c new file mode 100644 index 00000000..7821ea27 --- /dev/null +++ b/Kernel/platform-zxevo/main.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include + +/* 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(); + tty_polluart(); + timer_interrupt(); + poll_input(); + if (timer_wait) + wakeup(&timer_interrupt); +} + +/* 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. + * + * Discard gets turned into buffers or user space + */ +void platform_discard(void) +{ + uint16_t discard_size = 0xE000 - (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; + } +} + +/* Adding dummy swapper since it is referenced by tricks.s */ +void swapper(ptptr p) +{ + p; +} diff --git a/Kernel/platform-zxevo/platform_ide.h b/Kernel/platform-zxevo/platform_ide.h new file mode 100644 index 00000000..d05e97a4 --- /dev/null +++ b/Kernel/platform-zxevo/platform_ide.h @@ -0,0 +1,27 @@ +/* + * ZX Evolution. Sort of a NEMO IDE but has extra magic so you don't + * have to play with two ports and sometimes byteswap but can just inir + * and otir. + */ + +#define ide_select(x) +#define ide_deselect() + +#define IDE_DRIVE_COUNT 2 + +#define IDE_REG_DATA 0x10 +#define IDE_DATA_LATCH 0x11 +#define IDE_REG_ERROR 0x30 +#define IDE_REG_FEATURES 0x30 +#define IDE_REG_SEC_COUNT 0x50 +#define IDE_REG_LBA_0 0x70 +#define IDE_REG_LBA_1 0x90 +#define IDE_REG_LBA_2 0xB0 +#define IDE_REG_LBA_3 0xD0 +#define IDE_REG_DEVHEAD 0xD0 +#define IDE_REG_STATUS 0xF0 +#define IDE_REG_COMMAND 0xF0 + +#define IDE_REG_ALTSTATUS 0xC8 +#define IDE_REG_CONTROL 0xC8 + diff --git a/Kernel/platform-zxevo/target.mk b/Kernel/platform-zxevo/target.mk new file mode 100644 index 00000000..3bffcde0 --- /dev/null +++ b/Kernel/platform-zxevo/target.mk @@ -0,0 +1 @@ +export CPU = z80 diff --git a/Kernel/platform-zxevo/tricks.s b/Kernel/platform-zxevo/tricks.s new file mode 100644 index 00000000..d4ee7e17 --- /dev/null +++ b/Kernel/platform-zxevo/tricks.s @@ -0,0 +1,248 @@ + .module tricks + + .globl _ptab_alloc + .globl _makeproc + .globl _chksigs + .globl _getproc + .globl _platform_monitor + .globl trap_illegal + .globl _platform_switchout + .globl _switchin + .globl _doexec + .globl _dofork + .globl _runticks + .globl unix_syscall_entry + .globl interrupt_handler + .globl map_kernel + .globl _ramtop + .globl _need_resched + .globl _int_disabled + .globl _udata + + ; imported debug symbols + .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex + + .include "kernel.def" + .include "../kernel.def" + + .area _COMMONMEM + +; ramtop must be in common for single process swapping cases +; and its a constant for the others from before init forks so it'll be fine +; here +_ramtop: + .dw 0 +_need_resched: + .db 0 + +; Switchout switches out the current process, finds another that is READY, +; possibly the same process, and switches it in. When a process is +; restarted after calling switchout, it thinks it has just returned +; from switchout(). +; +; This function can have no arguments or auto variables. +_platform_switchout: + ; save machine state + + ld hl, #0 ; return code set here is ignored, but _switchin can + ; return from either _switchout OR _dofork, so they must both write + ; U_DATA__U_SP with the following on the stack: + push hl ; return code + push ix + push iy + ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin + + ; find another process to run (may select this one again) + call _getproc + + push hl + call _switchin + + ; we should never get here + call _platform_monitor + +badswitchmsg: .ascii "_switchin: FAIL" + .db 13, 10, 0 + +_switchin: + di + pop bc ; return address + pop de ; new process pointer + + ld hl, #P_TAB__P_PAGE_OFFSET+3 ; Common + add hl, de ; process ptr + + ld a,#0x01 + out (0xBF),a ; Shadow on + + ld a, (hl) + ld bc,#0xF7F7 + out (c), a ; *CAUTION* our stack just left the building + + xor a + out (0xBF),a ; Shadow off + + ; carry clear from xor + + ; ------- No stack ------- + ; check u_data->u_ptab matches what we wanted + ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab + sbc hl, de ; subtract, result will be zero if DE==IX + jr nz, switchinfail + + ; wants optimising up a bit + ld hl, #P_TAB__P_STATUS_OFFSET + add hl, de + ld (hl), #P_RUNNING + + ; runticks = 0 + ld hl, #0 + ld (_runticks), hl + + ; restore machine state -- note we may be returning from either + ; _switchout or _dofork + ld sp, (U_DATA__U_SP) + + ; ---- New task stack ---- + + pop iy + pop ix + pop hl ; return code + + ; enable interrupts, if the ISR isn't already running + ld a, (U_DATA__U_ININTERRUPT) + ld (_int_disabled),a + or a + ret nz ; in ISR, leave interrupts off + ei + ret ; return with interrupts on + +switchinfail: + call outhl + ld hl, #badswitchmsg + call outstring + ; something went wrong and we didn't switch in what we asked for + jp _platform_monitor + +fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry + +; +; Called from _fork. We are in a syscall, the uarea is live as the +; parent uarea. The kernel is the mapped object. +; +_dofork: + ; always disconnect the vehicle battery before performing maintenance + di ; should already be the case ... belt and braces. + + pop de ; return address + pop hl ; new process p_tab* + push hl + push de + + ld (fork_proc_ptr), hl + + ; prepare return value in parent process -- HL = p->p_pid; + ld de, #P_TAB__P_PID_OFFSET + add hl, de + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; Save the stack pointer and critical registers. + ; When this process (the parent) is switched back in, it will be as if + ; it returns with the value of the child's pid. + push hl ; HL still has p->p_pid from above, the return value in the parent + push ix + push iy + + ; save kernel stack pointer -- when it comes back in the parent we'll be in + ; _switchin which will immediately return (appearing to be _dofork() + ; returning) and with HL (ie return code) containing the child PID. + ; Hurray. + ld (U_DATA__U_SP), sp + + ; now we're in a safe state for _switchin to return in the parent + ; process. + + ; --------- we switch stack copies in this call ----------- + call fork_copy ; copy 0x000 to udata.u_top and the + ; uarea and return on the childs + ; common + ; We are now in the kernel child context + + ; now the copy operation is complete we can get rid of the stuff + ; _switchin will be expecting from our copy of the stack. + pop bc + pop bc + pop bc + + ; The child makes its own new process table entry, etc. + ld hl, #_udata + push hl + ld hl, (fork_proc_ptr) + push hl + call _makeproc + pop bc + pop bc + + ; any calls to map process will now map the childs memory + + ; runticks = 0; + ld hl, #0 + ld (_runticks), hl + ; in the child process, fork() returns zero. + ; + ; And we exit, with the kernel mapped, the child now being deemed + ; to be the live uarea. The parent is frozen in time and space as + ; if it had done a switchout(). + ret + +fork_copy: + ld hl, (U_DATA__U_TOP) + ld de, #0x0fff + add hl, de ; + 0x1000 (-1 for the rounding to follow) + ld a, h + rlca + rlca ; get just the number of banks in the bottom + ; bits + and #3 + inc a ; and round up to the next bank + ld b, a + ; we need to copy the relevant chunks + ld hl, (fork_proc_ptr) + ld de, #P_TAB__P_PAGE_OFFSET + add hl, de + ; hl now points into the child pages + ld de, #U_DATA__U_PAGE + ; and de is the parent + +fork_next: + ; These two must in the loop for the moment as map_kernel in the + ; loop undoes it + ld a,#0x01 + out (0xBF),a ; Shadow on + ld a,(hl) + exx + ld bc,#0x37F7 + out (c), a ; 0x4000 map the child + exx + ld c, a + inc hl + ld a, (de) + exx + ld bc,#0x77F7 + out (c), a ; 0x8000 map the parent + exx + inc de + exx + ld hl, #0x8000 ; copy the bank + ld de, #0x4000 + ld bc, #0x4000 ; we copy the whole bank, we could optimise + ; further + ldir + exx + ; FIXME: get the process tables lower (eg data first ?) + call map_kernel ; put the maps back so we can look in p_tab + djnz fork_next + jp map_kernel diff --git a/Kernel/platform-zxevo/video.s b/Kernel/platform-zxevo/video.s new file mode 100644 index 00000000..4e243523 --- /dev/null +++ b/Kernel/platform-zxevo/video.s @@ -0,0 +1,194 @@ +; +; ZX Evolution Text Mode +; +; Not particularly sane +; +; 80 column but split so +; 0x01C0 holds 40 chars then a gap (left of each pair) +; 0x11C0 holds the same for the right pairs +; 0x21C0 is the attributes of the *right* pairs +; 0x31C0 is the attributes of the left pairs +; +; And the attributes are +; +; bits 7/5/4/3 = pixel colour +; bits 6/2/1/0 = background colour +; +; Lower font is ascii, upper font is russian but font can be +; changed providing you jump through some weird hoops +; + + ; 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 + + ; imports + + .globl map_video + .globl map_kernel +; +; Y * 64 + X / 2 +; Base is then 0x1C0 (left) 0x11C0 (right) +; +videopos: + ld a,e ; Get Y (0 - 24) + ld e,d ; X + rl e ; So it shifts back as we want + rra + srl e + rra ; In effect Y x 64 + + srl e ; A,E is now the 16bit offset + ; Y * 64 + x / 2 + ld d,a + jr nc, left + set 4,d ; right +left: + ld hl,#0x01c0 + add hl,de + ld a,h + xor #0x30 + ld d,a ; attributes + ld e,l ; + ret + +_plot_char: + pop hl + pop de ; D = x E = y + pop bc + push bc + push de + push hl + + call map_video + call videopos + ld (hl), a + ld a,(_curattr) + ld (de), a + jp map_kernel + +_clear_lines: + pop hl + pop de ; E = line, D = count + push de + push hl + ; This way we handle 0 correctly + inc d + ld c,d + ld d,#0 + call videopos + ld a,(_curattr) + call map_video + jr nextline + +clear_next_line: + ld b,#80 +clear_line_loop: + ld (hl),#' ' + inc hl + ld (de),a + inc de + djnz clear_line_loop +nextline: + dec c + jr nz, clear_next_line + jp map_kernel + +_clear_across: + pop hl + pop de ; DE = coords + pop bc ; C = count + push bc + push de + push hl + ld a,c + or a + ret z ; No work to do - bail out + call videopos + ld a,(_curattr) + ld b,c + call map_video +clear_loop: + ld (hl),#' ' + inc hl + ld (de),a + inc de + djnz clear_loop + jp map_kernel + +_scroll_down: + call map_video + ld hl,#0x07BF + ld de,#0x07FF + ld bc,#1600-64 + lddr + ld hl,#0x17BF + ld de,#0x17FF + ld bc,#1600-64 + lddr + ld hl,#0x27BF + ld de,#0x27FF + ld bc,#1600-64 + ldir + ld hl,#0x37BF + ld de,#0x37FF + ld bc,#1600-64 + ldir + jp map_kernel + +_scroll_up: + call map_video + ld hl,#0x01E0 + ld de,#0x01C0 + ld bc,#1600-64 + ldir + ld hl,#0x11E0 + ld de,#0x11C0 + ld bc,#1600-64 + ldir + ld hl,#0x21E0 + ld de,#0x21C0 + ld bc,#1600-64 + ldir + ld hl,#0x31E0 + ld de,#0x31C0 + ld bc,#1600-64 + ldir + jp map_kernel + +_cursor_on: + pop hl + pop de + push de + push hl + ld (cursorpos), de +_cursor_disable: +_cursor_off: + ld de,(cursorpos) + call videopos + call map_video + ld a,(de) + xor #0x3F + ld (de),a + jp map_kernel + +_do_beep: + ret + + .area _DATA + +cursorpos: + .dw 0 + + .area _COMMONMEM +_curattr: + .db 7 diff --git a/Kernel/platform-zxevo/zxevo.s b/Kernel/platform-zxevo/zxevo.s new file mode 100644 index 00000000..692004a7 --- /dev/null +++ b/Kernel/platform-zxevo/zxevo.s @@ -0,0 +1,264 @@ +; +; ZX Evolution hardware support +; + + .module zxevo + + ; 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 nmi_handler + + .globl map_buffers + .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_kernel_restore + .globl map_video + .globl current_map + + .globl _int_disabled + .globl _vtborder + + ; 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 + + .include "kernel.def" + .include "../kernel.def" + +; ----------------------------------------------------------------------------- +; COMMON MEMORY BANK (above 0xE000) +; ----------------------------------------------------------------------------- + .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 + ; FIXME: put back 48K ROM + rst 0 ; back into our booter + +platform_interrupt_all: + ret + + .area _COMMONDATA + +_int_disabled: + .db 1 + +_vtborder: ; needs to be common + .db 0 + + +; ----------------------------------------------------------------------------- +; KERNEL CODE BANK (below 0xC000, only accessible when the kernel is mapped) +; ----------------------------------------------------------------------------- + .area _CODE + +init_early: + ret + + .area _DISCARD + +init_hardware: + ; set system RAM size + ld hl, #4096 + ld (_ramsize), hl + ld hl, #512 ; FIXME: TBD + ld (_procmem), hl + + ; Set up video etc + + ; EFE7 bit 0 0 bit 5 0 + ; xx77 bit 3: 1 = 14Mhz + ; xx77 bits 2-0: 111 ATM video + + ld a,#0x01 + out (0xBF),a ; Shadow on + + ld bc,#0x0177 ; MMU on, hold off, res off + ld a,#0x0F ; 14MHz, 80x25 text mode + out (c),a + + ld bc,#0xFFBF + ld a,#0x00 ; FIXME: correct value + out (c),a ; Video and turbo set + + xor a + out (c),a ; Shadow back off + + ; EFE7 is shadow off ! + ld bc,#0xEFE7 + + ld a,#0x80 ; turbo, pentagon, video 80x25 + ; no RAM0 override + out (c),a + + + ; screen initialization + call _vtinit + + ret + +;------------------------------------------------------------------------------ +; COMMON MEMORY PROCEDURES FOLLOW + + .area _COMMONMEM + +_program_vectors: + pop de + pop hl + push hl + push de + call map_process + + ; write zeroes across all vectors + ld hl, #0 + ld de, #1 + ld bc, #0x007f ; program first 0x80 bytes only + ld (hl), #0x00 + ldir + + ; now install the interrupt vector at 0x0038 + ld a, #0xC3 ; JP instruction + ld (0x0038), a + ld hl, #interrupt_handler + ld (0x0039), hl + + ; set restart vector for FUZIX system calls + ld (0x0030), a ; (rst 30h is unix function call vector) + ld hl, #unix_syscall_entry + ld (0x0031), hl + + ld (0x0000), a + ld hl, #null_handler ; to Our Trap Handler + ld (0x0001), hl + + ld (0x0066), a ; Set vector for NMI + ld hl, #nmi_handler + ld (0x0067), hl + + jr map_kernel + +map_process: + ld a, h + or l + jr z, map_kernel +map_process_always: +map_process_always_di: + push af + push bc + push hl + ld hl,(U_DATA__U_PAGE) +map_write_hl: + ld (current_map),hl + ; + ; The map is stored with page number complements + ; + ld a,#0x01 + out (0xBF),a ; Shadow on + ld bc,#0x37F7 + outi + ld b,#0x77 + outi + ld b,#0xB7 + outi + xor a + out (0xBF),a ; Shadow on + pop hl + pop bc + pop af + ret + +; +; Save and switch to kernel +; +map_save_kernel: + push hl + ld hl, (current_map) + ld (map_store), hl + pop hl +map_kernel_di: +map_kernel: +map_buffers: +map_kernel_restore: + push af + push bc + push hl + ld hl, #kernel_map + jr map_write_hl + +map_video: + push af + push bc + push hl + ld hl, #video_map + jr map_write_hl + +map_restore: + push af + push bc + push hl + ld hl, (map_store) + jr map_write_hl + +; +; Debug output +; +outchar: + push bc +outcw: + ld c,#0xFDEF + in a,(c) + and #0x20 + jr z, outcw + ld b,#0xF8 + out (c),a + pop bc + ret + + .area _COMMONDATA +_tmpout: + .db 1 + +current_map: ; place to store current page pointer + .dw 0 +map_store: ; and the saved one + .dw 0 + + ; TODO FIXME +kernel_map: + .db 0, 1, 2, 3 +video_map: + .db 0, 1, 8, 3