From: Alan Cox Date: Sat, 1 Nov 2014 12:34:52 +0000 (+0000) Subject: platform-px4: Add the PX4Plus X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=dde307cbd3f61234b51624f3127b45747bd7c076;p=FUZIX.git platform-px4: Add the PX4Plus The question was asked and its an interesting one as the PX4Plus is probably right on the limit of what we can handle if we use the ROM pods. This is untested but builds and also not very useful as it doesn't yet have the vt driver, keyboard, font or floppy. It does seem to prove that if you breathe in then you can fit the Z80 core into 32K of ROM with 8K for the common/udata and put the video/floppy/fonts banked into the top of the RAM area. That would still allow something like 48K binaries to run, and as the PX4Plus has at best 128K of RAMdisc for swapping 32K is probably a saner limit anyway. And no.. I do not think swapping to a 38400 baud serial floppy would rock. --- diff --git a/Kernel/Makefile b/Kernel/Makefile index 493b1116..34101151 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -1,6 +1,6 @@ TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-spec3 platform-trs80 platform-z80pack platform-z80pack-lite -export TARGET= pcw8256 +export TARGET= px4plus export CPU = z80 #export TARGET = 6809test #export CPU = 6809 diff --git a/Kernel/platform-px4plus/Makefile b/Kernel/platform-px4plus/Makefile new file mode 100644 index 00000000..cdbf5301 --- /dev/null +++ b/Kernel/platform-px4plus/Makefile @@ -0,0 +1,25 @@ + +CSRCS = devlpr.c devtty.c devfd.c +CSRCS += devices.c main.c + +ASRCS = crt0.s px4plus.s +ASRCS += tricks.s commonmem.s + +COBJS = $(CSRCS:.c=.rel) +AOBJS = $(ASRCS:.s=.rel) +OBJS = $(COBJS) $(AOBJS) + +JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst) + +all: $(OBJS) + +$(COBJS): %.rel: %.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(AOBJS): %.rel: %.s + $(CROSS_AS) $(ASOPTS) $< + +clean: + rm -f $(OBJS) $(JUNK) core *~ + +image: diff --git a/Kernel/platform-px4plus/README b/Kernel/platform-px4plus/README new file mode 100644 index 00000000..d1a65e5d --- /dev/null +++ b/Kernel/platform-px4plus/README @@ -0,0 +1,34 @@ +A FUZIX target for the PX4plus + +Just playing to see if we can make it fit. + +The PX4Plus has 64K of RAM, and can overlay 6000-DFFF with one of two +different ROMpacks (usually 'basic' and 'utility'). We build the kernel +at 0x6000 but for now plonk it into RAM so we can debug it. The small 8K +top window is awkward as we need to get udata and our kernel data/common in +that space if possible. We can hide the font/video below that under the top of +the ROM however. + + +Intended Memory Map + + +0x0000-0x00FF Vectors +0x0100-0x???? (RAM) User program (and discard area) +0xD000-0xDFFF Framebuffer, font, video code +0xE000-0xF7FFish Data for kernel +0xF800-0xFCFF Common (currently ends FBCC) +0xFD00-0xFFFF Udata + +In kernel execution modes we then are either + +0x0000-0x00FF Vectors +0x0100-0x5FFF Lower part of user +0x6000-0xDFFF Kernel code in ROM +0xE000-0xF7FFish Data for kernel +0xF800-0xFCFF Common (currently ends FBCC) +0xFD00-0xFFFF Udata + +and we will need to tuck the video code/font/framebuffer at 0xD000 or +similar in RAM under the ROM area. May need to hide the floppy driver +there too as its all a little bit tight diff --git a/Kernel/platform-px4plus/commonmem.s b/Kernel/platform-px4plus/commonmem.s new file mode 100644 index 00000000..82d17cb9 --- /dev/null +++ b/Kernel/platform-px4plus/commonmem.s @@ -0,0 +1,47 @@ +; +; Uarea is not in common on pure swap +; + .module commonmem + + ; exported symbols + .globl _ub + .globl _udata + .globl kstack_top + .globl istack_top + .globl istack_switched_sp + + .area _UDATA + +_ub: ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above +_udata: +kstack_base: + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +kstack_top: + + ; next 256 bytes: 254 byte interrupt stack, then 2 byte saved stack pointer +istack_base: + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +istack_top: +istack_switched_sp: .dw 0 diff --git a/Kernel/platform-px4plus/config.h b/Kernel/platform-px4plus/config.h new file mode 100644 index 00000000..264ad1ab --- /dev/null +++ b/Kernel/platform-px4plus/config.h @@ -0,0 +1,49 @@ +/* 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 +/* CP/M emulation */ +#undef CONFIG_CPM_EMU +/* Fixed banking */ +#undef CONFIG_BANK_FIXED +/* Swap only */ +#define CONFIG_SWAP_ONLY +/* Simple user copies for now (change when ROM the kernel) */ +#define CONFIG_USERMEM_C +#define BANK_KERNEL +#define BANK_PROCESS + +/* Banks as reported to user space */ +#define CONFIG_BANKS 1 + +/* FIXME: the OVL timer isn't quite 100/sec and we have an accurate 1Hz + timer available, so needs some tweaking */ +#define TICKSPERSEC 100 /* Ticks per second */ +#define PROGBASE ((char *)(0x0100)) /* also data base */ +#define PROGTOP ((char *)(0x7D00)) /* Top of program, base of U_DATA */ + +#define SWAP_SIZE 0x40 /* 32K in blocks (we actually don't need the low 256) */ +#define SWAPBASE 0x0000 /* We swap the lot in one, include the */ +#define SWAPTOP 0x8000 /* vectors so its a round number of sectors */ +#define MAX_SWAPS 4 /* We have a whopping 128K of RAMDISC! */ + +#define BOOT_TTY (512 + 1)/* Set this to default device for stdio, stderr */ + /* In this case, the default is the first TTY device */ + +/* We need a tidier way to do this from the loader */ +#define CMDLINE NULL /* Location of root dev name */ + +/* Device parameters */ +#define NUM_DEV_TTY 2 + +#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ +#define SWAPDEV (256 + 0) /* Device for swapping. (ram drive) */ +#define NBUFS 6 /* Number of block buffers */ +#define NMOUNTS 2 /* Number of mounts at a time */ + diff --git a/Kernel/platform-px4plus/crt0.s b/Kernel/platform-px4plus/crt0.s new file mode 100644 index 00000000..30dccdbb --- /dev/null +++ b/Kernel/platform-px4plus/crt0.s @@ -0,0 +1,64 @@ +; 2013-12-18 William R Sowerbutts + + .module crt0 + + ; Ordering of segments for the linker. + ; WRS: Note we list all our segments here, even though + ; we don't use them all, because their ordering is set + ; when they are first seen. + .area _CODE + .area _CODE2 + .area _CONST + .area _DATA + .area _INITIALIZED + .area _COMMONMEM + .area _BSEG + .area _BSS + .area _HEAP + ; note that areas below here may be overwritten by the heap at runtime, so + ; put initialisation stuff in here + .area _INITIALIZER + .area _GSINIT + .area _GSFINAL + + .area _DISCARD + .area _UDATA + + ; imported symbols + .globl _fuzix_main + .globl init_early + .globl init_hardware + .globl s__INITIALIZER + .globl s__COMMONMEM + .globl l__COMMONMEM + .globl s__DATA + .globl l__DATA + .globl kstack_top + + ; startup code + .area _CODE +init: + di + ld sp, #kstack_top + + ; Configure memory map + call init_early + + ; zero the data area + ld hl, #s__DATA + ld de, #s__DATA + 1 + ld bc, #l__DATA - 1 + ld (hl), #0 + ldir + + ; 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 + diff --git a/Kernel/platform-px4plus/devfd.c b/Kernel/platform-px4plus/devfd.c new file mode 100644 index 00000000..5d5fd01b --- /dev/null +++ b/Kernel/platform-px4plus/devfd.c @@ -0,0 +1,101 @@ +/* + * Disk driver + */ + +#include +#include +#include +#include + +static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag); +static int hd_transfer(bool is_read, uint8_t minor, uint8_t rawflag); + +int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; + return fd_transfer(true, minor, rawflag); +} + +int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; + return fd_transfer(false, minor, rawflag); +} + +/* hd is only used for swapping */ +int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; + return hd_transfer(true, minor, rawflag); +} + +int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; + return hd_transfer(false, minor, rawflag); +} + +static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag) +{ + /* Serial floppy driver - to write */ + is_read; + minor; + rawflag; + return -EIO; +} + +/* Easier to use statics as is this is single threaded and talking to asm + code in a critical path */ + +uint16_t ramd_off; +uint16_t ramd_size; +uint16_t ramd_uaddr; + +/* Really only ever used for swap */ +static int hd_transfer(bool is_read, uint8_t minor, uint8_t rawflag) +{ + minor; + + if(rawflag == 1) { + ramd_size = udata.u_count; + ramd_uaddr = (uint16_t)udata.u_base; + ramd_off = udata.u_offset << 1; + /* Should check this higher up ? */ + if ((ramd_size & 0x1FF) || (ramd_off & 0x1FF)) + return -EIO; + } else if (rawflag == 2) { /* Swap device special */ + ramd_size = swapcnt << 9; + ramd_uaddr = (uint16_t)swapbase; + ramd_off = swapblk << 1; + } else { /* rawflag == 0 */ + ramd_uaddr = (uint16_t)udata.u_buf->bf_data; + ramd_off = udata.u_buf->bf_blk << 8; + ramd_size = 512; + } + /* Block copy to/from the RAM disc I/O */ + if (is_read) + hd_xferin(); + else + hd_xferout(); + return ramd_size; +} + +int fd_open(uint8_t minor, uint16_t flag) +{ + flag; + if(minor >= 3) { + udata.u_error = ENODEV; + return -1; + } + return 0; +} + +int hd_open(uint8_t minor, uint16_t flag) +{ + flag; + if(minor) { + udata.u_error = ENODEV; + return -1; + } + return 0; +} diff --git a/Kernel/platform-px4plus/devfd.h b/Kernel/platform-px4plus/devfd.h new file mode 100644 index 00000000..629628ae --- /dev/null +++ b/Kernel/platform-px4plus/devfd.h @@ -0,0 +1,17 @@ +#ifndef __DEVFD_DOT_H__ +#define __DEVFD_DOT_H__ + +/* public interface */ +int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag); +int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag); +int fd_open(uint8_t minor, uint16_t flag); + +int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag); +int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag); +int hd_open(uint8_t minor, uint16_t flag); + +/* asm code */ +void hd_xferin(void); +void hd_xferout(void); + +#endif /* __DEVRD_DOT_H__ */ diff --git a/Kernel/platform-px4plus/devices.c b/Kernel/platform-px4plus/devices.c new file mode 100644 index 00000000..2c004595 --- /dev/null +++ b/Kernel/platform-px4plus/devices.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct devsw dev_tab[] = /* The device driver switch table */ +{ +// minor open close read write ioctl +// ----------------------------------------------------------------- + /* 0: /dev/fd Floppy disc block devices */ + { fd_open, no_close, fd_read, fd_write, no_ioctl }, + /* 1: /dev/hd Hard disc block devices (absent) */ + { hd_open, no_close, hd_read, hd_write, no_ioctl }, + /* 2: /dev/tty TTY devices */ + { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, + /* 3: /dev/lpr Printer devices */ + { lpr_open, lpr_close, no_rdwr, lpr_write, no_ioctl }, + /* 4: /dev/mem etc System devices (one offs) */ + { no_open, no_close, sys_read, sys_write, sys_ioctl }, + /* Pack to 7 with nxio if adding private devices and start at 8 */ +}; + +bool validdev(uint16_t dev) +{ + /* This is a bit uglier than needed but the right hand side is + a constant this way */ + if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) + 255) + return false; + else + return true; +} + +void device_init(void) +{ + int i; + /* Add 4 swaps (128K) to use the entire RAM drive */ + for (i = 0; i < MAX_SWAPS; i++) + swapmap_add(i); +} + +__sfr __at 0x19 ioctrlr; + +/* FIXME: find correct initial value */ +static uint8_t ioctrlr_shadow = 0x00; + +/* We need to track the state of the ioctrlr port as it is a shared + resource (7 = speaker, 6-4 LEDs, 3 - !cartridge reset, 2 serial out ctrl + 1 !printer initial output, 0 lpt strobe */ + +void mod_ioctrlr(uint8_t set, uint8_t clr) +{ + ioctrlr_shadow &= ~clr; + ioctrlr_shadow |= set; + ioctrlr = ioctrlr_shadow; +} diff --git a/Kernel/platform-px4plus/devices.h b/Kernel/platform-px4plus/devices.h new file mode 100644 index 00000000..cde79f9f --- /dev/null +++ b/Kernel/platform-px4plus/devices.h @@ -0,0 +1,2 @@ + +extern void mod_ioctrlr(uint8_t set, uint8_t clr); diff --git a/Kernel/platform-px4plus/devlpr.c b/Kernel/platform-px4plus/devlpr.c new file mode 100644 index 00000000..8c92b403 --- /dev/null +++ b/Kernel/platform-px4plus/devlpr.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include + +__sfr __at 0x16 lpstat; +__sfr __at 0x17 lpdata; + +int lpr_open(uint8_t minor, uint16_t flag) +{ + minor; flag; // shut up compiler + return 0; +} + +int lpr_close(uint8_t minor) +{ + minor; // shut up compiler + return 0; +} + +int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + int c = udata.u_count; + char *p = udata.u_base; + uint16_t ct; + minor; rawflag; flag; // shut up compiler + + while(c-- > 0) { + ct = 0; + while ((lpstat & 0x3) == 0x1) { + ct++; + /* Try and be polite */ + if (ct == 10000) { + udata.u_ptab->p_timeout = 3; + if (psleep_flags(NULL, flag)) { + if (udata.u_count) + udata.u_error = 0; + return udata.u_count; + } + ct = 0; + } + } + /* Printer on fire ? */ + if (lpstat & 0x2) + return -EIO; + lpdata = ugetc(p++); + /* Strobe */ + mod_ioctrlr(1,1); + mod_ioctrlr(0,1); + } + return (-1); +} diff --git a/Kernel/platform-px4plus/devlpr.h b/Kernel/platform-px4plus/devlpr.h new file mode 100644 index 00000000..7765c187 --- /dev/null +++ b/Kernel/platform-px4plus/devlpr.h @@ -0,0 +1,8 @@ +#ifndef __DEVLPR_DOT_H__ +#define __DEVLPR_DOT_H__ + +int lpr_open(uint8_t minor, uint16_t flag); +int lpr_close(uint8_t minor); +int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag); + +#endif diff --git a/Kernel/platform-px4plus/devtty.c b/Kernel/platform-px4plus/devtty.c new file mode 100644 index 00000000..074bfc3f --- /dev/null +++ b/Kernel/platform-px4plus/devtty.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include + +/* Console is only port we provide, port 2 there but used for floppies */ +char tbuf1[TTYSIZ]; + +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 }, +}; + +/* Write to system console */ +void kputchar(char c) +{ + /* handle CRLF */ + if(c=='\n') + tty_putc(1, '\r'); + tty_putc(1, c); +} + +/* It's the console display, always ready */ +static bool tty_writeready(uint8_t minor) +{ + minor; + return 1; +} + +void tty_putc(uint8_t minor, unsigned char c) +{ + minor;c; + /* Fixme: wire in VT code */ +} + +void tty_setup(uint8_t minor) +{ + minor; +} + +int tty_carrier(uint8_t minor) +{ + minor; + return 1; +} diff --git a/Kernel/platform-px4plus/devtty.h b/Kernel/platform-px4plus/devtty.h new file mode 100644 index 00000000..4638611d --- /dev/null +++ b/Kernel/platform-px4plus/devtty.h @@ -0,0 +1,7 @@ +#ifndef __DEVTTY_DOT_H__ +#define __DEVTTY_DOT_H__ +void tty_putc(uint8_t minor, unsigned char c); +bool tty_writeready(uint8_t minor); +void tty_pollirq(void); +void tty_setup(uint8_t minor); +#endif diff --git a/Kernel/platform-px4plus/main.c b/Kernel/platform-px4plus/main.c new file mode 100644 index 00000000..6cb5ac5c --- /dev/null +++ b/Kernel/platform-px4plus/main.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include + +uint8_t *ramtop = PROGTOP; + +/* On idle we spin checking for the terminals. Gives us more responsiveness + for the polled ports */ +void platform_idle(void) +{ + __asm + halt + __endasm; +} + +__sfr __at 0x04 isr; + +void platform_interrupt(void) +{ + uint8_t irq = isr; + /* We need to handle 1 for the 7508, and 2 for GAPNIO (serial in) at least */ + /* Overflow on timer */ + if (irq & 4) + timer_interrupt(); +} + +/* Nothing to do for the map of init */ +void map_init(void) +{ +} diff --git a/Kernel/platform-px4plus/px4plus.s b/Kernel/platform-px4plus/px4plus.s new file mode 100644 index 00000000..c5405348 --- /dev/null +++ b/Kernel/platform-px4plus/px4plus.s @@ -0,0 +1,224 @@ +; +; Z80Pack hardware support +; +; +; This goes straight after udata for common. Because of that the first +; 256 bytes get swapped to and from disk with the uarea (512 byte disk +; blocks). This isn't a problem but don't put any variables in here. +; +; If you make this module any shorter, check what follows next +; + + + .module px4plus + + ; exported symbols + .globl init_early + .globl init_hardware + .globl _program_vectors + .globl _system_tick_counter + + .globl map_kernel + .globl map_process + .globl map_process_always + .globl map_save + .globl map_restore + + ; exported debugging tools + .globl _trap_monitor + .globl outchar + + ; imported symbols + .globl _ramsize + .globl _procmem + + .globl unix_syscall_entry + .globl null_handler + .globl nmi_handler + .globl interrupt_handler + + ; RAM drive + .globl _hd_xferin + .globl _hd_xferout + .globl _ramd_off + .globl _ramd_size + .globl _ramd_uaddr + + + .include "kernel.def" + .include "../kernel.def" + +; ----------------------------------------------------------------------------- +; COMMON MEMORY BANK (not unmapped when we flip to ROM) +; ----------------------------------------------------------------------------- + .area _COMMONMEM + +; FIXME: figure out how to reboot into CP/M +_trap_monitor: +_trap_reboot: + di + halt + +; ----------------------------------------------------------------------------- +; KERNEL MEMORY BANK (only accessible when the kernel is mapped) +; ----------------------------------------------------------------------------- + .area _CODE + +init_early: + ret + +init_hardware: + ; set system RAM size + ; Not strictly correct FIXME: set right when ROM the image + ld hl, #64 + ld (_ramsize), hl + ld hl, #32 ; 32K for kernel + ld (_procmem), hl + + ; set up interrupt vectors for the kernel + ld hl, #0 + push hl + call _program_vectors + pop hl + + ; IRQ enables + ld a, #0xB ; OVF (timer), RXRDY (gapnio), 7508 + out (0x04), a + + im 1 ; set CPU interrupt mode + ret + + +;------------------------------------------------------------------------------ +; COMMON MEMORY PROCEDURES FOLLOW + + .area _COMMONMEM + + +_program_vectors: + ; we are called, with interrupts disabled, by both newproc() and crt0 + ; will exit with interrupts off + + ; write zeroes across all vectors + ld hl, #0 + ld de, #1 + ld bc, #0x007f ; program first 0x80 bytes only + ld (hl), #0x00 + ldir + + ; now install the interrupt vector at 0x0038 + ld a, #0xC3 ; JP instruction + ld (0x0038), a + ld hl, #interrupt_handler + ld (0x0039), hl + + ; set restart vector for UZI system calls + ld (0x0030), a ; (rst 30h is unix function call vector) + ld hl, #unix_syscall_entry + ld (0x0031), hl + + ; Set vector for jump to NULL + 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 + + ; our platform has a "true" common area, if it did not we would + ; need to copy the "common" code into the common area of the new + ; process. + + ; falls through + + ; Map functions are trivial for now + ; FIXME: will need to play with BANKR once we ROM the image +map_kernel: +map_process: +map_process_always: +map_save: +map_restore: + ret + +; outchar: Wait for UART TX idle, then print the char in A +outchar: + push af +outcharw: + in a, (0x15) + bit 0, a + jr z, outcharw + pop af + out (0x14), a + ret + +; +; RAM disc +; +_hd_xferin: +; +; Load the full 24 bit address to start +; + xor a ; always aligned + out (0x90), a + ld hl, #_ramd_off + 1 + ld de, (_ramd_size) +hd_xiloop: + ld a, (hl) + out (0x91), a + inc hl + ld a, (hl) + out (0x92), a + ld bc, #0x93 +; +; With a 256 byte block it autoincrements +; + ld hl, (_ramd_uaddr) + inir + dec d + ret z +; +; Move on a block +; + ld (_ramd_uaddr), hl + ld hl, #_ramd_off + 1 + inc (hl) + jr nz, hd_xiloop + inc hl + inc (hl) + dec hl + jr hd_xiloop + +_hd_xferout: +; +; Load the full 24 bit address to start +; + xor a ; always aligned + out (0x90), a + ld hl, #_ramd_off + 1 + ld de, (_ramd_size) +hd_xoloop: + ld a, (hl) + out (0x91), a + inc hl + ld a, (hl) + out (0x92), a + ld bc, #0x93 +; +; With a 256 byte block it autoincrements +; + ld hl, (_ramd_uaddr) + otir + dec d + ret z +; +; Move on a block +; + ld (_ramd_uaddr), hl + ld hl, #_ramd_off + 1 + inc (hl) + jr nz, hd_xoloop + inc hl + inc (hl) + dec hl + jr hd_xiloop diff --git a/Kernel/platform-px4plus/tricks.s b/Kernel/platform-px4plus/tricks.s new file mode 100644 index 00000000..4b50fcab --- /dev/null +++ b/Kernel/platform-px4plus/tricks.s @@ -0,0 +1,223 @@ +; 2013-12-21 William R Sowerbutts + + .module tricks + + .globl _ptab_alloc + .globl _newproc + .globl _chksigs + .globl _getproc + .globl _trap_monitor + .globl trap_illegal + .globl _inint + .globl _switchout + .globl _switchin + .globl _doexec + .globl _dofork + .globl _runticks + .globl unix_syscall_entry + .globl interrupt_handler + .globl dispatch_process_signal + .globl _swapper + .globl _swapout + + ; imported debug symbols + .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex + + .include "kernel.def" + .include "../kernel.def" + + .area _COMMONMEM + +; 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(). +; +; FIXME: make sure we optimise the switch to self case higher up the stack! +; +; This function can have no arguments or auto variables. +_switchout: + di + call _chksigs + ; 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 + + ; set inint to false + xor a + ld (_inint), a + + ; find another process to run (may select this one again) + call _getproc + + push hl + call _switchin + + ; we should never get here + call _trap_monitor + +badswitchmsg: .ascii "_switchin: FAIL" + .db 13, 10, 0 +swapped: .ascii "_switchin: SWAPPED" + .db 13, 10, 0 + +_switchin: + di + pop bc ; return address + pop de ; new process pointer +; +; FIXME: do we actually *need* to restore the stack ! +; + push de ; restore stack + push bc ; restore stack + + push de + ld hl, #P_TAB__P_PAGE_OFFSET + add hl, de ; process ptr + pop de + + ld a, (hl) + + or a + jr nz, not_swapped + + ; + ; We are still on the departing processes stack, which is + ; fine for now. + ; + ld sp, #_swapstack + push hl + ; We will always swap out the current process + ld hl, (U_DATA__U_PTAB) + push hl + call _swapout + pop hl + pop hl + push de + call _swapper + pop de + pop hl + ld a, (hl) + +not_swapped: + ; check u_data->u_ptab matches what we wanted + ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab + or a ; clear carry flag + sbc hl, de ; subtract, result will be zero if DE==IX + jr nz, switchinfail + + ; wants optimising up a bit + ld ix, (U_DATA__U_PTAB) + ; next_process->p_status = P_RUNNING + ld P_TAB__P_STATUS_OFFSET(ix), #P_RUNNING + + ; Fix the moved page pointers + ; Just do one byte as that is all we use on this platform + ld a, P_TAB__P_PAGE_OFFSET(ix) + ld (U_DATA__U_PAGE), a + ; 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) + + pop iy + pop ix + pop hl ; return code + + ; enable interrupts, if the ISR isn't already running + ld a, (_inint) + or a + ret z ; 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 _trap_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. + + ld hl, (U_DATA__U_PTAB) + push hl + call _swapout + pop hl + + ; 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 + + ; Make a new process table entry, etc. + ld hl, (fork_proc_ptr) + push hl + call _newproc + pop bc + + ; 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 +; +; We can keep a stack in common because we will complete our +; use of it before we switch common block. In this case we have +; a true common so it's even easier. +; + .ds 128 +_swapstack: diff --git a/Kernel/platform-px4plus/uzi.lnk b/Kernel/platform-px4plus/uzi.lnk new file mode 100644 index 00000000..6923d9de --- /dev/null +++ b/Kernel/platform-px4plus/uzi.lnk @@ -0,0 +1,37 @@ +-mwxuy +-i uzi.ihx +-b _DISCARD=0x5000 +-b _UDATA=0xFD00 +-b _CODE=0x6000 +-b _DATA=0xE000 +-k /usr/share/sdcc/lib/z80 +-l z80 +platform-px4plus/crt0.rel +platform-px4plus/commonmem.rel +platform-px4plus/px4plus.rel +platform-px4plus/main.rel +start.rel +version.rel +lowlevel-z80.rel +platform-px4plus/tricks.rel +timer.rel +kdata.rel +usermem.rel +platform-px4plus/devfd.rel +platform-px4plus/devices.rel +devio.rel +filesys.rel +process.rel +inode.rel +syscall_fs.rel +syscall_fs2.rel +syscall_proc.rel +syscall_other.rel +tty.rel +mm.rel +simple.rel +swap.rel +devsys.rel +platform-px4plus/devlpr.rel +platform-px4plus/devtty.rel +-e