From b30ab088efb4835fb044f22eb949260ade9c44ea Mon Sep 17 00:00:00 2001 From: Sergey Kiselev Date: Thu, 5 Mar 2015 10:16:07 -0800 Subject: [PATCH] zeta-v2: Initial support for Zeta SBC V2 platform --- Kernel/Makefile | 7 +- Kernel/platform-zeta-v2/Makefile | 44 ++++ Kernel/platform-zeta-v2/README | 117 +++++++++ Kernel/platform-zeta-v2/bootrom.s | 58 +++++ Kernel/platform-zeta-v2/commonmem.s | 9 + Kernel/platform-zeta-v2/config.h | 73 ++++++ Kernel/platform-zeta-v2/crt0.s | 75 ++++++ Kernel/platform-zeta-v2/devices.c | 39 +++ Kernel/platform-zeta-v2/devrd.c | 121 +++++++++ Kernel/platform-zeta-v2/devrd.h | 10 + Kernel/platform-zeta-v2/devrd_hw.s | 59 +++++ Kernel/platform-zeta-v2/devtty.c | 87 +++++++ Kernel/platform-zeta-v2/devtty.h | 9 + Kernel/platform-zeta-v2/discard.c | 26 ++ Kernel/platform-zeta-v2/ds1302-n8vem.s | 76 ++++++ Kernel/platform-zeta-v2/kernel.def | 60 +++++ Kernel/platform-zeta-v2/main.c | 33 +++ Kernel/platform-zeta-v2/monitor.s | 37 +++ Kernel/platform-zeta-v2/target.mk | 1 + Kernel/platform-zeta-v2/tricks.s | 239 ++++++++++++++++++ Kernel/platform-zeta-v2/zeta-v2.h | 20 ++ Kernel/platform-zeta-v2/zeta-v2.s | 335 +++++++++++++++++++++++++ 22 files changed, 1532 insertions(+), 3 deletions(-) create mode 100644 Kernel/platform-zeta-v2/Makefile create mode 100644 Kernel/platform-zeta-v2/README create mode 100644 Kernel/platform-zeta-v2/bootrom.s create mode 100644 Kernel/platform-zeta-v2/commonmem.s create mode 100644 Kernel/platform-zeta-v2/config.h create mode 100644 Kernel/platform-zeta-v2/crt0.s create mode 100644 Kernel/platform-zeta-v2/devices.c create mode 100644 Kernel/platform-zeta-v2/devrd.c create mode 100644 Kernel/platform-zeta-v2/devrd.h create mode 100644 Kernel/platform-zeta-v2/devrd_hw.s create mode 100644 Kernel/platform-zeta-v2/devtty.c create mode 100644 Kernel/platform-zeta-v2/devtty.h create mode 100644 Kernel/platform-zeta-v2/discard.c create mode 100644 Kernel/platform-zeta-v2/ds1302-n8vem.s create mode 100644 Kernel/platform-zeta-v2/kernel.def create mode 100644 Kernel/platform-zeta-v2/main.c create mode 100644 Kernel/platform-zeta-v2/monitor.s create mode 100644 Kernel/platform-zeta-v2/target.mk create mode 100644 Kernel/platform-zeta-v2/tricks.s create mode 100644 Kernel/platform-zeta-v2/zeta-v2.h create mode 100644 Kernel/platform-zeta-v2/zeta-v2.s diff --git a/Kernel/Makefile b/Kernel/Makefile index 77ecfc37..2e951c9b 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -1,4 +1,4 @@ -TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-zx128 platform-trs80 platform-z80pack platform-z80pack-lite platform-z80pack32 platform-dragon platform-tgl6502 platform-plus3 +TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-zx128 platform-trs80 platform-z80pack platform-z80pack-lite platform-z80pack32 platform-dragon platform-tgl6502 platform-plus3 platform-zeta-v2 #export TARGET = 8086test #export TARGET = atarist @@ -11,14 +11,15 @@ TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 #export TARGET = nc100 #export TARGET = p112 #export TARGET = pcw8256 -export TARGET = plus3 +#export TARGET = plus3 #export TARGET = px4plus #export TARGET = tgl6502 #export TARGET = trs80 #export TARGET = ubee #export TARGET = z80pack #export TARGET = z80pack-lite -#export TARGET= zx128 +#export TARGET = zeta-v2 +#export TARGET = zx128 export VERSION = "0.1" export SUBVERSION = "ac1" diff --git a/Kernel/platform-zeta-v2/Makefile b/Kernel/platform-zeta-v2/Makefile new file mode 100644 index 00000000..210bd684 --- /dev/null +++ b/Kernel/platform-zeta-v2/Makefile @@ -0,0 +1,44 @@ +ASRCS = crt0.s tricks.s commonmem.s zeta-v2.s monitor.s +ASRCS += ds1302-n8vem.s devrd_hw.s +CSRCS = devices.c main.c devtty.c devrd.c +DISCARD_CSRCS = discard.c +DISCARD_DSRCS = ../dev/ds1302_discard.c +DSRCS = ../dev/devsd.c ../dev/mbr.c ../dev/blkdev.c ../dev/ds1302.c + +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)) + +OBJS = $(AOBJS) $(COBJS) $(DOBJS) $(DISCARD_DOBJS) $(DISCARD_COBJS) + +CROSS_CCOPTS += -I../dev/ + +JUNK = *.rel *.lst *.asm *.sym *.rst *.map *.ihx *.bin + +all: $(OBJS) + +$(AOBJS): %.rel: %.s + $(CROSS_AS) $(ASOPTS) $< + +$(COBJS): %.rel: %.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(DOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(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 + +image: + sdasz80 -o bootrom.s + sdldz80 -m -i bootrom.rel + makebin -s 256 bootrom.ihx > bootrom.bin + cat bootrom.bin ../fuzix.bin > ../fuzix.rom diff --git a/Kernel/platform-zeta-v2/README b/Kernel/platform-zeta-v2/README new file mode 100644 index 00000000..4aba9c60 --- /dev/null +++ b/Kernel/platform-zeta-v2/README @@ -0,0 +1,117 @@ +--- README for Zeta SBC V2 --- +This is Fuzix for the Zeta SBV V2 +Written by Sergey Kiselev +Heavily based on prior work by Will Sowerbutts and others + +Supported hardware: + - RAM disk + - RS232 serial port (16550 UART, tty1) + - Real time clock (should be, not tested) + +Memory allocation (16 KiB pages): +- ROM pages: 0 - 31 + - Kernel image: 0 - 2 - copied by bootrom.s to pages 32 - 34 + - RAM disk image: 3 - 19 - copied by bootrom.s to pages 48 - 63 +- RAM pages: 32 - 63 + - Kernel pages: 32 - 34 + - Common page: 35 + - User space pages: 36 - 47 + - RAM disk: 48 - 63 + +To build the kernel, edit the TARGET line in Kernel/Makefile to read: + export TARGET = zeta-v2 +Then run "make clean; make all" in the "Kernel" directory. + +Currently the system can be booted from the Flash ROM. Use the following steps +to build the Flash ROM image: + +1. Build the kernel (see above) +2. Build the userspace utils (needs to be documented) +3. [In FUZIX/Kernel dir] Create a 256 KiB filesystem image: + ../Standalone/mkfs zeta_v2_rootfs.img 16 512 +4. Populate the filesystem image + ../Standalone/ucp zeta_v2_rootfs.img + +run the following ucp commands: + +mkdir bin +chmod 0755 bin +mkdir etc +chmod 0755 etc +mkdir dev +chmod 0755 dev +mkdir tmp +chmod 01777 tmp +mkdir usr +chmod 0755 usr +mkdir usr/lib +chmod 0755 usr/lib +mkdir root +chmod 0700 root +cd /dev +mknod tty1 20660 513 +mknod tty2 20660 514 +mknod tty3 20660 515 +mknod tty4 20660 516 +mknod hda 60660 0 +mknod hda1 60660 1 +mknod fd0 60660 256 +mknod fd1 60660 257 +mknod null 20666 1024 +mknod mem 20660 1025 +mknod zero 20444 1026 +mknod proc 20660 1027 +cd / +bget ../Applications/util/init +chmod 0755 init +cd /etc +bget passwd +chmod 0644 passwd +cd /bin +bget ../Applications/util/cat +chmod 0755 cat +bget ../Applications/util/cp +chmod 0755 cp +bget ../Applications/util/date +chmod 0755 date +bget ../Applications/util/df +chmod 0755 df +bget ../Applications/util/echo +chmod 0755 echo +bget ../Applications/util/fdisk +chmod 0755 fdisk +bget ../Applications/util/fsck +chmod 0755 fsck +bget ../Applications/util/ln +chmod 0755 ln +bget ../Applications/util/ls +chmod 0755 ls +bget ../Applications/util/mkdir +chmod 0755 mkdir +bget ../Applications/util/mkfs +chmod 0755 mkfs +bget ../Applications/util/mount +chmod 0755 mount +bget ../Applications/util/mv +chmod 0755 mv +bget ../Applications/util/passwd +chmod 0755 passwd +bget ../Applications/util/rm +chmod 0755 rm +bget ../Applications/util/rmdir +chmod 0755 rmdir +bget ../Applications/util/ssh +chmod 0755 ssh +bget ../Applications/util/umount +chmod 0755 umount +exit + +5. Create ROM image: +dd if=fuzix.rom of=fuzix_48k.rom bs=48k count=1 conv=syn +cat fuzix_48k.rom zeta_v2_rootfs.img > fuzix_zeta_v2_bootfs.rom + +6. Program the image (fuzix_zeta_v2_bootfs.rom) to the Flash ROM using an +EPROM programmer + +7. Power on the the system. Enter device number 256 to boot from the RAM disk. + diff --git a/Kernel/platform-zeta-v2/bootrom.s b/Kernel/platform-zeta-v2/bootrom.s new file mode 100644 index 00000000..ee95c879 --- /dev/null +++ b/Kernel/platform-zeta-v2/bootrom.s @@ -0,0 +1,58 @@ +; +; ROM boot for FUZIX on the ZETA SBC V2 +; + .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 + ; 3 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 #3 ; are we there yet (RAM page == 3?) + jr nz,kernel_copy + + ; copy data to RAM disk + ; 16 pages, starting from ROM page 3, RAM page 48 + ld a,#3 +ramdisk_copy: + out (MPGSEL_1),a ; map ROM page to bank #1 + add #45 ; RAM page = ROM page + 45 + 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 #44 ; next ROM page = RAM page - 45 + 1 + cp #19 ; are we there yet (RAM page == 3 + 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 0x100 ; jump to crt0.s +; pad + .ds (0x100-(.-start)) diff --git a/Kernel/platform-zeta-v2/commonmem.s b/Kernel/platform-zeta-v2/commonmem.s new file mode 100644 index 00000000..522503a8 --- /dev/null +++ b/Kernel/platform-zeta-v2/commonmem.s @@ -0,0 +1,9 @@ +; +; Common on z80pack is at 0xF000 as defined by hardware. +; + + .module commonmem + + .area _COMMONMEM + + .include "../cpu-z80/std-commonmem.s" diff --git a/Kernel/platform-zeta-v2/config.h b/Kernel/platform-zeta-v2/config.h new file mode 100644 index 00000000..4bcce9f5 --- /dev/null +++ b/Kernel/platform-zeta-v2/config.h @@ -0,0 +1,73 @@ +/* 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, 16 pages for RAM disk */ +#define MAX_MAPS 13 + +/* Banks as reported to user space */ +#define CONFIG_BANKS 4 + +#define TICKSPERSEC 15 /* 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 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 "fd,hd#" + +//#define SWAPDEV (256 + 1) /* Device for swapping */ +#define NBUFS 10 /* Number of block buffers */ +#define NMOUNTS 4 /* Number of mounts at a time */ + +#define MAX_BLKDEV 4 /* 1 ROM disk, 1 RAM disk, 1 floppy, 1 SD card */ + +/* 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 */ + +/* Optional ParPortProp board connected to PPI */ +//#define CONFIG_PPP /* #define CONFIG_PPP to enable as tty3 */ + +/* Device parameters */ +#define NUM_DEV_RD 1 +#define DEV_RD_PAGES 16 /* size of the RAM disk in pages */ +#define DEV_RD_START 48 /* first page used by the RAM disk */ + +#ifdef CONFIG_PPP + /* SD card in ParPortProp */ + #define DEVICE_SD + #define SD_DRIVE_COUNT 1 + #define NUM_DEV_TTY 2 + + /* ParPortProp as the console */ + #define BOOT_TTY (512 + 2) +#else + #define NUM_DEV_TTY 1 + + /* UART0 as the console */ + #define BOOT_TTY (512 + 1) +#endif + +#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ diff --git a/Kernel/platform-zeta-v2/crt0.s b/Kernel/platform-zeta-v2/crt0.s new file mode 100644 index 00000000..a618496c --- /dev/null +++ b/Kernel/platform-zeta-v2/crt0.s @@ -0,0 +1,75 @@ +; 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 _DATA + .area _INITIALIZED + .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 _COMMONMEM + + ; imported symbols + .globl _fuzix_main + .globl init_early + .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: + di + ld sp, #kstack_top + ; move the common memory where it belongs + ld hl, #s__INITIALIZER + 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 + + ; setup the rest of the memory paging + call init_early + + ; 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 diff --git a/Kernel/platform-zeta-v2/devices.c b/Kernel/platform-zeta-v2/devices.c new file mode 100644 index 00000000..fb27ee6b --- /dev/null +++ b/Kernel/platform-zeta-v2/devices.c @@ -0,0 +1,39 @@ +#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/fd - Floppy disk block devices */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl}, + /* 1: /dev/hd - RAM disk interface */ + { rd_open, no_close, rd_read, rd_write, no_ioctl}, + /* 2: /dev/tty -- serial ports */ + { tty_open, tty_close, tty_read, tty_write, tty_ioctl}, + /* 3: unused slot */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl}, + /* 4: /dev/mem etc System devices (one offs) */ + { no_open, no_close, sys_read, sys_write, sys_ioctl}, +}; + +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) +{ + ds1302_init(); +} diff --git a/Kernel/platform-zeta-v2/devrd.c b/Kernel/platform-zeta-v2/devrd.c new file mode 100644 index 00000000..728376de --- /dev/null +++ b/Kernel/platform-zeta-v2/devrd.c @@ -0,0 +1,121 @@ +/* Zeta SBC V2 RAM disk driver + * + * Implements a single RAM disk DEV_RD_PAGES size and + * starting from DEV_RD_START page + * + * */ + +#include +#include +#include + +extern uint8_t src_page; /* source page number */ +extern uint8_t dst_page; /* destination page number */ +extern uint16_t src_offset; /* offset of the data in the source page */ +extern uint16_t dst_offset; /* offset of the data in the destination page */ +extern uint16_t cpy_count; /* data transfer length */ +extern uint8_t kernel_pages[]; /* kernel's page table */ + +int ramdisk_transfer(bool is_read, uint8_t minor, uint8_t rawflag); +int page_copy(void); /* assembler code */ + +int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; + return ramdisk_transfer(true, minor, rawflag); +} + +int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; + return ramdisk_transfer(false, minor, rawflag); +} + +int ramdisk_transfer(bool is_read, uint8_t minor, uint8_t rawflag) +{ + blkno_t block; + int block_xfer; /* r/w return value (number of 512 byte blocks transferred) */ + uint32_t rd_addr; + uint16_t buffer_addr; + usize_t xfer_count; + + if (minor >= NUM_DEV_RD) { + udata.u_error = ENXIO; + return -1; + } + + if (rawflag) { /* rawflag == 1, read to or write from user space */ + xfer_count = udata.u_count; + buffer_addr = (uint16_t) udata.u_base; + block = udata.u_offset >> 9; + block_xfer = xfer_count >> 9; + } else { /* rawflag == 0, read to or write from kernel space */ + xfer_count = 512; + buffer_addr = (uint16_t) udata.u_buf->bf_data; + block = udata.u_buf->bf_blk; + block_xfer = 1; + } + + if (block > (DEV_RD_PAGES * 16 * 2)) { /* block beyond RAM disk end? */ + udata.u_error = EIO; + return -1; + } + + /* calculate physical address of the RAM drive data */ + /* rd_addr = block * 512 + DEV_RD_START * 16K; */ + rd_addr = ((unsigned long) block << 9) + DEV_RD_START * 16384UL; + while (xfer_count > 0) { + if (is_read) { + /* RAM disk page number = rd_addr / 16K */ + src_page = rd_addr >> 14; + /* offset within RAM disk page */ + src_offset = rd_addr & 0x3FFF; + /* destination page number */ + if (rawflag) + dst_page = ((uint8_t *) &udata.u_page)[buffer_addr >> 14]; + else + dst_page = kernel_pages[buffer_addr >> 14]; + /* offset in the destination page */ + dst_offset = buffer_addr & 0x3FFF; + } else { + /* source page number */ + if (rawflag) + src_page = ((uint8_t *) &udata.u_page)[buffer_addr >> 14]; + else + src_page = kernel_pages[buffer_addr >> 14]; + /* offset in the source page */ + src_offset = buffer_addr & 0x3FFF; + /* RAM disk page number = rd_addr / 16K */ + dst_page = rd_addr >> 14; + /* offset within RAM disk page */ + dst_offset = rd_addr & 0x3FFF; + } + cpy_count = xfer_count; + if (cpy_count > 16384 - src_offset) + cpy_count = 16384 - src_offset; + if (cpy_count > 16384 - dst_offset) + cpy_count = 16384 - dst_offset; +#ifdef DEBUG + kprintf("page_cpy(src_page=%x, src_offset=%x, dst_page=%x, dst_offset=%x, cpy_count=%x)\n", src_page, src_offset, dst_page, dst_offset, cpy_count); +#endif + __critical { + page_copy(); + } + xfer_count -= cpy_count; + buffer_addr += cpy_count; + rd_addr += cpy_count; + } + + return block_xfer; +} + + +int rd_open(uint8_t minor) +{ + if(minor < NUM_DEV_RD){ + return 0; + } else { + udata.u_error = EIO; + return -1; + } +} diff --git a/Kernel/platform-zeta-v2/devrd.h b/Kernel/platform-zeta-v2/devrd.h new file mode 100644 index 00000000..e54a1546 --- /dev/null +++ b/Kernel/platform-zeta-v2/devrd.h @@ -0,0 +1,10 @@ +#ifndef __DEVRD_DOT_H__ +#define __DEVRD_DOT_H__ + +/* public interface */ +int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag); +int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag); +int rd_init(void); +int rd_open(uint8_t minor, uint16_t flag); + +#endif /* __DEVRD_DOT_H__ */ diff --git a/Kernel/platform-zeta-v2/devrd_hw.s b/Kernel/platform-zeta-v2/devrd_hw.s new file mode 100644 index 00000000..65a1fd18 --- /dev/null +++ b/Kernel/platform-zeta-v2/devrd_hw.s @@ -0,0 +1,59 @@ + .module devrd_hw + + ; imported symbols - from zeta-v2.s + .globl map_table + + ; exported symbols (used by devrd.c) + .globl _page_copy + .globl _src_page, _src_offset, _dst_page, _dst_offset, _cpy_count + + .include "kernel.def" + + .area _COMMONMEM + +;========================================================================= +; _page_copy - Copy data from one physical page to another +; Inputs: +; _src_page - page number of the source page (uint8_t) +; _src_offset - offset in the source page (uint16_t) +; _dst_page - page number of the destination page (uint8_t) +; _dst_offset - offset in the destination page (uint16_t) +; _cpy_count - number of bytes to copy (uint16_t) +; map_table - current page register values, used to restore paging registers +; Outputs: +; Data copied +; Destroys AF, BC, DE, HL +;========================================================================= +_page_copy: + ld a,(_src_page) + out (MPGSEL_1),a ; map source page to bank #1 + ld a,(_dst_page) + out (MPGSEL_2),a ; map destination page to bank #2 + ld hl,(_src_offset) ; load offset in source page + ld a,#0x40 ; add bank #1 offset - 0x4000 + add h ; to the source offset + ld h,a + ld de,(_dst_offset) + ld a,#0x80 ; add bank #2 offset - 0x8000 + add d ; to the destination offset + ld d,a + ld bc,(_cpy_count) ; bytes to copy + ldir ; do the copy + ld a,(map_table+1) + out (MPGSEL_1),a ; restore the mapping of bank #1 + ld a,(map_table+2) + out (MPGSEL_2),a ; restore the mapping of bank #2 + ret + +; variables +_src_page: + .db 0 +_dst_page: + .db 0 +_src_offset: + .dw 0 +_dst_offset: + .dw 0 +_cpy_count: + .dw 0 +;========================================================================= diff --git a/Kernel/platform-zeta-v2/devtty.c b/Kernel/platform-zeta-v2/devtty.c new file mode 100644 index 00000000..f9ac01be --- /dev/null +++ b/Kernel/platform-zeta-v2/devtty.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include +#include + +char tbuf1[TTYSIZ]; + +#ifdef CONFIG_PPP +char tbufp[TTYSIZ]; +#endif + +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 }, +#ifdef CONFIG_PPP + { tbufp, tbufp, tbufp, TTYSIZ, 0, TTYSIZ/2 }, +#endif +}; + +/* FIXME: implement */ +void tty_setup(uint8_t minor) +{ + minor; +} + +/* FIXME: implement (although /DCD is hardwired to GND) */ +int tty_carrier(uint8_t minor) +{ + minor; + return 1; +} + +void tty_interrupt(void) +{ + uint8_t reg = UART0_LSR; + if (reg & 0x01) { + /* data available */ + reg = UART0_RBR; + tty_inproc(1, reg); + } +} + +#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) +{ + if (minor == 1) { + while(!(UART0_LSR & 0x20)); + UART0_THR = c; +#ifdef CONFIG_PPP + } else if (minor = 2) { + /* FIXME: implement */ +#endif + } +} + +void tty_sleeping(uint8_t minor) +{ + minor; +} + +ttyready_t tty_writeready(uint8_t minor) +{ + uint8_t reg; + if (minor == 1) { + reg = UART0_LSR; + return (reg & 0x20) ? TTY_READY_NOW : TTY_READY_SOON; + } + 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-zeta-v2/devtty.h b/Kernel/platform-zeta-v2/devtty.h new file mode 100644 index 00000000..242631e9 --- /dev/null +++ b/Kernel/platform-zeta-v2/devtty.h @@ -0,0 +1,9 @@ +#ifndef __DEVTTY_DOT_H__ +#define __DEVTTY_DOT_H__ +void tty_putc(uint8_t minor, unsigned char c); +void tty_interrupt(void); + +#ifdef CONFIG_PPP +void tty_poll_ppp(void); +#endif +#endif diff --git a/Kernel/platform-zeta-v2/discard.c b/Kernel/platform-zeta-v2/discard.c new file mode 100644 index 00000000..fca69f88 --- /dev/null +++ b/Kernel/platform-zeta-v2/discard.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include "config.h" + +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_START; i++) + pagemap_add(i); + + /* finally add the common area */ + pagemap_add(32 + 3); +} + +void map_init(void) +{ +} diff --git a/Kernel/platform-zeta-v2/ds1302-n8vem.s b/Kernel/platform-zeta-v2/ds1302-n8vem.s new file mode 100644 index 00000000..d215b82a --- /dev/null +++ b/Kernel/platform-zeta-v2/ds1302-n8vem.s @@ -0,0 +1,76 @@ +; 2015-02-19 Sergey Kiselev +; 2014-12-31 William R Sowerbutts +; N8VEM SBC / Zeta SBC DS1302 real time clock interface code + + .module ds1302-n8vem + + ; exported symbols + .globl _ds1302_set_pin_ce + .globl _ds1302_set_pin_clk + .globl _ds1302_set_pin_data + .globl _ds1302_set_pin_data_driven + .globl _ds1302_get_pin_data + + .include "kernel.def" + .include "../kernel.def" + +; ----------------------------------------------------------------------------- +; DS1302 interface +; ----------------------------------------------------------------------------- + +N8VEM_RTC = 0x70 +PIN_CE = 0x10 +PIN_DATA_HIZ = 0x20 +PIN_CLK = 0x40 +PIN_DATA_OUT = 0x80 +PIN_DATA_IN = 0x01 + +.area _DATA + +rtc_shadow: .db 0 ; we can't read back the latch contents, so we must keep a copy + +.area _CODE + +_ds1302_get_pin_data: + in a, (N8VEM_RTC) ; read input register + and #PIN_DATA_IN ; mask off data pin + ld l, a ; return result in L + ret + +_ds1302_set_pin_data_driven: + ld hl, #2 ; get address of function argument + add hl, sp + ld b, (hl) ; load argument from stack + ld a, (rtc_shadow) + and #~PIN_DATA_HIZ ; 0 - output pin + bit 0, b ; test bit + jr nz, writereg + or #PIN_DATA_HIZ + jr writereg + +_ds1302_set_pin_data: + ld bc, #(((~PIN_DATA_OUT) << 8) | PIN_DATA_OUT) + jr setpin + +_ds1302_set_pin_ce: + ld bc, #(((~PIN_CE) << 8) | PIN_CE) + jr setpin + +_ds1302_set_pin_clk: + ld bc, #(((~PIN_CLK) << 8) | PIN_CLK) + jr setpin + +setpin: + ld a, (rtc_shadow) ; load current register contents + and b ; unset the pin + ld hl, #2 ; get address of function argument + add hl, sp + ld b, (hl) ; load argument from stack + bit 0, b ; test bit + jr z, writereg ; arg is false + or c ; arg is true +writereg: + out (N8VEM_RTC), a ; write out new register contents + ld (rtc_shadow), a ; update our shadow copy + ret + diff --git a/Kernel/platform-zeta-v2/kernel.def b/Kernel/platform-zeta-v2/kernel.def new file mode 100644 index 00000000..d723ee68 --- /dev/null +++ b/Kernel/platform-zeta-v2/kernel.def @@ -0,0 +1,60 @@ +; 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 an old good Z80 +;RAM_KB .equ 512 +RAM_KB .equ 256 +USE_FANCY_MONITOR .equ 1 ; disabling this saves around approx 0.5KB + +PROGBASE .equ 0x0000 +PROGLOAD .equ 0x0100 + +; Zeta SBC V2 mnemonics for I/O ports etc + +CONSOLE_RATE .equ 38400 + +; Z80 CTC ports +CTC_CH0 .equ 0x20 ; CTC channel 0 and interrupt vector +CTC_CH1 .equ 0x21 ; CTC channel 1 (periodic interrupts) +CTC_CH2 .equ 0x22 ; CTC channel 2 (UART interrupt) +CTC_CH3 .equ 0x23 ; CTC channel 3 (PPI interrupt) + +; 37C65 FDC ports +FDC_CCR .equ 0x28 ; Configuration Control Register (W/O) +FDC_MSR .equ 0x30 ; 8272 Main Status Register (R/O?) +FDC_DATA .equ 0x31 ; 8272 Data Port (R/W) +FDC_DOR .equ 0x38 ; Digital Output Register (W/O) +FDC_TC .equ 0x38 ; Pulse terminal count (R/O) + +; 8255 PPI ports +PPI_BASE .equ 0x60 +PPI_PORTA .equ PPI_BASE + 0 ; Port A +PPI_PORTB .equ PPI_BASE + 1 ; Port B +PPI_PORTC .equ PPI_BASE + 2 ; Port C +PPI_CONTROL .equ PPI_BASE + 3 ; PPI Control Port + +; 16550 UART +UART0_BASE .equ 0x68 +UART0_RBR .equ UART0_BASE + 0 ; DLAB=0: Receiver buffer register (R/O) +UART0_THR .equ UART0_BASE + 0 ; DLAB=0: Transmitter holding reg (W/O) +UART0_IER .equ UART0_BASE + 1 ; DLAB=0: Interrupt enable register +UART0_IIR .equ UART0_BASE + 2 ; Interrupt identification reg (R/0) +UART0_FCR .equ UART0_BASE + 2 ; FIFO control register (W/O) +UART0_LCR .equ UART0_BASE + 3 ; Line control register +UART0_MCR .equ UART0_BASE + 4 ; Modem control register +UART0_LSR .equ UART0_BASE + 5 ; Line status register +UART0_MSR .equ UART0_BASE + 6 ; Modem status register +UART0_SCR .equ UART0_BASE + 7 ; Scratch register +UART0_DLL .equ UART0_BASE + 0 ; DLAB=1: Divisor latch - low byte +UART0_DLH .equ UART0_BASE + 1 ; DLAB=1: Divisor latch - high byte + +; DS1302 RTC +N8VEM_RTC .equ 0x70 ; RTC / bit banging (R/W) + +; 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) diff --git a/Kernel/platform-zeta-v2/main.c b/Kernel/platform-zeta-v2/main.c new file mode 100644 index 00000000..723a4a31 --- /dev/null +++ b/Kernel/platform-zeta-v2/main.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include "config.h" + +extern unsigned char irqvector; + +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; +} + +void platform_interrupt(void) +{ + switch(irqvector) { + case 1: +#ifdef CONFIG_PPP + tty_poll_ppp() +#endif + timer_interrupt(); + return; + case 2: + tty_interrupt(); + return; + default: + return; + } +} diff --git a/Kernel/platform-zeta-v2/monitor.s b/Kernel/platform-zeta-v2/monitor.s new file mode 100644 index 00000000..83af254b --- /dev/null +++ b/Kernel/platform-zeta-v2/monitor.s @@ -0,0 +1,37 @@ +; 2015-01-17 William R Sowerbutts + + .module monitor + .include "kernel.def" + .globl _trap_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 +_trap_monitor: + di + call map_kernel + jp monitor_entry + + +; ----------------------------------------------------------------------------- +.else ; MICRO MONITOR --------------------------------------------------------- + .globl outchar + .globl outnewline + .globl outhl + + .area _COMMONMEM +_trap_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-zeta-v2/target.mk b/Kernel/platform-zeta-v2/target.mk new file mode 100644 index 00000000..3bffcde0 --- /dev/null +++ b/Kernel/platform-zeta-v2/target.mk @@ -0,0 +1 @@ +export CPU = z80 diff --git a/Kernel/platform-zeta-v2/tricks.s b/Kernel/platform-zeta-v2/tricks.s new file mode 100644 index 00000000..413f9ea2 --- /dev/null +++ b/Kernel/platform-zeta-v2/tricks.s @@ -0,0 +1,239 @@ +; 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 map_kernel + .globl _ramtop + + ; 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 + +; 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 + +_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, (_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. + + ; --------- 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 + 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-zeta-v2/zeta-v2.h b/Kernel/platform-zeta-v2/zeta-v2.h new file mode 100644 index 00000000..dd719141 --- /dev/null +++ b/Kernel/platform-zeta-v2/zeta-v2.h @@ -0,0 +1,20 @@ +#ifndef __ZETA_V2_DOT_H__ +#define __ZETA_V2_DOT_H__ + +#include "config.h" + +#define UART0_BASE 0x68 +__sfr __at (UART0_BASE + 0) UART0_RBR; /* receive buffer register, R/O */ +__sfr __at (UART0_BASE + 0) UART0_THR; /* xmit holding register, W/O */ +__sfr __at (UART0_BASE + 1) UART0_IER; /* interrupt enable register */ +__sfr __at (UART0_BASE + 2) UART0_IIR; /* interrupt ident. register, R/O */ +__sfr __at (UART0_BASE + 2) UART0_FCR; /* FIFO control register, W/O */ +__sfr __at (UART0_BASE + 3) UART0_LCR; /* Line control register */ +__sfr __at (UART0_BASE + 4) UART0_MCR; /* Modem control register */ +__sfr __at (UART0_BASE + 5) UART0_LSR; /* Line status register */ +__sfr __at (UART0_BASE + 6) UART0_MSR; /* Modem status register */ +__sfr __at (UART0_BASE + 7) UART0_SCR; /* Scratch register */ +__sfr __at (UART0_BASE + 0) UART0_DLL; /* Divisor latch - low byte */ +__sfr __at (UART0_BASE + 1) UART0_DLH; /* Divisor latch - high byte */ + +#endif diff --git a/Kernel/platform-zeta-v2/zeta-v2.s b/Kernel/platform-zeta-v2/zeta-v2.s new file mode 100644 index 00000000..3cfa6ffa --- /dev/null +++ b/Kernel/platform-zeta-v2/zeta-v2.s @@ -0,0 +1,335 @@ +; 2014-02-19 Sergey Kiselev +; Zeta SBC V2 hardware specific code + + .module zeta-v2 + + ; exported symbols + .globl init_early + .globl init_hardware + .globl _program_vectors + .globl map_kernel + .globl map_process + .globl map_process_always + .globl map_save + .globl map_restore + .globl _kernel_flag + .globl _irqvector + .globl platform_interrupt_all + .globl map_table + .globl _kernel_pages + + ; imported symbols + .globl _ramsize + .globl _procmem + .globl outhl + .globl outnewline + .globl interrupt_handler + .globl unix_syscall_entry + .globl nmi_handler + .globl null_handler + + ; 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) + +;========================================================================= +; Initialization code +;========================================================================= + .area _DISCARD + +init_early: + ret + +init_hardware: + ld hl, #RAM_KB ; set system RAM size + ld (_ramsize), hl + ld hl,#(RAM_KB-64) ; 64K for kernel + ld (_procmem), hl + + ; initialize UART0 + ld a,#0x80 ; LCR = DLAB ON + out (UART0_LCR),a ; set LCR + ld a,#CONSOLE_DIVISOR_LOW ; baud rate divisor - low byte + out (UART0_DLL),a ; set low byte of divisor + ld a,#CONSOLE_DIVISOR_HIGH ; baud rate divisor - high byte + out (UART0_DLH),a ; set high byte of divisor + ld a,#3 ; value for LCR and MCR + out (UART0_LCR),a ; 8 bit data, 1 stop, no parity + out (UART0_MCR),a ; DTR ON, RTS ON + ld a,#6 ; disable and reset FIFOs + out (UART0_FCR),a + ld a,#1 ; enable receive data available + out (UART0_IER),a ; interrupt + ; initialize CTC + ld a,#0x47 ; 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 + 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 + + ret + +;========================================================================= +; 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 + +_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 + +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 + ; Zeta SBC V2 uses IM 2 interrupts, so nothing should hit this vector + ; use null_handler just in case something causes it anyway + ld a,#0xC3 ; JP instruction + ld (0x0038),a + ld hl,#null_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 + + 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 + call map_process_2 + pop hl + 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 + call map_process_2 + pop hl + 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,#map_table ; 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 + call map_process_2 + pop hl + ret + +;========================================================================= +; map_save - save the current page mapping +; Inputs: none +; Outputs: none +;========================================================================= +map_save: + push hl + ld hl,(map_table) + ld (map_savearea),hl + ld hl,(map_table+2) + ld (map_savearea+2),hl + pop hl + ret + +map_table: + .db 32,33,34,35 +_kernel_pages: + .db 32,33,34,35 +map_savearea: + .db 32,33,34,35 + +; has to live in common +_kernel_flag: + .db 1 + +;========================================================================= +; Basic console I/O +;========================================================================= + +;========================================================================= +; outchar - Wait for UART TX idle, then print the char in A +; Inputs: A - character to print +; Outputs: none +;========================================================================= +outchar: + push af + ; wait for transmitter to be idle +ocloop: + in a,(UART0_LSR) ; read Line Status Register + and #0x20 ; get THRE bit + jr z,ocloop + ; now output the char to serial port + pop af + out (UART0_THR),a + ret + +;========================================================================= +; inchar - Wait for character on UART, return in A +; Inputs: none +; Outputs: A - received character, F destroyed +;========================================================================= +inchar: + in a,(UART0_LSR) ; read Line Status Register + and #0x01 ; test if data is in receive buffer + jp z,inchar ; no data, wait + in a,(UART0_RBR) ; read the character from the UART + ret -- 2.34.1