From aa759e1f2b3f981d7602943a3167fa279b2eeff6 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 23 Jun 2018 01:18:01 +0100 Subject: [PATCH] rc2014: import the RC2014 fork of Fuzix and realign it with current kernels Not yet tested. In theory the changes done are small... --- Kernel/platform-rc2014/Makefile | 64 +++ Kernel/platform-rc2014/README | 48 +++ Kernel/platform-rc2014/bootrom.s | 59 +++ Kernel/platform-rc2014/commonmem.s | 9 + Kernel/platform-rc2014/config.h | 100 +++++ Kernel/platform-rc2014/crt0.s | 114 ++++++ Kernel/platform-rc2014/devices.c | 47 +++ Kernel/platform-rc2014/devrd_zeta2.c | 45 +++ Kernel/platform-rc2014/devrd_zeta2_hw.s | 141 +++++++ Kernel/platform-rc2014/devtty.c | 155 ++++++++ Kernel/platform-rc2014/devtty.h | 16 + Kernel/platform-rc2014/devtty_discard.c | 21 + Kernel/platform-rc2014/discard.c | 62 +++ Kernel/platform-rc2014/diskboot.s | 197 ++++++++++ Kernel/platform-rc2014/fuzix.lnk | 50 +++ Kernel/platform-rc2014/kernel.def | 48 +++ Kernel/platform-rc2014/main.c | 66 ++++ Kernel/platform-rc2014/monitor.s | 37 ++ Kernel/platform-rc2014/platform_ide.h | 38 ++ Kernel/platform-rc2014/ppide.c | 121 ++++++ Kernel/platform-rc2014/rc2014.h | 24 ++ Kernel/platform-rc2014/rc2014.s | 496 ++++++++++++++++++++++++ Kernel/platform-rc2014/target.mk | 1 + Kernel/platform-rc2014/tricks.s | 235 +++++++++++ Kernel/platform-rc2014/vfd-debug.c | 10 + Kernel/platform-rc2014/vfd-debug.h | 13 + Kernel/platform-rc2014/vfd-term.c | 18 + Kernel/platform-rc2014/vfd-term.h | 9 + Kernel/platform-rc2014/vfdterm.s | 191 +++++++++ 29 files changed, 2435 insertions(+) create mode 100644 Kernel/platform-rc2014/Makefile create mode 100644 Kernel/platform-rc2014/README create mode 100644 Kernel/platform-rc2014/bootrom.s create mode 100644 Kernel/platform-rc2014/commonmem.s create mode 100644 Kernel/platform-rc2014/config.h create mode 100644 Kernel/platform-rc2014/crt0.s create mode 100644 Kernel/platform-rc2014/devices.c create mode 100644 Kernel/platform-rc2014/devrd_zeta2.c create mode 100644 Kernel/platform-rc2014/devrd_zeta2_hw.s create mode 100644 Kernel/platform-rc2014/devtty.c create mode 100644 Kernel/platform-rc2014/devtty.h create mode 100644 Kernel/platform-rc2014/devtty_discard.c create mode 100644 Kernel/platform-rc2014/discard.c create mode 100644 Kernel/platform-rc2014/diskboot.s create mode 100644 Kernel/platform-rc2014/fuzix.lnk create mode 100644 Kernel/platform-rc2014/kernel.def create mode 100644 Kernel/platform-rc2014/main.c create mode 100644 Kernel/platform-rc2014/monitor.s create mode 100644 Kernel/platform-rc2014/platform_ide.h create mode 100644 Kernel/platform-rc2014/ppide.c create mode 100644 Kernel/platform-rc2014/rc2014.h create mode 100644 Kernel/platform-rc2014/rc2014.s create mode 100644 Kernel/platform-rc2014/target.mk create mode 100644 Kernel/platform-rc2014/tricks.s create mode 100644 Kernel/platform-rc2014/vfd-debug.c create mode 100644 Kernel/platform-rc2014/vfd-debug.h create mode 100644 Kernel/platform-rc2014/vfd-term.c create mode 100644 Kernel/platform-rc2014/vfd-term.h create mode 100644 Kernel/platform-rc2014/vfdterm.s diff --git a/Kernel/platform-rc2014/Makefile b/Kernel/platform-rc2014/Makefile new file mode 100644 index 00000000..d2677977 --- /dev/null +++ b/Kernel/platform-rc2014/Makefile @@ -0,0 +1,64 @@ +ASRCS = crt0.s tricks.s commonmem.s rc2014.s monitor.s vfdterm.s +ASRCS += devrd_zeta2_hw.s +CSRCS = devices.c main.c devtty.c devrd_zeta2.c vfd-debug.c vfd-term.c +DISCARD_CSRCS = discard.c devtty_discard.c +DISCARD_DSRCS = +DSRCS = ../dev/devfd.c ../dev/devsd.c ../dev/mbr.c ../dev/blkdev.c +DSRCS += ../dev/devrd.c +DASRCS = ../dev/devfd_hw.s ../dev/devrd_hw.s + +AOBJS = $(ASRCS:.s=.rel) +COBJS = $(CSRCS:.c=.rel) +DISCARD_COBJS = $(DISCARD_CSRCS:.c=.rel) +DISCARD_DOBJS = $(patsubst ../dev/%.c,%.rel, $(DISCARD_DSRCS)) +DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS)) +DAOBJS = $(patsubst ../dev/%.s,%.rel, $(DASRCS)) + +OBJS = $(AOBJS) $(COBJS) $(DOBJS) $(DAOBJS) $(DISCARD_DOBJS) $(DISCARD_COBJS) + +CROSS_CCOPTS += -I../dev/ + +JUNK = *.rel *.lst *.asm *.sym *.rst *.map *.ihx *.bin + +all: $(OBJS) diskboot.bin + +$(AOBJS): %.rel: %.s + $(CROSS_AS) $(ASOPTS) $< + +$(COBJS): %.rel: %.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(DOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(DAOBJS): %.rel: ../dev/%.s + $(CROSS_AS) $(ASOPTS) $@ $< + +$(DISCARD_COBJS): %.rel: %.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(DISCARD_DOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +clean: + rm -f $(OBJS) $(JUNK) core *~ bootrom.ihx bootrom.bin diskboot.bin fuzix.com fuzix.rom + +diskboot.bin: diskboot.s + $(CROSS_AS) $(ASOPTS) diskboot.s + sdldz80 -nmi diskboot.rel + makebin -s 65536 diskboot.ihx | dd bs=512 skip=125 count=1 of=diskboot.bin + +image: + sdasz80 -o bootrom.s + sdldz80 -m -i bootrom.rel + makebin -s 136 bootrom.ihx > bootrom.bin +# cat bootrom.bin ../fuzix.bin | dd conv=sync bs=65536 count=1 of=fuzix.rom + cat bootrom.bin ../fuzix.bin > tmp.rom + cat tmp.rom | dd conv=sync bs=65536 count=1 of=fuzix.rom + cat fuzix.rom ../rc2014_root_fs > fuzix_rc2014_sio_bootfs.rom + ../cpm-loader/makecpmloader ../cpm-loader/cpmload.bin ../fuzix.bin 0x88 fuzix.com + ../cpm-loader/makecpmloader ../cpm-loader/fuzixload.bin ../fuzix.bin 0x88 fuzix + +cleanup_sio_acia: + rm -f devtty.asm devtty.rel main.asm main.rel rc2014.rel + rm -f devtty_discard.asm devtty_discard.rel discard.asm discard.rel diff --git a/Kernel/platform-rc2014/README b/Kernel/platform-rc2014/README new file mode 100644 index 00000000..32b53847 --- /dev/null +++ b/Kernel/platform-rc2014/README @@ -0,0 +1,48 @@ +--- README for RC2014 --- +This is Fuzix for the RC2014 + +Imported into the current tree from Scott Baker's git tree and adjusted to +build against a current kernel. Don't blame Scott for any bugs! + +Modified for RC2014 with FlashROM/Ram board by Scott Baker . + +Heavily based on prior work by Will Sowerbutts , +Sergey Kiselev , and others. + +Supported Hardware + + * The Flash ROM / RAM board is required. This board is basically a clone of + the memory management subsystem of the Zeta V2. It replaces the RC2014's + default ROM and RAM boards. + + * A serial IO board is required. This can either be an SIO/2 board or a + 68B50 ACIA board. The 68B50 ACIA is the one that comes standard with the + RC2014 kit. + + * VFD Display. If config.h:CONFIG_VFD_TERM is defined, then the VFD Terminal + will be supported. This will display all output to the serial port on the + VFD. If it's defined and you don't have a VFD, then it probably won't hurt + anything, other than some useless io to ports 0-3. + +Notes + + * This platform is based heavily on the Zeta V2 platform, so consult the + Zeta V2 readme for more instructions. This instructions are intentionally + minimal, focusing on items specific to the RC2014 configuration. + +Configuration + + * Make sure to edit config.h and kernel.def to specify whether you are + using SIO/2 or ACIA. + + * The Makefile assumes a file system image exists in ../rc2014_root_fs. + See the Zeta V2 instructions for building a filesystem. + +Things that don't work + + * The RC2014 doesn't come with a clock. I added fakeclock.c, which is a + clock that always returns 0. + + * I couldn't get the WD37C65 floppy to work. + + * Flow control isn't yet enabled for the serial port. diff --git a/Kernel/platform-rc2014/bootrom.s b/Kernel/platform-rc2014/bootrom.s new file mode 100644 index 00000000..0cfe86fc --- /dev/null +++ b/Kernel/platform-rc2014/bootrom.s @@ -0,0 +1,59 @@ +; +; ROM boot for FUZIX on the RC2014 +; + .module bootrom + .include "kernel.def" + + .area _LOADER (ABS) + .org 0x0000 +start: + ; map ROM page 0 to bank #0 and enable paging + di ; better be safe than sorry + xor a + out (MPGSEL_0),a ; map page 0 (ROM) to bank #0 + ld a,#1 + out (MPGENA),a ; enable paging + + ; copy FUZIX kernel to RAM + ; 4 pages, starting from ROM page 0, RAM page 32 + xor a +kernel_copy: + out (MPGSEL_1),a ; map ROM page to bank #1 + add #32 ; RAM page = ROM page + 32 + out (MPGSEL_2),a ; map RAM page to bank #2 + ld hl,#0x4000 ; source - bank #1 offset + ld de,#0x8000 ; destination - bank #2 offset + ld bc,#0x4000 ; count - 16 KiB + ldir ; copy it + sub a,#31 ; next ROM page = RAM page - 32 + 1 + cp #4 ; are we there yet (RAM page == 4?) + jr nz,kernel_copy + +;; ; copy data to RAM disk +;; ; 16 pages, starting from ROM page 4, RAM page 48 +;; ld a,#4 +;; ramdisk_copy: +;; out (MPGSEL_1),a ; map ROM page to bank #1 +;; add #44 ; RAM page = ROM page + 44 +;; out (MPGSEL_2),a ; map RAM page to bank #2 +;; ld hl,#0x4000 ; source - bank #1 offset +;; ld de,#0x8000 ; destination - bank #2 offset +;; ld bc,#0x4000 ; count - 16 KiB +;; ldir ; copy it +;; sub #43 ; next ROM page = RAM page - 44 + 1 +;; cp #20 ; are we there yet (RAM page == 4 + 16?) +;; jr nz,ramdisk_copy +;; + ; scary... switching memory bank under our feet + ld a,#32 ; map page 32 (RAM) to bank 0 + out (MPGSEL_0),a + inc a ; map page 33 (RAM+16k) to bank 1 + out (MPGSEL_1),a + inc a ; map page 34 (RAM+32K) to bank 2 + out (MPGSEL_2),a + inc a ; map page 35 (RAM+48K) to bank 3 + out (MPGSEL_3),a + + jp 0x8B ; jump to init_from_rom in crt0 +; pad + .ds (0x88-(.-start)) diff --git a/Kernel/platform-rc2014/commonmem.s b/Kernel/platform-rc2014/commonmem.s new file mode 100644 index 00000000..12884457 --- /dev/null +++ b/Kernel/platform-rc2014/commonmem.s @@ -0,0 +1,9 @@ +; +; Common is placed at 0xF000 by fuzix.lnk +; + + .module commonmem + + .area _COMMONMEM + + .include "../cpu-z80/std-commonmem.s" diff --git a/Kernel/platform-rc2014/config.h b/Kernel/platform-rc2014/config.h new file mode 100644 index 00000000..e560250f --- /dev/null +++ b/Kernel/platform-rc2014/config.h @@ -0,0 +1,100 @@ +/* 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 +/* Flexible 4x16K banking */ +#define CONFIG_BANK16 +/* Permit large I/O requests to bypass cache and go direct to userspace */ +#define CONFIG_LARGE_IO_DIRECT +/* 32 x 16K pages, 3 pages for kernel, whatever the RAM disk uses */ +#define MAX_MAPS (32 - 3 - DEV_RD_RAM_PAGES) + +/* Banks as reported to user space */ +#define CONFIG_BANKS 4 + +#define TICKSPERSEC 20 /* Ticks per second */ +#define PROGBASE 0x0000 /* also data base */ +#define PROGLOAD 0x0100 /* also data base */ +#define PROGTOP 0xF000 /* Top of program, base of U_DATA copy */ +#define KERNTOP 0xC000 /* Top of kernel (first 3 banks), base of shared bank */ +#define PROC_SIZE 64 /* Memory needed per process */ + +/* WRS: this is probably wrong -- we want to swap the full 64K minus the common code */ +/* For now let's just use something and fix this up later when we have a swap device */ +#define SWAP_SIZE 0x7F /* 63.5K in blocks (which is the wrong number) */ +#define SWAPBASE 0x0000 /* start at the base of user mem */ +#define SWAPTOP 0xFF00 /* can we stop at the top? not sure how. let's stop short. */ +#define MAX_SWAPS 10 /* Well, that depends really, hmmmmmm. Pick a number, any number. */ + +/* We need a tidier way to do this from the loader */ +#define CMDLINE NULL /* Location of root dev name */ +#define BOOTDEVICENAMES "hd#,fd,,rd" + +//#define SWAPDEV (256 + 1) /* Device for swapping */ +#define CONFIG_DYNAMIC_BUFPOOL /* we expand bufpool to overwrite the _DISCARD segment at boot */ +#define NBUFS 4 /* Number of block buffers, keep in line with space reserved in zeta-v2.s */ +#define NMOUNTS 4 /* Number of mounts at a time */ + +#define MAX_BLKDEV 4 /* 1 ROM disk, 1 RAM disk, 1 floppy, 1 PPIDE */ + +#if 0 /* for now */ +/* On-board DS1302, we can read the time of day from it */ +#define CONFIG_RTC +#define CONFIG_RTC_INTERVAL 30 /* deciseconds between reading RTC seconds counter */ +#endif + +/* Floppy support */ +#define CONFIG_FLOPPY /* #define CONFIG_FLOPPY to enable floppy */ + +/* Optional ParPortProp board connected to PPI */ +//#define CONFIG_PPP /* #define CONFIG_PPP to enable as tty3 */ + +#define CONFIG_SIO /* #define CONFIG_SIO to enable SIO support */ +//#define CONFIG_ACIA /* #define CONFIG_SIO to enable ACIA support */ + +#define CONFIG_VFD_TERM /* #define CONFIG_VFD_TERM to show console output on VFD display */ + +// sanity check +#ifdef CONFIG_SIO +#ifdef CONFIG_ACIA +#error "please define either CONFIG_SIO or CONFIG_ACIA but not both" +#endif +#endif + +/* Device parameters */ +#define CONFIG_DEV_MEM /* enable /dev/mem driver */ + +#define CONFIG_RAMDISK /* enable memory-backed disk driver */ +#define DEV_RD_ROM_PAGES 28 /* size of the ROM disk in 16KB pages (max 32, any unused pages are at the start of the ROM) */ +#define DEV_RD_RAM_PAGES 0 /* size of the RAM disk in 16KB pages */ + +#define DEV_RD_ROM_START ((uint32_t)(32-DEV_RD_ROM_PAGES) << 14) /* first byte used by the ROM disk */ +#define DEV_RD_RAM_START ((uint32_t)(64-DEV_RD_RAM_PAGES) << 14) /* first byte used by the RAM disk */ +#define DEV_RD_ROM_SIZE ((uint32_t)DEV_RD_ROM_PAGES << 14) /* size of the ROM disk */ +#define DEV_RD_RAM_SIZE ((uint32_t)DEV_RD_RAM_PAGES << 14) /* size of the RAM disk */ + +#ifdef CONFIG_PPP + /* SD card in ParPortProp */ + #define CONFIG_SD + #define SD_DRIVE_COUNT 1 + #define NUM_DEV_TTY 3 + + /* ParPortProp as the console */ + #define BOOT_TTY (512 + 3) +#else + #define NUM_DEV_TTY 2 + + /* UART0 as the console */ + #define BOOT_TTY (512 + 1) + #define TTY_INIT_BAUD B38400 +#endif + +#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ diff --git a/Kernel/platform-rc2014/crt0.s b/Kernel/platform-rc2014/crt0.s new file mode 100644 index 00000000..7183d9c6 --- /dev/null +++ b/Kernel/platform-rc2014/crt0.s @@ -0,0 +1,114 @@ +; 2015-02-20 Sergey Kiselev +; 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 _HOME ; compiler stores __mullong etc in here if you use them + .area _CODE2 + .area _CONST + .area _INITIALIZED + .area _DATA + .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 _BUFFERS ; _BUFFERS grows to consume all before it (up to KERNTOP) + .area _INITIALIZER ; binman copies this to the right place for us + .area _GSINIT ; unused + .area _GSFINAL ; unused + .area _DISCARD + .area _COMMONMEM + + ; exported symbols + .globl init + .globl init_from_rom + .globl _boot_from_rom + + ; imported symbols + .globl _fuzix_main + .globl init_hardware + .globl s__INITIALIZER + .globl s__COMMONMEM + .globl l__COMMONMEM + .globl s__DISCARD + .globl l__DISCARD + .globl s__DATA + .globl l__DATA + .globl kstack_top + + .include "kernel.def" + + ; startup code + .area _CODE +init: ; must be at 0x88 -- warm boot methods enter here + xor a + jr init_common +init_from_rom: ; must be at 0x8B -- bootrom.s enters here + ld a, #1 + ; fall through +init_common: + di + ld (_boot_from_rom), a + or a + jr nz, mappedok ; bootrom.s loads us in the correct pages + + ; move kernel to the correct location in RAM + ; note that this cannot cope with kernel images larger than 48KB + ld hl, #0x0000 + ld a, #32 ; first page of RAM is page 32 +movenextbank: + out (MPGSEL_3), a ; map page at 0xC000 upwards + ld de, #0xC000 + ld bc, #0x4000 ; copy 16KB + ldir + inc a + cp #35 ; done three pages? + jr nz, movenextbank + + ; setup the memory paging for kernel + out (MPGSEL_3), a ; map page 35 at 0xC000 + ld a, #32 + out (MPGSEL_0), a ; map page 32 at 0x0000 + inc a + out (MPGSEL_1), a ; map page 33 at 0x4000 + inc a + out (MPGSEL_2), a ; map page 34 at 0x8000 + +mappedok: + ; switch to stack in high memory + ld sp, #kstack_top + + ; move the common memory where it belongs + ld hl, #s__DATA + ld de, #s__COMMONMEM + ld bc, #l__COMMONMEM + ldir + ; and the discard + ld de, #s__DISCARD + ld bc, #l__DISCARD + ldir + ; then 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 + + ; fuzix_main() shouldn't return, but if it does... + di +stop: halt + jr stop + +_boot_from_rom: .db 0 diff --git a/Kernel/platform-rc2014/devices.c b/Kernel/platform-rc2014/devices.c new file mode 100644 index 00000000..63bbb7d1 --- /dev/null +++ b/Kernel/platform-rc2014/devices.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct devsw dev_tab[] = /* The device driver switch table */ +{ +/* open close read write ioctl */ + /* 0: /dev/hd - block device interface */ +#ifdef CONFIG_PPIDE + { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl}, +#else + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl}, +#endif + /* 1: /dev/fd - Floppy disk block devices */ +#ifdef CONFIG_FLOPPY + { fd_open, fd_close, fd_read, fd_write, no_ioctl}, +#else + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl}, +#endif + /* 2: /dev/tty -- serial ports */ + { tty_open, tty_close, tty_read, tty_write, tty_ioctl}, + /* 3: RAM disk */ +#ifdef CONFIG_RAMDISK + { rd_open, no_close, rd_read, rd_write, no_ioctl}, +#else + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl}, +#endif + /* 4: /dev/mem etc System devices (one offs) */ + { no_open, no_close, sys_read, sys_write, sys_ioctl}, +}; + +bool validdev(uint16_t dev) +{ + /* This is a bit uglier than needed but the right hand side is + a constant this way */ + if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) + 255) + return false; + else + return true; +} diff --git a/Kernel/platform-rc2014/devrd_zeta2.c b/Kernel/platform-rc2014/devrd_zeta2.c new file mode 100644 index 00000000..9588060e --- /dev/null +++ b/Kernel/platform-rc2014/devrd_zeta2.c @@ -0,0 +1,45 @@ +/* Zeta SBC V2 memory driver + * + * 2017-01-03 William R Sowerbutts, based on RAM disk code by Sergey Kiselev + */ + +#include +#include +#include +#define DEVRD_PRIVATE +#include "devrd.h" + +void rd_page_copy(void); // devrd_zeta2_hw.s + +void rd_platform_copy(void) +{ + uint16_t ocount, count, maxcpy; + + ocount = count = rd_cpy_count; + + while(true){ + /* ensure transfer will not span a 16KB bank boundary */ + maxcpy = ((uint16_t)rd_src_address) & 0x3FFF; + if((rd_dst_address & 0x3FFF) > maxcpy) + maxcpy = rd_dst_address & 0x3FFF; + maxcpy = 0x4000 - maxcpy; + if(rd_cpy_count > maxcpy) + rd_cpy_count = maxcpy; +#ifdef DEBUG + kprintf("rd_transfer: src=0x%lx, dst=0x%x(%s) reverse=%d count=%d\n", + rd_src_address, rd_dst_address, rd_dst_userspace?"user":"kern", + rd_reverse, rd_cpy_count); +#endif + rd_page_copy(); + + count -= rd_cpy_count; + if(!count) + break; + + rd_dst_address += rd_cpy_count; + rd_src_address += rd_cpy_count; + rd_cpy_count = count; + } + + rd_cpy_count = ocount; +} diff --git a/Kernel/platform-rc2014/devrd_zeta2_hw.s b/Kernel/platform-rc2014/devrd_zeta2_hw.s new file mode 100644 index 00000000..05b2f861 --- /dev/null +++ b/Kernel/platform-rc2014/devrd_zeta2_hw.s @@ -0,0 +1,141 @@ + .module devrd_hw + + ; imported symbols + .globl map_kernel, mpgsel_cache, _kernel_pages + .globl _rd_platform_copy + + ; exported symbols + .globl _rd_page_copy + .globl _rd_cpy_count + .globl _rd_reverse + .globl _rd_dst_userspace + .globl _rd_dst_address + .globl _rd_src_address + .globl _devmem_read + .globl _devmem_write + + .include "../kernel.def" + .include "kernel.def" + + .area _CODE +_devmem_write: + ld a, #1 + ld (_rd_reverse), a ; 1 = write + jr _devmem_go + +_devmem_read: + xor a + ld (_rd_reverse), a ; 0 = read + inc a +_devmem_go: + ld (_rd_dst_userspace), a ; 1 = userspace + ; load the other parameters + ld hl, (U_DATA__U_BASE) + ld (_rd_dst_address), hl + ld hl, (U_DATA__U_OFFSET) + ld (_rd_src_address), hl + ld hl, (U_DATA__U_OFFSET+2) + ld (_rd_src_address+2), hl + ld hl, (U_DATA__U_COUNT) + ld (_rd_cpy_count), hl + ; for single byte transfers we can optimise away the outer loop + dec l ; test for HL=1 + ld a, h + or l + jp nz, _rd_platform_copy ; > 1 byte, do it the hard way + call _rd_page_copy ; transfer single byte + ld hl, #1 ; return with HL set appropriately + ret + + .area _COMMONMEM +;========================================================================= +; _rd_page_copy - Copy data from one physical page to another +; See notes in devrd.h for input parameters +;========================================================================= +_rd_page_copy: + ; split rd_src_address into page and offset -- it's limited to 20 bits (max 0xFFFFF) + ; example address 0x000ABCDE + ; in memory it is stored: DE BC 0A 00 + ; offset would be 0x0ABCDE & 0x3FFF = 0x3CDE + ; page would be 0x0ABCDE >> 14 = 0x2A + + ; compute source page number + ld a,(_rd_src_address+1) ; load 0xBC -> B + ld b, a + ld a,(_rd_src_address+2) ; load 0x0A -> A + rl b ; grab the top bit into carry + rla ; shift accumulator left, load carry bit at the bottom + rl b ; and again + rla ; now A is the page number (0x2A) + + ; map source page + ld (mpgsel_cache+1),a ; save the mapping + out (MPGSEL_1),a ; map source page to bank #1 + + ; compute source page offset, store in DE + ld a,(_rd_src_address+1) + and #0x3F ; mask to 16KB + or #0x40 ; add offset for bank 1 + ld d, a + ld a,(_rd_src_address+0) + ld e, a ; now offset is in DE + + ; compute destination page index (addr 0xABCD >> 14 = 0x02) + ld a,(_rd_dst_address+1) ; load top 8 bits + and #0xc0 ; mask off top 2 bits + rlca ; rotate into lower 2 bits + rlca + ld b, #0 + ld c, a ; store in l + + ; look up page number + ld a,(_rd_dst_userspace) ; are we loading into userspace memory? + or a + jr nz, rd_translate_userspace + ld hl, #_kernel_pages ; get kernel page table + jr rd_do_translate +rd_translate_userspace: + ld hl, #U_DATA__U_PAGE ; get user process page table +rd_do_translate: + add hl, bc ; add index to base ptr (uint8_t *) + ld a, (hl) ; load the page number from the page table + + ; map destination page + ld (mpgsel_cache+2),a ; save the mapping + out (MPGSEL_2),a ; map destination page to bank #2 + + ; compute destination page offset, store in HL + ld a,(_rd_dst_address+1) + and #0x3F ; mask to 16KB + or #0x80 ; add offset for bank #2 + ld h, a + ld a, (_rd_dst_address+0) + ld l, a ; now offset is in HL + + ; load byte count + ld bc,(_rd_cpy_count) ; bytes to copy + + ; check if reversed + ld a, (_rd_reverse) + or a + jr nz, go + ex de,hl ; reverse if necessary +go: + ldir ; do the copy + jp map_kernel ; map back the kernel + +; variables +_rd_cpy_count: + .dw 0 ; uint16_t +_rd_reverse: + .db 0 ; bool +_rd_dst_userspace: + .db 0 ; bool +_rd_dst_address: + .dw 0 ; uint16_t +_rd_src_address: + .db 0 ; uint32_t + .db 0 + .db 0 + .db 0 +;========================================================================= diff --git a/Kernel/platform-rc2014/devtty.c b/Kernel/platform-rc2014/devtty.c new file mode 100644 index 00000000..2b47b7de --- /dev/null +++ b/Kernel/platform-rc2014/devtty.c @@ -0,0 +1,155 @@ +#include +#include +#include +#include +#include +#include +#include +#include "vfd-term.h" +#include "vfd-debug.h" + +char tbuf1[TTYSIZ]; +char tbuf2[TTYSIZ]; + +#ifdef CONFIG_PPP +char tbufp[TTYSIZ]; +#endif + +unsigned char sio_type; + +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}, +#ifdef CONFIG_PPP + {tbufp, tbufp, tbufp, TTYSIZ, 0, TTYSIZ/2}, +#endif +}; + +void tty_setup(uint8_t minor) +{ + if (minor == 1) { + } +} + +int tty_carrier(uint8_t minor) +{ +// uint8_t c; + if (minor == 1) { +// c = UART0_MSR; +// return (c & 0x80) ? 1 : 0; /* test DCD */ + } + return 1; +} + +void tty_pollirq_sio(void) +{ + uint8_t ca, cb; + + SIOA_C = 0; // read register 0 + ca = SIOA_C; + if (ca & 1) { + tty_inproc(1, SIOA_D); + } + if (ca & 4) { + tty_outproc(1); + SIOA_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending + } + + SIOB_C = 0; // read register 0 + cb = SIOB_C; + if (cb & 1) { + tty_inproc(2, SIOB_D); + } + if (cb & 4) { + tty_outproc(2); + SIOB_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending + } +} + +void tty_pollirq_acia(void) +{ + uint8_t ca; + + ca = ACIA_C; + if (ca & 1) { + tty_inproc(1, ACIA_D); + } + if (ca & 2) { + tty_outproc(1); + } +} + +#ifdef CONFIG_PPP +void tty_poll_ppp(void) +{ + while(PROPIO2_STAT & 0x20) + tty_inproc(3, PROPIO2_TERM); +} +#endif + +void tty_putc(uint8_t minor, unsigned char c) +{ +// while (tty_writeready(minor) != TTY_READY_NOW) ; + if (minor == 1) { +#ifdef CONFIG_SIO + SIOA_D = c; +#endif +#ifdef CONFIG_ACIA + ACIA_D = c; +#endif +#ifdef CONFIG_VFD_TERM + vfd_term_write(c); +#endif + } else if (minor == 2) { + SIOB_D = c; +#ifdef CONFIG_PPP + } else if (minor = 3) { + /* FIXME: implement */ +#endif + } +} + +void tty_sleeping(uint8_t minor) +{ + if (minor == 1) { +// UART0_IER = 0x0B; /* enable all but LSR interrupt */ + } +} + +ttyready_t tty_writeready(uint8_t minor) +{ + uint8_t c; + if (minor == 1) { +#ifdef CONFIG_SIO + SIOA_C = 0; // read register 0 + c = SIOA_C; + if (c & 0x04) /* THRE? */ + return TTY_READY_NOW; + return TTY_READY_SOON; +#endif +#ifdef CONFIG_ACIA + c = ACIA_C; + if (c & 0x02) /* THRE? */ + return TTY_READY_NOW; + return TTY_READY_SOON; +#endif + } else if (minor == 2) { +#ifdef CONFIG_SIO + SIOB_C = 0; // read register 0 + c = SIOB_C; + if (c & 0x04) /* THRE? */ + return TTY_READY_NOW; + return TTY_READY_SOON; +#endif + } + return TTY_READY_NOW; +} + +/* kernel writes to system console -- never sleep! */ +void kputchar(char c) +{ + tty_putc(TTYDEV - 512, c); + if(c == '\n') + tty_putc(TTYDEV - 512, '\r'); +} diff --git a/Kernel/platform-rc2014/devtty.h b/Kernel/platform-rc2014/devtty.h new file mode 100644 index 00000000..e88fb5ef --- /dev/null +++ b/Kernel/platform-rc2014/devtty.h @@ -0,0 +1,16 @@ +#ifndef __DEVTTY_DOT_H__ +#define __DEVTTY_DOT_H__ + +#define SIO_SIO 1 + +void tty_putc(uint8_t minor, unsigned char c); +void tty_pollirq_sio(void); +void tty_pollirq_acia(void); + +void sio_init(void); +void acia_init(void); + +#ifdef CONFIG_PPP +void tty_poll_ppp(void); +#endif +#endif diff --git a/Kernel/platform-rc2014/devtty_discard.c b/Kernel/platform-rc2014/devtty_discard.c new file mode 100644 index 00000000..989d99f6 --- /dev/null +++ b/Kernel/platform-rc2014/devtty_discard.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include +#include +#include + +extern unsigned char sio_type; + +/* uart0_init - detect UART type, print it, enable FIFO if present + */ +void sio_init(void) { + kprintf("UART0 type: SIO/2.\n"); +} + +void acia_init(void) { + kprintf("UART0 type: ACIA.\n"); +} + + diff --git a/Kernel/platform-rc2014/discard.c b/Kernel/platform-rc2014/discard.c new file mode 100644 index 00000000..74f3fef6 --- /dev/null +++ b/Kernel/platform-rc2014/discard.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include "config.h" +#include "devrd.h" +#include "vfd-term.h" + +/* Everything in here is discarded after init starts */ + +#ifdef CONFIG_PPIDE +#include +void ppide_init(void); +#endif + +void init_hardware_c(void) +{ +// vfd_debug_init(); +#ifdef CONFIG_VFD_TERM + vfd_term_init(); +#endif + ramsize = 512; + procmem = 512 - 64 - (DEV_RD_RAM_PAGES<<4); + /* zero out the initial bufpool */ + memset(bufpool, 0, (char*)bufpool_end - (char*)bufpool); +} + +void pagemap_init(void) +{ + int i; + + /* ZETA SBC V2 has RAM in the top 512 KiB of physical memory + * corresponding pages are 32-63 (page size is 16 KiB) + * Pages 32-34 are used by the kernel + * Page 35 is the common area + * Pages starting from DEV_RD_START are used by RAM disk + */ + for (i = 32 + 4; i < (DEV_RD_RAM_START >> 14); i++) + pagemap_add(i); + + /* finally add the common area */ + pagemap_add(32 + 3); +} + +void map_init(void) +{ +} + +void device_init(void) +{ +#ifdef CONFIG_SIO + sio_init(); +#endif +#ifdef CONFIG_ACIA + acia_init(); +#endif +#ifdef CONFIG_PPIDE + ppide_init(); + devide_init(); +#endif +} diff --git a/Kernel/platform-rc2014/diskboot.s b/Kernel/platform-rc2014/diskboot.s new file mode 100644 index 00000000..9b57d5e9 --- /dev/null +++ b/Kernel/platform-rc2014/diskboot.s @@ -0,0 +1,197 @@ +; 2015-01-21 Will Sowerbutts +; +; Boot sector for N8VEM Mark IV SBC with UNA BIOS, based on +; my UNA CP/M boot sector (2014-07-11) + + .module diskboot + + +; we are loaded at 0x8000 +himem = 0xFA00 ; our location in memory +buffer = 0xF800 ; disk buffer (512 bytes) +stacktop = 0xFE00 ; top of stack (512 bytes) + +; UNA BIOS constants +UNABIOS_STUB_ENTRY = 0xFFFD ; main UNA entry vector +UNABIOS_BOOTHISTORY = 0xFC ; C register (subfunction in B) +UNABIOS_BOOT_GET = 0x00 ; B register (BOOTHISTORY subfunction) +UNABIOS_GETINFO = 0xFA ; C regsister (subfunction in B) +UNABIOS_GET_USER_PAGES = 0x05 ; B register (GETINFO subfunction) +UNABIOS_BANKEDMEM = 0xFB ; C register (subfunction in B) +UNABIOS_BANK_GET = 0x00 ; B register (BANKEDMEM subfunction) +UNABIOS_BANK_SET = 0x01 ; B register (BANKEDMEM subfunction) +UNABIOS_GET_HMA = 0xF1 ; C register (subfunction in B) +UNABIOS_BLOCK_SETLBA = 0x41 ; C register (unit number in B, 28-bit LBA in DEHL) +UNABIOS_BLOCK_READ = 0x42 ; C register (unit number in B, buffer address in DE, sector count in L) +UNABIOS_OUTPUT_WRITE = 0x12 ; C register (unit number in B) + + .area _LOADER (ABS) + .org himem +start: + ; UNA BIOS loads us from disk sector 0 at 0x8000 + jr gocopy ; we must start with a JP or JR instruction. + .ds 0x40 - (.-start) ; must leave room for floppy or partition superblock information + + ; Copy us up into high memory +gocopy: ld hl, #0x8000 + ld de, #himem + ld bc, #512 + ldir + jp go + + ; Executes in high memory +go: ld sp, #stacktop ; set inital stack + ; write a character + ld e, #0x5B ; '[' + call printchar + + ; determine the boot unit + ld bc, #(UNABIOS_BOOT_GET << 8 | UNABIOS_BOOTHISTORY) + call #UNABIOS_STUB_ENTRY + ld a, l + ld (unit), a ; save boot unit + + ; get the page number for the user memory bank + ld bc, #(UNABIOS_GET_USER_PAGES << 8 | UNABIOS_GETINFO) + call #UNABIOS_STUB_ENTRY + ; returns EXEC_PAGE value in DE + + ; map in user memory bank + ld bc, #(UNABIOS_BANK_SET << 8 | UNABIOS_BANKEDMEM) + call #UNABIOS_STUB_ENTRY + + ; write unabios vector in user memory + ld hl, #UNABIOS_STUB_ENTRY + ld de, #0x0008 + ld bc, #3 + ldir + + ; wipe BDOS entry vector + ld a, #0x76 ; halt instruction + ld (0x0005), a ; this is used as a marker to detect cold boot versus warm reload + + ; wipe persistent memory pointer (persist_ptr, immediately below UNA UBIOS stub / HMA) + ld c, #UNABIOS_GET_HMA ; get pointer to lowest byte used by UNA BIOS stub + call #UNABIOS_STUB_ENTRY ; returns lowest used byte in HL. + xor a ; zero out the two bytes below that. + dec hl + ld (hl), a + dec hl + ld (hl), a + + ld a, (firstblock) + ld (block), a + +nextblock: + ; print a = character only every other block + ld a, (block) + and #1 + jr z, setlba + ld e, #0x3D ; '=' + call printchar + +setlba: ; set LBA + xor a + ld d, a + ld e, a + ld h, a + ld a, (block) + ld l, a + inc a ; setup for next block now + ld (block), a + ld c, #UNABIOS_BLOCK_SETLBA + ld a, (unit) + ld b, a + call #UNABIOS_STUB_ENTRY + jr nz, error + + ; read block into buffer + ld c, #UNABIOS_BLOCK_READ + ld a, (unit) + ld b, a + ld l, #1 + ld de, #buffer + call #UNABIOS_STUB_ENTRY + jr nz, error + + ; copy block into low memory + ld hl, #buffer + ld de, (copyaddr) + ld bc, #512 + ldir + + ld (copyaddr), de + ld a, (firstblock) + ld d, a + ld a, (count) + ld e, a + ld a, (block) + sub d + cp e + jr nz, nextblock + + ld e, #0x5D ; ']' + call printchar + ld e, #0x0D + call printchar + ld e, #0x0A + call printchar + + ; we're loaded. let's go. + ld hl, (entryaddr) + jp (hl) + + +; print a hex byte in A +byt_out: + push af ; save low nibble + rrca ; move high nibble into position + rrca ; ** + rrca + rrca + call nib_out ; put out the high nibble + pop af ; fall into nib_out to put out low nibble +; print a hex-nibble in A +nib_out: + and #0x0F ; mask the nibble + add #0 ; clear the AUX carry bit + daa ; decimal adjust the A + add #0xF0 ; move hi-nib into carry, hi-nib is 0 or F + adc #0x40 ; form ascii character + ld e, a + ; fall through into printchar +printchar: + ld bc, #UNABIOS_OUTPUT_WRITE + jp UNABIOS_STUB_ENTRY + +error: + ; print the error + ld a, c + call byt_out + ld e, a + call printchar + + ; sad face :( + ld e, #0x20 ; space + call printchar + ld e, #0x3A ; ':' + call printchar + ld e, #0x28 ; '(' + call printchar + + ; park the vehicle + halt + +block: .ds 1 +unit: .ds 1 +firstblock: .db 2 ; start loading at sector 2 +count: .db 124 ; max sectors we can load before we overwrite ourselves (62KB) +copyaddr: .dw 0x0088 ; load address +entryaddr: .dw 0x0088 ; entry address + + .ds 0x1BE - ( . -start) ; pad to start of partition tables + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; partition 1 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; partition 2 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; partition 3 + .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; partition 4 + .dw 0xAA55 ; DOS boot signature diff --git a/Kernel/platform-rc2014/fuzix.lnk b/Kernel/platform-rc2014/fuzix.lnk new file mode 100644 index 00000000..890d55c4 --- /dev/null +++ b/Kernel/platform-rc2014/fuzix.lnk @@ -0,0 +1,50 @@ +-mwxuy +-i fuzix.ihx +-b _CODE=0x0088 +-b _COMMONMEM=0xF000 +-b _DISCARD=0xE000 +-l z80 +platform-rc2014/crt0.rel +platform-rc2014/commonmem.rel +platform-rc2014/rc2014.rel +platform-rc2014/vfd-debug.rel +platform-rc2014/vfdterm.rel +platform-rc2014/vfd-term.rel +start.rel +version.rel +lowlevel-z80.rel +platform-rc2014/tricks.rel +platform-rc2014/main.rel +timer.rel +kdata.rel +platform-rc2014/devfd.rel +platform-rc2014/devfd_hw.rel +platform-rc2014/devrd.rel +platform-rc2014/devrd_hw.rel +platform-rc2014/devrd_zeta2.rel +platform-rc2014/devrd_zeta2_hw.rel +platform-rc2014/devices.rel +devio.rel +filesys.rel +process.rel +inode.rel +syscall_exec16.rel +syscall_fs.rel +syscall_proc.rel +syscall_fs2.rel +syscall_fs3.rel +syscall_other.rel +mm.rel +swap.rel +bank16k.rel +tty.rel +devsys.rel +usermem.rel +usermem_std-z80.rel +platform-rc2014/discard.rel +platform-rc2014/devtty.rel +platform-rc2014/devtty_discard.rel +platform-rc2014/mbr.rel +platform-rc2014/blkdev.rel +platform-rc2014/monitor.rel +-e diff --git a/Kernel/platform-rc2014/kernel.def b/Kernel/platform-rc2014/kernel.def new file mode 100644 index 00000000..2b2864eb --- /dev/null +++ b/Kernel/platform-rc2014/kernel.def @@ -0,0 +1,48 @@ +; UZI mnemonics for memory addresses etc + +U_DATA .equ 0xF000 ; (this is struct u_data from kernel.h) +U_DATA__TOTALSIZE .equ 0x300 ; 256+256+256 bytes. +Z80_TYPE .equ 0 ; just a old good Z80 +USE_FANCY_MONITOR .equ 1 ; disabling this saves around approx 0.5KB + +Z80_MMU_HOOKS .equ 0 + +PROGBASE .equ 0x0000 +PROGLOAD .equ 0x0100 + +; Zeta SBC V2 mnemonics for I/O ports etc + +CONSOLE_RATE .equ 38400 + +CPU_CLOCK_KHZ .equ 7372 + +; VFD Debugging +VFD_C .EQU 0 ; control register +VFD_D .EQU 1 ; data register + +; Z80 CTC ports +CTC_CH0 .equ 0x90 ; CTC channel 0 and interrupt vector +CTC_CH1 .equ 0x91 ; CTC channel 1 (periodic interrupts) +CTC_CH2 .equ 0x92 ; CTC channel 2 (UART interrupt) +CTC_CH3 .equ 0x93 ; CTC channel 3 (PPI interrupt) + +; 37C65 FDC ports +FDC_CCR .equ 0x48 ; Configuration Control Register (W/O) +FDC_MSR .equ 0x50 ; 8272 Main Status Register (R/O) +FDC_DATA .equ 0x51 ; 8272 Data Port (R/W) +FDC_DOR .equ 0x58 ; Digital Output Register (W/O) +FDC_TC .equ 0x58 ; Pulse terminal count (R/O) + +; MMU Ports +MPGSEL_0 .equ 0x78 ; Bank_0 page select register (W/O) +MPGSEL_1 .equ 0x79 ; Bank_1 page select register (W/O) +MPGSEL_2 .equ 0x7A ; Bank_2 page select register (W/O) +MPGSEL_3 .equ 0x7B ; Bank_3 page select register (W/O) +MPGENA .equ 0x7C ; memory paging enable register, bit 0 (W/O) + +; Define which serial device to use +; NOTE: Make sure this agrees with CONFIG_SIO and CONFIG_ACIA +; in config.h +CONFIG_SIO .equ 1 +CONFIG_ACIA .equ 0 + diff --git a/Kernel/platform-rc2014/main.c b/Kernel/platform-rc2014/main.c new file mode 100644 index 00000000..83972ee7 --- /dev/null +++ b/Kernel/platform-rc2014/main.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include "config.h" +#ifdef CONFIG_FLOPPY +#include +#endif + +extern unsigned char irqvector; +struct blkbuf *bufpool_end = bufpool + NBUFS; /* minimal for boot -- expanded after we're done with _DISCARD */ + +void platform_discard(void) +{ + while(bufpool_end < (struct blkbuf*)(KERNTOP - sizeof(struct blkbuf))){ + memset(bufpool_end, 0, sizeof(struct blkbuf)); +#if BF_FREE != 0 + bufpool_end->bf_busy = BF_FREE; /* redundant when BF_FREE == 0 */ +#endif + bufpool_end->bf_dev = NO_DEVICE; + bufpool_end++; + } +} + +void platform_idle(void) +{ + /* Let's go to sleep while we wait for something to interrupt us; + * Makes the HALT LED go yellow, which amuses me greatly. */ + __asm + halt + __endasm; +} + +uint8_t platform_param(unsigned char *p) +{ + used(p); + return 0; +} + +void platform_interrupt(void) +{ + switch(irqvector) { + case 1: +#ifdef CONFIG_PPP + tty_poll_ppp() +#endif +#ifdef CONFIG_FLOPPY + fd_tick(); +#endif + timer_interrupt(); + return; + + case 4: +#ifdef CONFIG_SIO + tty_pollirq_sio(); +#endif + return; + case 0x38: +#ifdef CONFIG_ACIA + tty_pollirq_acia(); +#endif + return; + default: + return; + } +} diff --git a/Kernel/platform-rc2014/monitor.s b/Kernel/platform-rc2014/monitor.s new file mode 100644 index 00000000..5a18d1a8 --- /dev/null +++ b/Kernel/platform-rc2014/monitor.s @@ -0,0 +1,37 @@ +; 2015-01-17 William R Sowerbutts + + .module monitor + .include "kernel.def" + .globl _platform_monitor + .globl map_kernel + +; ----------------------------------------------------------------------------- +.ifne USE_FANCY_MONITOR ; ----------------------------------------------------- + .area _CODE ; actual monitor lives in kernel bank + .include "../lib/monitor-z80.s" + + .area _COMMONMEM ; just a stub goes in common memory +_platform_monitor: + di + call map_kernel + jp monitor_entry + + +; ----------------------------------------------------------------------------- +.else ; MICRO MONITOR --------------------------------------------------------- + .globl outchar + .globl outnewline + .globl outhl + + .area _COMMONMEM +_platform_monitor: di + call outnewline + ; just dump a few words from the stack + ld b, #50 +stacknext: pop hl + call outhl + ld a, #' ' + call outchar + djnz stacknext + halt +.endif diff --git a/Kernel/platform-rc2014/platform_ide.h b/Kernel/platform-rc2014/platform_ide.h new file mode 100644 index 00000000..95d67e15 --- /dev/null +++ b/Kernel/platform-rc2014/platform_ide.h @@ -0,0 +1,38 @@ +#ifdef CONFIG_PPIDE +#define PPIDE_BASE 0x60 /* Base address of 8255A */ +#define IDE_REG_INDIRECT /* IDE registers are not directly connected to the CPU bus */ + +/* IDE control signal to 8255 port C mapping */ +#define PPIDE_A0_LINE 0x01 // Direct from 8255 to IDE interface +#define PPIDE_A1_LINE 0x02 // Direct from 8255 to IDE interface +#define PPIDE_A2_LINE 0x04 // Direct from 8255 to IDE interface +#define PPIDE_CS0_LINE 0x08 // Inverter between 8255 and IDE interface +#define PPIDE_CS1_LINE 0x10 // Inverter between 8255 and IDE interface +#define PPIDE_WR_LINE 0x20 // Inverter between 8255 and IDE interface +#define PPIDE_WR_BIT 5 // (1 << PPIDE_WR_BIT) = PPIDE_WR_LINE +#define PPIDE_RD_LINE 0x40 // Inverter between 8255 and IDE interface +#define PPIDE_RD_BIT 6 // (1 << PPIDE_RD_BIT) = PPIDE_RD_LINE +#define PPIDE_RST_LINE 0x80 // Inverter between 8255 and IDE interface + +/* 8255 configuration */ +#define PPIDE_PPI_BUS_READ 0x92 +#define PPIDE_PPI_BUS_WRITE 0x80 + +/* IDE register addresses */ +#define ide_reg_data (PPIDE_CS0_LINE) +#define ide_reg_error (PPIDE_CS0_LINE | PPIDE_A0_LINE) +#define ide_reg_features (PPIDE_CS0_LINE | PPIDE_A0_LINE) +#define ide_reg_sec_count (PPIDE_CS0_LINE | PPIDE_A1_LINE) +#define ide_reg_lba_0 (PPIDE_CS0_LINE | PPIDE_A1_LINE | PPIDE_A0_LINE) +#define ide_reg_lba_1 (PPIDE_CS0_LINE | PPIDE_A2_LINE) +#define ide_reg_lba_2 (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A0_LINE) +#define ide_reg_lba_3 (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE) +#define ide_reg_devhead (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE) +#define ide_reg_command (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE | PPIDE_A0_LINE) +#define ide_reg_status (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE | PPIDE_A0_LINE) +#define ide_reg_altstatus (PPIDE_CS1_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE) +#define ide_reg_control (PPIDE_CS1_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE | PPIDE_A0_LINE) +#endif /* CONFIG_PPIDE */ + +#define ide_select(x) +#define ide_deselect() diff --git a/Kernel/platform-rc2014/ppide.c b/Kernel/platform-rc2014/ppide.c new file mode 100644 index 00000000..4e80bf1b --- /dev/null +++ b/Kernel/platform-rc2014/ppide.c @@ -0,0 +1,121 @@ +/* 2015-04-24 WRS: devide glue functions for PPIDE */ + +#include +#include +#include +#include +#include +#include +#include + +__sfr __at (PPIDE_BASE + 0x00) ppi_port_a; /* IDE bus LSB */ +__sfr __at (PPIDE_BASE + 0x01) ppi_port_b; /* IDE bus MSB */ +__sfr __at (PPIDE_BASE + 0x02) ppi_port_c; /* IDE bus control signals */ +__sfr __at (PPIDE_BASE + 0x03) ppi_control; /* 8255 command register */ + +void ppide_init(void) +{ + ppi_control = PPIDE_PPI_BUS_READ; + ppi_port_c = ide_reg_status; +} + +uint8_t devide_readb(uint8_t regaddr) +{ + uint8_t r; + + /* note: ppi_control should contain PPIDE_PPI_BUS_READ already */ + ppi_port_c = regaddr; + ppi_control = 1 | (PPIDE_RD_BIT << 1); /* begin /RD pulse */ + r = ppi_port_a; + ppi_control = 0 | (PPIDE_RD_BIT << 1); /* end /RD pulse */ + return r; +} + +void devide_writeb(uint8_t regaddr, uint8_t value) +{ + ppi_control = PPIDE_PPI_BUS_WRITE; + ppi_port_c = regaddr; + ppi_port_a = value; + ppi_port_b = 0; + ppi_control = 1 | (PPIDE_WR_BIT << 1); /* begin /WR pulse */ + ppi_control = 0 | (PPIDE_WR_BIT << 1); /* end /WR pulse */ + ppi_control = PPIDE_PPI_BUS_READ; +} + +/****************************************************************************/ +/* The innermost part of the transfer routines has to live in common memory */ +/* since it must be able to bank switch to the user memory bank. */ +/****************************************************************************/ +COMMON_MEMORY + +void devide_read_data(void) __naked +{ + __asm + ld a, #ide_reg_data + ld c, #PPIDE_BASE+2 ; select control lines + out (c), a ; select IDE data register + ld hl, (_blk_op+BLKPARAM_ADDR_OFFSET) ; blkparam.addr + ld d, #ide_reg_data ; register address + ld e, #ide_reg_data | PPIDE_RD_LINE ; register address with /RD asserted + ld b, #0 ; setup count + ld a, (_blk_op+BLKPARAM_IS_USER_OFFSET) ; blkparam.is_user + or a ; test is_user + push af ; save flags + ld a, #PPIDE_BASE+0 ; I will be needing this later + call nz, map_process_always ; map user memory first if required +goread: ; now we do the transfer + out (c), e ; assert /RD + ld c, a ; PPIDE_BASE + ini ; read byte from LSB + inc c ; up to MSB + ini ; read byte from MSB + inc c ; control lines + out (c), d ; de-assert /RD + inc b ; (delay) counteract second ini instruction + jr nz, goread ; (delay) next word + ; read completed + pop af ; recover is_user test result + ret z ; done if kernel memory transfer + jp map_kernel ; else map kernel then return + __endasm; +} + +void devide_write_data(void) __naked +{ + __asm + ld c, #PPIDE_BASE+2 ; select control lines + ld a, #ide_reg_data + out (c), a ; select data register + ld a, #PPIDE_PPI_BUS_WRITE + inc c ; up to 8255A command register + out (c), a ; 8255A ports A, B to output mode + dec c ; back down to the control lines + ld hl, (_blk_op+BLKPARAM_ADDR_OFFSET) ; blkparam.addr + ld d, #ide_reg_data ; register address + ld e, #ide_reg_data | PPIDE_WR_LINE ; register address with /WR asserted + ld b, #0 ; setup count + ld a, (_blk_op+BLKPARAM_IS_USER_OFFSET) ; blkparam.is_user + or a ; test is_user + push af ; save flags + ld a, #PPIDE_BASE+0 ; I will be needing this later + call nz, map_process_always ; map user memory first if required +gowrite: ; now we do the transfer + out (c), d ; de-assert /WR + ld c, a ; PPIDE_BASE + outi ; write byte to LSB + inc c ; up to MSB + outi ; write byte to MSB + inc c ; up to control lines + out (c), e ; assert /WR + inc b ; (delay) offset to counteract second outi instruction + jr nz, gowrite ; (delay) next word + ; write completed + out (c), d ; de-assert /WR + ld a, #PPIDE_PPI_BUS_READ + inc c ; up to 8255A command register + out (c), a ; 8255A ports A, B to read mode + pop af ; recover is_user test result + ret z ; done if kernel memory transfer + jp map_kernel ; else map kernel then return + __endasm; +} diff --git a/Kernel/platform-rc2014/rc2014.h b/Kernel/platform-rc2014/rc2014.h new file mode 100644 index 00000000..1cb65e6d --- /dev/null +++ b/Kernel/platform-rc2014/rc2014.h @@ -0,0 +1,24 @@ +#ifndef __RC2014_SIO_DOT_H__ +#define __RC2014_SIO_DOT_H__ + +#include "config.h" + +#define SIO0_IVT 8 + +#define SIO0_BASE 0x80 +__sfr __at (SIO0_BASE + 0) SIOA_D; +__sfr __at (SIO0_BASE + 2) SIOA_C; +__sfr __at (SIO0_BASE + 1) SIOB_D; +__sfr __at (SIO0_BASE + 3) SIOB_C; + +/* ACIA is at same address as SIO. Assume CONFIG_ACIA or CONFIG_SIO has been + defined in config.h, but not both. +*/ + +#define ACIA_BASE 0x80 +__sfr __at (ACIA_BASE + 0) ACIA_C; +__sfr __at (ACIA_BASE + 1) ACIA_D; + +extern bool boot_from_rom; + +#endif diff --git a/Kernel/platform-rc2014/rc2014.s b/Kernel/platform-rc2014/rc2014.s new file mode 100644 index 00000000..0cdbfe15 --- /dev/null +++ b/Kernel/platform-rc2014/rc2014.s @@ -0,0 +1,496 @@ +; 2014-02-19 Sergey Kiselev +; RC2014 hardware specific code + + .module zeta_v2 + + ; exported symbols + .globl init_hardware + .globl _program_vectors + .globl map_kernel + .globl map_process + .globl map_process_always + .globl map_save + .globl map_restore + .globl _irqvector + .globl platform_interrupt_all + .globl mpgsel_cache + .globl _kernel_pages + .globl _platform_reboot + .globl _bufpool + + ; imported symbols + .globl _ramsize + .globl _procmem + .globl _init_hardware_c + .globl outhl + .globl outnewline + .globl interrupt_handler + .globl unix_syscall_entry + .globl nmi_handler + .globl null_handler + .globl _boot_from_rom + + ; exported debugging tools + .globl inchar + .globl outchar + + .include "kernel.def" + .include "../kernel.def" + +;========================================================================= +; Constants +;========================================================================= +CONSOLE_DIVISOR .equ (1843200 / (16 * CONSOLE_RATE)) +CONSOLE_DIVISOR_HIGH .equ (CONSOLE_DIVISOR >> 8) +CONSOLE_DIVISOR_LOW .equ (CONSOLE_DIVISOR & 0xFF) + +RTS_HIGH .EQU 0xE8 +RTS_LOW .EQU 0xEA + +SIOA_D .EQU 0x80 ; Base address of SIO/2 chip +SIOA_C .EQU SIOA_D+2 +SIOB_D .EQU SIOA_D+1 +SIOB_C .EQU SIOA_D+3 + +SIO_IV .EQU 8 ; Interrupt vector table entry to use + +ACIA_C .EQU 0x80 +ACIA_D .EQU 0x81 +ACIA_RESET .EQU 0x03 +ACIA_RTS_HIGH_A .EQU 0xD6 ; rts high, xmit interrupt disabled +ACIA_RTS_LOW_A .EQU 0x96 ; rts low, xmit interrupt disabled +;ACIA_RTS_LOW_A .EQU 0xB6 ; rts low, xmit interrupt enabled + +;========================================================================= +; Buffers +;========================================================================= + .area _BUFFERS +_bufpool: + .ds (BUFSIZE * 4) ; adjust NBUFS in config.h in line with this + +;========================================================================= +; Initialization code +;========================================================================= + .area _DISCARD +init_hardware: + ; program vectors for the kernel + ld hl, #0 + push hl + call _program_vectors + pop hl + + ; Stop floppy drive motors + ld a, #0x0C + out (FDC_DOR), a + + ; initialize UART0 + ld a, (_boot_from_rom) ; do not set the baud rate and other + or a ; serial line parameters if the BIOS + jr z, init_partial_uart ; already set them for us. + ; nothing to do here yet +init_partial_uart: + +.if CONFIG_SIO + LD A,#0x00 + OUT (SIOA_C),A + LD A,#0x18 + OUT (SIOA_C),A + + LD A,#0x04 + OUT (SIOA_C),A + LD A,#0xC4 + OUT (SIOA_C),A + + LD A,#0x01 + OUT (SIOA_C),A + LD A,#0x1A ; Receive int mode 11, tx int enable (was $18) + OUT (SIOA_C),A + + LD A,#0x03 + OUT (SIOA_C),A + LD A,#0xE1 + OUT (SIOA_C),A + + LD A,#0x05 + OUT (SIOA_C),A + LD A,#RTS_LOW + OUT (SIOA_C),A + + LD A,#0x00 + OUT (SIOB_C),A + LD A,#0x18 + OUT (SIOB_C),A + + LD A,#0x04 + OUT (SIOB_C),A + LD A,#0xC4 + OUT (SIOB_C),A + + LD A,#0x01 + OUT (SIOB_C),A + LD A, #0x1A ; Receive int mode 11, tx int enable (was $18) + OUT (SIOB_C),A + + LD A,#0x02 + OUT (SIOB_C),A + LD A,#SIO_IV ; INTERRUPT VECTOR ADDRESS + OUT (SIOB_C),A + + LD A,#0x03 + OUT (SIOB_C),A + LD A,#0xE1 + OUT (SIOB_C),A + + LD A,#0x05 + OUT (SIOB_C),A + LD A,#RTS_LOW + OUT (SIOB_C),A + + ; --------------------------------------------------------------------- + ; Initialize CTC + ; Only supported for SIO, since CTC must operate in IM2. + ; If you don't have a CTC probably nothing bad will happen, other than + ; your floppy not working. + + ld a,#0x57 ; counter mode, disable interrupts + out (CTC_CH0),a ; set CH0 mode + ld a,#0 ; time constant = 256 + out (CTC_CH0),a ; set CH0 time constant + ld a,#0xC7 ; counter mode, enable interrupts + out (CTC_CH1),a ; set CH1 mode + ld a,#180 ; time constant = 180 + out (CTC_CH1),a ; set CH1 time constant + +; ld a,#0xD7 ; counter mode, rising edge +; ; enable interrupts +; out (CTC_CH2),a ; set CH2 mode +; ld a,#1 ; time constant = 1 +; out (CTC_CH2),a ; set CH2 time constant +; ; FIXME: should use interrupts when PPP firmware allows it +; ld a,#0x37 ; timer mode for now, disable interrupts +; out (CTC_CH3),a +; ld a,#0 ; time constant = 256 +; out (CTC_CH3),a ; set CH3 time constant + + ld hl,#intvectors + ld a,l + and #0xF8 ; get bits 7-3 of int. vectors table + out (CTC_CH0),a ; send it to CTC + + ; Done CTC Stuff + ; --------------------------------------------------------------------- + + ld hl,#intvectors + ld a,h ; get bits 15-8 of int. vectors table + ld i,a ; load to I register + im 2 ; set Z80 CPU interrupt mode 2 +.endif + +.if CONFIG_ACIA + LD A, #ACIA_RESET + OUT (ACIA_C),A + LD A, #ACIA_RTS_LOW_A + OUT (ACIA_C),A ; Initialise ACIA + + im 1 +.endif + + jp _init_hardware_c ; pass control to C, which returns for us + +;========================================================================= +; Kernel code +;========================================================================= + .area _CODE + +_platform_reboot: + ; We need to map the ROM back in -- ideally into every page. + ; This little trick based on a clever suggestion from John Coffman. + di + ld hl, #(MPGENA << 8) | 0xD3 ; OUT (MPGENA), A + ld (0xFFFE), hl ; put it at the very top of RAM + xor a ; A=0 + jp 0xFFFE ; execute it; PC then wraps to 0 + + +;========================================================================= +; Common Memory (0xF000 upwards) +;========================================================================= + .area _COMMONMEM + +;========================================================================= +; Interrupt stuff +;========================================================================= +; IM2 interrupt verctors table +; Note: this is linked after the udata block, so it is aligned on 256 byte +; boundary +intvectors: + .dw ctc0_int ; CTC CH0 used as prescaler for CH1 + .dw ctc1_int ; timer interrupt handler + .dw serial_int ; UART interrupt handler + .dw ppi_int ; PPI interrupt handler + .dw sio_int ; SIO interrupt handler + +_irqvector: + .db 0 ; used to identify interrupt vector + +; CTC CH0 shouldn't be used to generate interrupts +; but we'll implement it just in case +ctc0_int: + push af + xor a ; IRQ vector = 0 + ld (_irqvector),a ; store it + pop af + jp interrupt_handler + +; periodic timer interrupt +ctc1_int: + push af + ld a,#1 ; IRQ vector = 1 + ld (_irqvector),a ; store it + pop af + jp interrupt_handler + +; UART interrupt +serial_int: + push af + ld a,#2 ; IRQ vector = 2 + ld (_irqvector),a ; store it + pop af + jp interrupt_handler + +; PPI interrupt - not used for now +ppi_int: + push af + ld a,#3 ; IRQ vector = 3 + ld (_irqvector),a ; store it + pop af + jp interrupt_handler + +; SIO interrupt +sio_int: + push af + ld a,#4 ; IRQ vector = 4 + ld (_irqvector),a ; store it + pop af + jp interrupt_handler + +; int38h handler +; Calls interrupt_handler with irqvector of 0x38 +; For SIO/2, nothing will happen, since it uses IM2 +; For ACIA, serial interrupt handler will execute +int38h_int: + push af + LD A, #'B' + OUT (VFD_D),A + ld a,#0x38 ; not a real vector, just a signal that the 0x38h occurred + ld (_irqvector),a ; store it + pop af + jp interrupt_handler + +platform_interrupt_all: + ret + +; install interrupt vectors +_program_vectors: + di + pop de ; temporarily store return address + pop hl ; function argument -- base page number + push hl ; put stack back as it was + push de + + ; At this point the common block has already been copied + 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,#int38h_int + 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 + + 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 + +;========================================================================= +; Memory management +; - kernel pages: 32 - 34 +; - common page: 35 +; - user space pages: 36 - 63 +;========================================================================= + +;========================================================================= +; map_process_always - map process pages +; Inputs: page table address in #U_DATA__U_PAGE +; Outputs: none; all registers preserved +;========================================================================= +map_process_always: + push hl + ld hl,#U_DATA__U_PAGE + jr map_process_2_pophl_ret + +;========================================================================= +; map_process - map process or kernel pages +; Inputs: page table address in HL, map kernel if HL == 0 +; Outputs: none; A and HL destroyed +;========================================================================= +map_process: + ld a,h + or l ; HL == 0? + jr nz,map_process_2 ; HL == 0 - map the kernel + +;========================================================================= +; map_kernel - map kernel pages +; Inputs: none +; Outputs: none; all registers preserved +;========================================================================= +map_kernel: + push hl + ld hl,#_kernel_pages + jr map_process_2_pophl_ret + +;========================================================================= +; map_process_2 - map process or kernel pages +; Inputs: page table address in HL +; Outputs: none, HL destroyed +;========================================================================= +map_process_2: + push de + push af + ld de,#mpgsel_cache ; paging registers are write only + ; so cache their content in RAM + ld a,(hl) ; memory page number for bank #0 + ld (de),a + out (MPGSEL_0),a ; set bank #0 + inc hl + inc de + ld a,(hl) ; memory page number for bank #1 + ld (de),a + out (MPGSEL_1),a ; set bank #1 + inc hl + inc de + ld a,(hl) ; memory page number for bank #2 + ld (de),a + out (MPGSEL_2),a ; set bank #2 + pop af + pop de + ret + +;========================================================================= +; map_restore - restore a saved page mapping +; Inputs: none +; Outputs: none, all registers preserved +;========================================================================= +map_restore: + push hl + ld hl,#map_savearea +map_process_2_pophl_ret: + call map_process_2 + pop hl + ret + +;========================================================================= +; map_save - save the current page mapping to map_savearea +; Inputs: none +; Outputs: none +;========================================================================= +map_save: + push hl + ld hl,(mpgsel_cache) + ld (map_savearea),hl + ld hl,(mpgsel_cache+2) + ld (map_savearea+2),hl + pop hl + ret + +; MPGSEL registers are read only, so their content is cached here +mpgsel_cache: + .db 0,0,0,0 + +; kernel page mapping +_kernel_pages: + .db 32,33,34,35 + +; memory page mapping save area for map_save/map_restore +map_savearea: + .db 0,0,0,0 + +;========================================================================= +; Basic console I/O +;========================================================================= + +;========================================================================= +; outchar - Wait for UART TX idle, then print the char in A +; Inputs: A - character to print +; Outputs: none +;========================================================================= +outchar: + +.if CONFIG_SIO + push af + ; wait for transmitter to be idle +ocloop_sio: + xor a ; read register 0 + out (SIOA_C), a + in a,(SIOA_C) ; read Line Status Register + and #0x04 ; get THRE bit + jr z,ocloop_sio + ; now output the char to serial port + pop af + out (SIOA_D),a +.endif + +.if CONFIG_ACIA + push af + ; wait for transmitter to be idle +ocloop_acia: + in a,(ACIA_C) ; read Line Status Register + and #0x02 ; get THRE bit + jr z,ocloop_acia + ; now output the char to serial port + pop af + out (ACIA_D),a +.endif + + out (VFD_D),a + ret + +;========================================================================= +; inchar - Wait for character on UART, return in A +; Inputs: none +; Outputs: A - received character, F destroyed +;========================================================================= +inchar: +.if CONFIG_SIO + xor a ; read register 0 + out (SIOA_C), a + in a,(SIOA_C) ; read Line Status Register + and #0x01 ; test if data is in receive buffer + jp z,inchar ; no data, wait + in a,(SIOA_D) ; read the character from the UART +.endif + +.if CONFIG_ACIA + in a,(ACIA_C) ; read Line Status Register + and #0x01 ; test if data is in receive buffer + jp z,inchar ; no data, wait + in a,(ACIA_D) ; read the character from the UART +.endif + ret diff --git a/Kernel/platform-rc2014/target.mk b/Kernel/platform-rc2014/target.mk new file mode 100644 index 00000000..3bffcde0 --- /dev/null +++ b/Kernel/platform-rc2014/target.mk @@ -0,0 +1 @@ +export CPU = z80 diff --git a/Kernel/platform-rc2014/tricks.s b/Kernel/platform-rc2014/tricks.s new file mode 100644 index 00000000..6e8917f9 --- /dev/null +++ b/Kernel/platform-rc2014/tricks.s @@ -0,0 +1,235 @@ +; 2013-12-21 William R Sowerbutts + + .module tricks + + .globl _ptab_alloc + .globl _newproc + .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 mpgsel_cache + + ; 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 +; +; FIXME: do we actually *need* to restore the stack ! +; + push de ; restore stack + push bc ; restore stack + + ld hl, #P_TAB__P_PAGE_OFFSET+3 ; Common + add hl, de ; process ptr + ld a, (hl) + out (MPGSEL_3), a ; *CAUTION* our stack just left the building + + ; ------- No stack ------- + ; 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 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) + 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, (fork_proc_ptr) + push hl + call _newproc + 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: + ld a,(hl) + out (MPGSEL_1), a ; 0x4000 map the child + ld c, a + inc hl + ld a, (de) + out (MPGSEL_2), a ; 0x8000 maps the parent + 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 + call map_kernel ; put the maps back so we can look in p_tab + djnz fork_next + ld a, c + ld (mpgsel_cache+3),a ; cache the page number + out (MPGSEL_3), a ; our last bank repeats up to common + ; --- we are now on the stack copy, parent stack is locked away --- + ret ; this stack is copied so safe to return on + + diff --git a/Kernel/platform-rc2014/vfd-debug.c b/Kernel/platform-rc2014/vfd-debug.c new file mode 100644 index 00000000..acdf6a10 --- /dev/null +++ b/Kernel/platform-rc2014/vfd-debug.c @@ -0,0 +1,10 @@ +#include "vfd-debug.h" + +void vfd_debug_init(void) { + VFD_C = 0x30; + VFD_D = 0; + VFD_C = 1; + VFD_C = 0x0F; + VFD_D = '>'; +} + diff --git a/Kernel/platform-rc2014/vfd-debug.h b/Kernel/platform-rc2014/vfd-debug.h new file mode 100644 index 00000000..2a16b024 --- /dev/null +++ b/Kernel/platform-rc2014/vfd-debug.h @@ -0,0 +1,13 @@ +#ifndef __VFD_DEBUG_DOT_H__ +#define __VFD_DEBUG_DOT_H__ + +#include "config.h" + +__sfr __at (0) VFD_C; +__sfr __at (1) VFD_D; + +void vfd_debug_init(void); + +#define vprtch(c) VFD_D=(c); + +#endif diff --git a/Kernel/platform-rc2014/vfd-term.c b/Kernel/platform-rc2014/vfd-term.c new file mode 100644 index 00000000..1d74ea64 --- /dev/null +++ b/Kernel/platform-rc2014/vfd-term.c @@ -0,0 +1,18 @@ +#include "vfd-term.h" + +void vfd_term_init(void) { + __asm + call VFDTERM_PREINIT + __endasm; +} + +void vfd_term_write(char c) { + __asm + ld hl, #2+0 + add hl, sp + ld e, (hl) + call VFDTERM_PUTC + __endasm; + (void)c; // suppress error +} + diff --git a/Kernel/platform-rc2014/vfd-term.h b/Kernel/platform-rc2014/vfd-term.h new file mode 100644 index 00000000..89e4450f --- /dev/null +++ b/Kernel/platform-rc2014/vfd-term.h @@ -0,0 +1,9 @@ +#ifndef __VFD_TERM_DOT_H__ +#define __VFD_TERM_DOT_H__ + +#include "config.h" + +void vfd_term_init(void); +void vfd_term_write(char c); + +#endif diff --git a/Kernel/platform-rc2014/vfdterm.s b/Kernel/platform-rc2014/vfdterm.s new file mode 100644 index 00000000..1450a1b6 --- /dev/null +++ b/Kernel/platform-rc2014/vfdterm.s @@ -0,0 +1,191 @@ + .module vfdterm + + .include "kernel.def" + .include "../kernel.def" + + .globl VFDTERM_PREINIT + .globl VFDTERM_PUTC + +;------------------------ +; VFD dumb terminal +;------------------------ + +VFDTERM_C0 .EQU 0 +VFDTERM_D0 .EQU 1 +VFDTERM_C1 .EQU 2 +VFDTERM_D1 .EQU 3 + + .area _DATA +vfdPtr: .DW 0 +vfdLen: .DB 0 +vfdLine1: .DW 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +vfdLine2: .DW 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +vfdLine3: .DW 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +vfdLine4: .DW 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + +vfdLineLen .EQU 40 + + + .area _CODE +VFDTERM_PREINIT: + ; initialize first two lines + LD A, #0x30 + OUT (VFDTERM_C0), A + LD A, #0 + OUT (VFDTERM_D0), A + LD A, #1 + OUT (VFDTERM_C0), A + LD A, #0x0C ; display on, cursor off + OUT (VFDTERM_C0), A + + ; initialize second two lines + LD A, #0x30 + OUT (VFDTERM_C1), A + LD A, #0 + OUT (VFDTERM_D1), A + LD A, #1 + OUT (VFDTERM_C1), A + LD A, #0x0F ; display on, cursor on + OUT (VFDTERM_C1), A + + ; position to start of last line + CALL VFDTERM_SOL + RET + + ; assume character in E +VFDTERM_PUTC: PUSH AF + PUSH BC + PUSH DE + PUSH HL + + LD A,E + CP #0x08 + JR Z, VFDTERM_BSPC + CP #0x0A ; line feed + JR Z, VFDTERM_NEWLINE + CP #0x0D ; CR + JR Z, VFDTERM_CR + +VFDTERM_STOREC: LD A, E ; write the character to the vfd + OUT (VFDTERM_D1), A + + LD HL, (vfdPtr) ; update pointer + LD (HL), E + INC HL + LD (vfdPtr), HL + + LD A, (vfdLen) ; update position index + INC A + LD (vfdLen), A + + LD A, (vfdLen) ; check if we just wrapped + CP #vfdLineLen + JR NZ, VFDTERM_PUTC_OUT + +VFDTERM_NEWLINE: + CALL VFDTERM_SCROLL + CALL VFDTERM_REDRAW + CALL VFDTERM_SOL + JR VFDTERM_PUTC_OUT + +VFDTERM_BSPC: LD A, (vfdLen) + CP #0x00 + JR Z, VFDTERM_PUTC_OUT ; at beginning of buffer, no-op + + DEC A ; decrement line len + LD (vfdLen), A + LD HL, (vfdPtr) ; decrement ptr + DEC HL + LD (vfdPtr), HL + + LD A, #0x10 ; shift cursor left one place + OUT (VFDTERM_C1), A + + JR VFDTERM_PUTC_OUT + +VFDTERM_CR: CALL VFDTERM_SOL + JR VFDTERM_PUTC_OUT + +VFDTERM_PUTC_OUT: + POP HL + POP DE + POP BC + POP AF + RET + + ; scroll the buffer up one line +VFDTERM_SCROLL: + LD HL, #vfdLine2 + LD DE, #vfdLine1 + LD BC, #120 + LDIR ; do the move + LD HL, #vfdLine4 ; clear the last line of the buffer + LD BC, #vfdLineLen + LD A, #' ' + CALL UTIL_FILL + RET + +UTIL_FILL: + LD D,H ; SET DE TO HL + LD E,L ; SO DESTINATION EQUALS SOURCE + LD (HL),A ; FILL THE FIRST BYTE WITH DESIRED VALUE + INC DE ; INCREMENT DESTINATION + DEC BC ; DECREMENT THE COUNT + LDIR ; DO THE REST + RET ; RETURN + + ; move pointer to start of 4th line +VFDTERM_SOL: + LD HL, #vfdLine4 + LD (vfdPtr), HL + LD A, #0 + LD (vfdLen), A + LD A, #0xC0 ; command to move to start of line 2 + OUT (VFDTERM_C1), A ; send to VFD + RET + +VFDTERM_REDRAW: + LD A, #0x80 ; command to move to start of line 1 + OUT (VFDTERM_C0), A + LD DE, #vfdLine1 + LD C, #vfdLineLen +VFDTERM_REDRAW0: LD A, (DE) + INC DE + OUT (VFDTERM_D0), A + DEC C + JR NZ, VFDTERM_REDRAW0 + + LD A, #0xC0 ; command to move to start of line 2 + OUT (VFDTERM_C0), A + LD DE, #vfdLine2 + LD C, #vfdLineLen +VFDTERM_REDRAW1: LD A, (DE) + INC DE + OUT (VFDTERM_D0), A + DEC C + JR NZ, VFDTERM_REDRAW1 + + LD A, #0x80 ; command to move to start of line 3 + OUT (VFDTERM_C1), A + LD DE, #vfdLine3 + LD C, #vfdLineLen +VFDTERM_REDRAW2: LD A, (DE) + INC DE + OUT (VFDTERM_D1), A + DEC C + JR NZ, VFDTERM_REDRAW2 + + LD A, #0xC0 ; command to move to start of line 4 + OUT (VFDTERM_C1), A + LD DE, #vfdLine4 + LD C, #vfdLineLen +VFDTERM_REDRAW3: LD A, (DE) + INC DE + OUT (VFDTERM_D1), A + DEC C + JR NZ, VFDTERM_REDRAW3 + + RET + + + -- 2.34.1