From: Alan Cox Date: Sat, 25 Aug 2018 14:21:53 +0000 (+0100) Subject: platform-sbcv2: N8VEM Mark 2 X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=88b8b7afde50125969ba60c0e41485dce0884c9e;p=FUZIX.git platform-sbcv2: N8VEM Mark 2 A nice simple tickless platform to use as a reference. Supports the PPIDE and PropIOv2. Currently only works with PropIOv2 present until I fix a bit of probing logic. --- diff --git a/Kernel/platform-sbcv2/Makefile b/Kernel/platform-sbcv2/Makefile new file mode 100644 index 00000000..67777c76 --- /dev/null +++ b/Kernel/platform-sbcv2/Makefile @@ -0,0 +1,52 @@ +CROSS_CCOPTS += -I../dev/ + + +CSRCS = devtty.c ppide.c +CSRCS += devices.c main.c + +DISCSRCS = discard.c + +ASRCS = sbcv2.s crt0.s ds1302-n8vem.s +ASRCS += tricks.s commonmem.s + +DISCARD_DSRCS = ../dev/devide_discard.c +DSRCS = ../dev/blkdev.c ../dev/devide.c ../dev/mbr.c +DSRCS += ../dev/propio2.c ../dev/ds1302.c + +NSRCS = + +COBJS = $(CSRCS:.c=.rel) +AOBJS = $(ASRCS:.s=.rel) +NOBJS = $(patsubst ../dev/net/%.c,%.rel, $(NSRCS)) +DISCOBJS = $(DISCSRCS:.c=.rel) +DISCARD_DOBJS = $(patsubst ../dev/%.c,%.rel, $(DISCARD_DSRCS)) +DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS)) + +OBJS = $(COBJS) $(AOBJS) $(NOBJS) $(DISCOBJS) $(DOBJS) $(DISCARD_DOBJS) + +JUNK = *.lst *.asm *.sym *.rst *.lst + +all: $(OBJS) + +$(COBJS): %.rel: %.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(DISCOBJS): %.rel: %.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(DOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(DISCARD_DOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(NOBJS): %.rel: ../dev/net/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(AOBJS): %.rel: %.s + $(CROSS_AS) $(ASOPTS) $< + +clean: + rm -f $(OBJS) $(JUNK) core *~ + +image: diff --git a/Kernel/platform-sbcv2/README b/Kernel/platform-sbcv2/README new file mode 100644 index 00000000..795a256e --- /dev/null +++ b/Kernel/platform-sbcv2/README @@ -0,0 +1,116 @@ +N8VEM SBCv2 + +This port is intended as a reference port for simple systems. + +The N8VEM mark 2 is a single board hobby Z80 based computer. It has 512K of +RAM and 512K or 1MB of Flash. The upper 32K of the address space is fixed as +the top 32K of the 512K RAM. The lower 32K can be switched to any 32K bank +of the ROM or RAM. + +Onboard I/O is limited to a 16550A UART providing a serial port and some +modem control lines, and an 8255 PIO that is normally used to connect a +PPIDE adapter. A bitbanged DS1302 real time clock is also provided but no timer +interrupt. + +The only interrupt available is either from the optional ECB backplane and add +in cards, or from the 16550A, but not both. + +The onboard firmware (ROMWBW) provides a monitor, BIOS and also CP/M or +ZSystem. For simplicity Fuzix is currently booted from the OS. + +Supported Hardware + +N8VEM SBC v2 +Optional PPIDE adapter for IDE disks or CF cards +Optional ECB PropIOv2 for keyboard/VGA console/SD card interface + +(currently the PropIOv2 is required - this will get fixed soon) + + +Implementation + +This platform uses the standard banked memory model. One lower 32K bank is +assigned to the kernel (Bank 14). The upper memory is fixed at bank 15, and +bank 0-13 are available to applications, one per bank. + +During execution the current per process data and stack (udata) live in the +upper bank near the top of memory. When a process is switched out they are saved +into the top of the low 32K space. + +Memory Layout + +Kernel +0000-00FF Interrupt vectors +0100-7FFF Kernel code + +User +0000-00FF Interrupt vectors +0100-7DFF User process (currently 7CFF needs fixing) +7E00-7FFF Copy of task kernel stack and variables + +8000-???? Kernel +????-EFFF Disk buffers +F000-FDFF Kernel common area and stacks +FE00-FFFF Reserved for firmware + + +Notes + +There are a variety of clever things that could be done to make this platform +more useful but at a cost. Firstly there is a lot of space free in the top 32K +so 8000-AFFF could probably be made user space and copied in and out each task +switch. As a single user machine doesn't switch much the cost isn't too high +and more becomes possible. + +As this is meant to be a porting reference nothing clever is done. There is +no fast bank to bank copier, and no clever user to kernel copier. These can be +taken from other ports if wanted. + +Oddities + +The SBCv2 by default has no timer interrupt. This means that time based +pre-emption cannot be performed, and the terminal will only be responsive when +the system is waiting for user activity (except the UART if it has interrupts +enabled). + +The code supports connecting a 10Hz clock source to a serial control line to +provide a real clock, and also routing the ECB interrupt using the same hack. + +Some ECB cards can provide a timer interrupt. These are not presently supported. + +Working With The Simulator + +The way I work is as follows + +Install cpmtools. +Add the following to the /usr/share/cpmtools/diskdefs + +diskdef romwbwhd + seclen 128 + tracks 1040 + sectrk 64 + blocksize 4096 + maxdir 512 + skew 0 + boottrk 16 + os 2.2 +end + +You can then create an sdcard image with + +dd if=/dev/zero of=sdcard.img bs=512 couunt=16384 + +Run the simulator and in CP/M or ZSystem and (if G is the SD card drive letter) + +n8vem2 -p + +G:ERA *.* + +then exit the simulator + +Once this is done you can copy Fuzix images to it using + +cpmcp -T raw -f romwbwhd sdcard.img fuzix.bin 0:fuzix.com + +Then go back in the simulator and run FUZIX as a CP/M binary + diff --git a/Kernel/platform-sbcv2/commonmem.s b/Kernel/platform-sbcv2/commonmem.s new file mode 100644 index 00000000..bafd590b --- /dev/null +++ b/Kernel/platform-sbcv2/commonmem.s @@ -0,0 +1,10 @@ +; +; We have no real common on the TRS80so just tuck it up at the top of +; memory leaving room for the keyboard and video (3K) +; + .module commonmem + + .area _COMMONMEM + + .include "../cpu-z80/std-commonmem.s" + diff --git a/Kernel/platform-sbcv2/config.h b/Kernel/platform-sbcv2/config.h new file mode 100644 index 00000000..4bdc8944 --- /dev/null +++ b/Kernel/platform-sbcv2/config.h @@ -0,0 +1,69 @@ +/* We have an RTC - well maybe (its optional) */ +#define CONFIG_RTC +#define CONFIG_RTC_FULL +#define CONFIG_NO_CLOCK +/* 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 +/* Banked memory set up */ +#define CONFIG_BANK_FIXED +#define MAX_MAPS 15 /* 512 KByte... minus the high one */ +#define MAP_SIZE 0x8000 + +/* Set these two for networking - no point right now */ +//#define CONFIG_NET +//#define CONFIG_NET_NATIVE + +/* PPIDE is present */ +#define CONFIG_IDE +#define CONFIG_PPIDE + +#define CONFIG_DYNAMIC_BUFPOOL +#define CONFIG_DYNAMIC_SWAP +#define CONFIG_LARGE_IO_DIRECT + +#define MAX_BLKDEV 4 + +#define CONFIG_BANKS 2 /* 2 x 32K */ + +/* For now we don't support resizing */ +#define VT_WIDTH 80 +#define VT_HEIGHT 25 +#define VT_RIGHT 79 +#define VT_BOTTOM 24 + +#define TICKSPERSEC 10 /* Ticks per second */ +#define PROGBASE 0x0000 /* Base of user */ +#define PROGLOAD 0x0100 /* Load and run here */ +#define PROGTOP 0x7D00 /* Top of program, base of U_DATA stash */ +#define PROC_SIZE 32 /* Memory needed per process */ + +#define SWAPDEV (swap_dev) +#define SWAP_SIZE 0x40 /* 32K in blocks */ +#define SWAPBASE 0x0000 /* We swap the lot in one, include the */ +#define SWAPTOP 0x8000 /* vectors so its a round number of sectors */ + +#define MAX_SWAPS 16 /* Should be plenty */ + +#define swap_map(x) ((uint8_t *)(x)) + +#define BOOT_TTY (512 + 1) /* Set this to default device for stdio, stderr */ + /* In this case, the default is the first TTY device */ + +/* We need a tidier way to do this from the loader */ +#define CMDLINE NULL /* Location of root dev name */ + +/* Device parameters */ +#define NUM_DEV_TTY 2 +#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ +#define NBUFS 5 /* Number of block buffers */ +#define NMOUNTS 4 /* Number of mounts at a time */ + +extern unsigned int swap_dev; diff --git a/Kernel/platform-sbcv2/crt0.s b/Kernel/platform-sbcv2/crt0.s new file mode 100644 index 00000000..038c336f --- /dev/null +++ b/Kernel/platform-sbcv2/crt0.s @@ -0,0 +1,87 @@ + ; Ordering of segments for the linker. + .area _CODE + .area _CODE2 + .area _HOME + .area _CONST + .area _INITIALIZED + .area _DATA + .area _BSEG + .area _BSS + .area _HEAP + .area _GSINIT + .area _GSFINAL + .area _BUFFERS + .area _DISCARD + .area _COMMONMEM + ; note that areas below here may be overwritten by the heap at runtime, so + ; put initialisation stuff in here + .area _INITIALIZER + + ; imported symbols + .globl _fuzix_main + .globl init_early + .globl init_hardware + .globl s__DATA + .globl l__DATA + .globl s__DISCARD + .globl l__DISCARD + .globl s__BUFFERS + .globl l__BUFFERS + .globl s__COMMONMEM + .globl l__COMMONMEM + .globl s__INITIALIZER + .globl kstack_top + .globl map_kernel + + ; startup code + .area _CODE + + ; Load at 0x0100 + ; We are executed as a CP/M task so live in bank 14/15 + ; with CP/M under us and the HBIOS proxy at FE00 +start: + ld bc,#0x0100 + ld e,#'*' + rst 8 + di + ld sp, #kstack_top + ; move the common memory where it belongs + ld hl, #s__DATA + ld de, #s__COMMONMEM + ld bc, #l__COMMONMEM + ldir + ; then the discard + ; Discard can just be linked in but is next to the buffers + ld de, #s__DISCARD + ld bc, #l__DISCARD + ldir + ld bc,#0x0100 + ld e,#':' + rst 8 + ; then zero the data area + ld hl, #s__DATA + ld de, #s__DATA + 1 + ld bc, #l__DATA - 1 + ld (hl), #0 + ldir +; Zero buffers area + ld hl, #s__BUFFERS + ld de, #s__BUFFERS + 1 + ld bc, #l__BUFFERS - 1 + ld (hl), #0 + ldir + ld bc,#0x0100 + ld e,#'X' + rst 8 + call init_early + ld bc,#0x0100 + ld e,#'Y' + rst 8 + call init_hardware + ld bc,#0x0100 + ld e,#'Z' + rst 8 + call _fuzix_main + di +stop: halt + jr stop diff --git a/Kernel/platform-sbcv2/devices.c b/Kernel/platform-sbcv2/devices.c new file mode 100644 index 00000000..a854830b --- /dev/null +++ b/Kernel/platform-sbcv2/devices.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct devsw dev_tab[] = /* The device driver switch table */ +{ + /* 0: /dev/hd Hard disc block devices */ + { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl }, + /* 1: /dev/fd Floppy disc block devices */ + { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* 2: /dev/tty TTY devices */ + { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, + /* 3: /dev/lpr Printer devices */ + { nxio_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 }, + /* Pack to 7 with nxio if adding private devices and start at 8 */ +}; + +bool validdev(uint16_t dev) +{ + /* This is a bit uglier than needed but the right hand side is + a constant this way */ + if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) - 1) + return false; + else + return true; +} diff --git a/Kernel/platform-sbcv2/devtty.c b/Kernel/platform-sbcv2/devtty.c new file mode 100644 index 00000000..6ea0ef99 --- /dev/null +++ b/Kernel/platform-sbcv2/devtty.c @@ -0,0 +1,83 @@ +/* + * We have a 16x50 UART at 0x68 and maybe a PropIO2 at A8 + */ + +#include +#include +#include +#include +#include +#include + +__sfr __at 0x68 uart_tx; +__sfr __at 0x68 uart_rx; +__sfr __at 0x6D uart_lsr; + +static char tbuf1[TTYSIZ]; +static char tbuf2[TTYSIZ]; + +/* Updated early in boot to 0,2,1 if PropIO present */ +uint8_t ttymap[NUM_DEV_TTY + 1] = { + 0, 1, 2 +}; + +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}, +}; + +/* Write to system console */ +void kputchar(char c) +{ + /* Need to make console dynamic FIXME */ + if (c == '\n') + tty_putc(1, '\r'); + tty_putc(1, c); +} + +uint8_t tty_writeready(uint8_t minor) +{ + minor; + /* FIXME: flow control */ + if (ttymap[minor] == 1) + return uart_lsr & 0x20 ? TTY_READY_NOW : TTY_READY_SOON; + return prop_tty_writeready(); +} + +void tty_putc(uint8_t minor, unsigned char c) +{ + minor; + if (ttymap[minor] == 1) + uart_tx = c; + else + prop_tty_write(c); +} + +void tty_setup(uint8_t minor) +{ + minor; +} + +void tty_sleeping(uint8_t minor) +{ + minor; +} + +int tty_carrier(uint8_t minor) +{ + minor; + return 1; +} + +void tty_data_consumed(uint8_t minor) +{ +} + +void tty_poll(void) +{ + /* Should be IRQ driven for this */ + if (uart_lsr & 0x01) + tty_inproc(ttymap[1], uart_rx); + prop_tty_poll(ttymap[2]); +} diff --git a/Kernel/platform-sbcv2/devtty.h b/Kernel/platform-sbcv2/devtty.h new file mode 100644 index 00000000..f4803a19 --- /dev/null +++ b/Kernel/platform-sbcv2/devtty.h @@ -0,0 +1,6 @@ +#ifndef _DEVTTY_H +#define _DEVTTY_H + +extern void tty_poll(void); + +#endif diff --git a/Kernel/platform-sbcv2/discard.c b/Kernel/platform-sbcv2/discard.c new file mode 100644 index 00000000..784017aa --- /dev/null +++ b/Kernel/platform-sbcv2/discard.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern int strcmp(const char *, const char *); + +void map_init(void) +{ +} + +/* Kernel in bank 0, user in banks 1-14, high 32K is bank 15 */ +void pagemap_init(void) +{ + uint8_t i; + for (i = 1; i < 15; i++) + pagemap_add(i); +} + +uint8_t platform_param(char *p) +{ + if (strcmp(p, "compumuse") == 0) { + return 1; + } + return 0; +} + +void platform_swap_found(uint8_t letter, uint8_t m) +{ + blkdev_t *blk = blk_op.blkdev; + uint16_t n; + if (swap_dev != 0xFFFF) + return; + letter -= 'a'; + kputs("(swap) "); + swap_dev = letter << 4 | m; + n = blk->lba_count[m - 1] / SWAP_SIZE; + if (n > MAX_SWAPS) + n = MAX_SWAPS; + while(n) + swapmap_add(n--); +} + +void device_init(void) +{ + devide_init(); + prop_sd_probe(); +} diff --git a/Kernel/platform-sbcv2/ds1302-n8vem.s b/Kernel/platform-sbcv2/ds1302-n8vem.s new file mode 100644 index 00000000..87a95bcd --- /dev/null +++ b/Kernel/platform-sbcv2/ds1302-n8vem.s @@ -0,0 +1,79 @@ +; 2015-02-19 Sergey Kiselev +; 2014-12-31 William R Sowerbutts +; N8VEM SBC / Zeta SBC DS1302 real time clock interface code +; +; FIXME: belongs in dev/ +; + + .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-sbcv2/fuzix.lnk b/Kernel/platform-sbcv2/fuzix.lnk new file mode 100644 index 00000000..5a3530cc --- /dev/null +++ b/Kernel/platform-sbcv2/fuzix.lnk @@ -0,0 +1,45 @@ +-mwxuy +-i fuzix.ihx +-b _CODE=0x0100 +-b _COMMONMEM=0xF000 +-b _INITIALIZER=0xFD00 +-l z80 +platform-sbcv2/crt0.rel +platform-sbcv2/commonmem.rel +platform-sbcv2/sbcv2.rel +start.rel +version.rel +lowlevel-z80.rel +usermem.rel +usermem_std-z80.rel +platform-sbcv2/tricks.rel +platform-sbcv2/main.rel +platform-sbcv2/discard.rel +timer.rel +kdata.rel +platform-sbcv2/devices.rel +devio.rel +filesys.rel +process.rel +inode.rel +syscall_exec16.rel +syscall_fs.rel +syscall_fs2.rel +syscall_fs3.rel +syscall_proc.rel +syscall_other.rel +tty.rel +mm.rel +swap.rel +bankfixed.rel +devsys.rel +platform-sbcv2/devtty.rel +platform-sbcv2/blkdev.rel +platform-sbcv2/mbr.rel +platform-sbcv2/devide.rel +platform-sbcv2/devide_discard.rel +platform-sbcv2/propio2.rel +platform-sbcv2/ppide.rel +platform-sbcv2/ds1302.rel +platform-sbcv2/ds1302-n8vem.rel +-e diff --git a/Kernel/platform-sbcv2/kernel.def b/Kernel/platform-sbcv2/kernel.def new file mode 100644 index 00000000..ad02967a --- /dev/null +++ b/Kernel/platform-sbcv2/kernel.def @@ -0,0 +1,17 @@ +; 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. + +U_DATA_STASH .equ 0x7D00 ; 7D00-7FFF + +PROGBASE .equ 0x0000 +PROGLOAD .equ 0x0100 + +Z80_TYPE .equ 1 ; NMOS (IRQ bugs) Z80 + +Z80_MMU_HOOKS .equ 0 + +CONFIG_SWAP .equ 1 + +NBUFS .equ 5 diff --git a/Kernel/platform-sbcv2/main.c b/Kernel/platform-sbcv2/main.c new file mode 100644 index 00000000..2cae50cc --- /dev/null +++ b/Kernel/platform-sbcv2/main.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include +#include +#include + +uint16_t ramtop = PROGTOP; +uint16_t swap_dev = 0xFFFF; + +/* On idle we spin checking for the terminals. Gives us more responsiveness + for the polled ports */ +void platform_idle(void) +{ + irqflags_t irq = di(); + sync_clock(); + tty_poll(); + irqrestore(irq); +} + +void platform_interrupt(void) +{ + /* TODO */ + tty_poll(); +} + +struct blkbuf *bufpool_end = bufpool + NBUFS; + +/* + * We pack discard into the memory image is if it were just normal + * code but place it at the end after the buffers. When we finish up + * booting we turn everything from the buffer pool to common into + * buffers. + */ +void platform_discard(void) +{ + uint16_t discard_size = (uint16_t)udata - (uint16_t)bufpool_end; + bufptr bp = bufpool_end; + + discard_size /= sizeof(struct blkbuf); + + kprintf("%d buffers added\n", discard_size); + + bufpool_end += discard_size; + + memset( bp, 0, discard_size * sizeof(struct blkbuf) ); + + for( bp = bufpool + NBUFS; bp < bufpool_end; ++bp ){ + bp->bf_dev = NO_DEVICE; + bp->bf_busy = BF_FREE; + } +} + +static uint8_t rtc_buf[8]; + +int platform_rtc_read(void) +{ + uint16_t len = sizeof(struct cmos_rtc); + uint16_t y; + struct cmos_rtc cmos; + uint8_t *p = cmos.data.bytes; + + if (udata.u_count < len) + len = udata.u_count; + + ds1302_read_clock(rtc_buf, 7); + + y = rtc_buf[6]; + if (y > 0x70) + y = 0x1900 | y; + else + y = 0x2000 | y; + *p++ = y >> 8; + *p++ = y; + rtc_buf[4]--; /* 0 based */ + if ((rtc_buf[4] & 0x0F) > 9) /* Overflow case */ + rtc_buf[4] -= 0x06; + *p++ = rtc_buf[4]; /* Month */ + *p++ = rtc_buf[3]; /* Day of month */ + if ((rtc_buf[2] & 0x90) == 0x90) { /* 12hr mode, PM */ + /* Add 12 BCD */ + rtc_buf[2] += 0x12; + if ((rtc_buf[2] & 0x0F) > 9) /* Overflow case */ + rtc_buf[2] += 0x06; + } + *p++ = rtc_buf[2]; /* Hour */ + *p++ = rtc_buf[1]; /* Minute */ + *p = rtc_buf[0]; /* Second */ + cmos.type = CMOS_RTC_BCD; + if (uput(&cmos, udata.u_base, len) == -1) + return -1; + return len; +} + +int platform_rtc_write(void) +{ + udata.u_error = -EOPNOTSUPP; + return -1; +} + +static uint8_t newticks = 0xFF; +static uint8_t oldticks; + +static uint8_t re_enter; + +void sync_clock_read(void) +{ + uint8_t s; + oldticks = newticks; + ds1302_read_clock(&s, 1); + s = (s & 0x0F) + (((s & 0xF0) >> 4) * 10); + newticks = s; +} + +void sync_clock(void) +{ + irqflags_t irq = di(); + int16_t tmp; + if (!re_enter++) { + sync_clock_read(); + if (oldticks != 0xFF) { + tmp = newticks - oldticks; + if (tmp < 0) + tmp += 60; + tmp *= 10; + while(tmp--) { + timer_interrupt(); + } + platform_interrupt(); + } + re_enter--; + } + irqrestore(irq); +} + +void update_sync_clock(void) +{ +} diff --git a/Kernel/platform-sbcv2/platform_ide.h b/Kernel/platform-sbcv2/platform_ide.h new file mode 100644 index 00000000..95d67e15 --- /dev/null +++ b/Kernel/platform-sbcv2/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-sbcv2/ppide.c b/Kernel/platform-sbcv2/ppide.c new file mode 100644 index 00000000..1d89cb79 --- /dev/null +++ b/Kernel/platform-sbcv2/ppide.c @@ -0,0 +1,123 @@ +/* 2015-04-24 WRS: devide glue functions for PPIDE */ +/* FIXME: move to dev */ + +#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_port_c = regaddr | PPIDE_RD_LINE; /* begin /RD pulse */ + r = ppi_port_a; + ppi_port_c = regaddr; /* 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_port_c = regaddr | PPIDE_WR_LINE; + /* FIXME: check timing */ + ppi_port_c = regaddr; + 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-sbcv2/sbcv2.s b/Kernel/platform-sbcv2/sbcv2.s new file mode 100644 index 00000000..925713b4 --- /dev/null +++ b/Kernel/platform-sbcv2/sbcv2.s @@ -0,0 +1,246 @@ +; +; SBC v2 support +; + + .module sbcv2 + + ; exported symbols + .globl init_early + .globl init_hardware + .globl interrupt_handler + .globl _program_vectors + .globl map_kernel + .globl map_process + .globl map_process_a + .globl map_process_always + .globl map_save + .globl map_restore + .globl map_for_swap + .globl platform_interrupt_all + .globl _kernel_flag + + ; exported debugging tools + .globl _platform_monitor + .globl _platform_reboot + .globl outchar + + ; imported symbols + .globl _ramsize + .globl _procmem + .globl istack_top + .globl istack_switched_sp + .globl unix_syscall_entry + .globl trap_illegal + .globl outcharhex + .globl null_handler + + .globl s__COMMONMEM + .globl l__COMMONMEM + + .include "kernel.def" + .include "../kernel.def" + +; +; Buffers (we use asm to set this up as we need them in a special segment +; so we can recover the discard memory into the buffer pool +; + + .globl _bufpool + .area _BUFFERS + +_bufpool: + .ds BUFSIZE * NBUFS +; +; COMMON MEMORY BANK (kept even when we task switch) +; + .area _COMMONMEM + +platform_interrupt_all: + ret + +; FIXME: map ROM and jump into it +_platform_monitor: +_platform_reboot: + di + xor a + out (0x7C),a + rst 0 + +; ----------------------------------------------------------------------------- +; KERNEL MEMORY BANK (may be below 0x8000, only accessible when the kernel is +; mapped) +; ----------------------------------------------------------------------------- + .area _CODE + +; +; We will address this one better when we do some ROMWBW integration +; + .globl _ttymap +init_early: + ; FIXME: code goes here to check for PropIO v2 nicely + ; Passes the minimal checking + ld hl,#0x0102 + ld (_ttymap+1), hl ; set tty map to 0,2,1 for prop + ret + + .area _DISCARD + +init_hardware: + ld hl,#512 + ld (_ramsize), hl + ld hl,#448 + ld (_procmem), hl + + ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused) + ld hl, #0 + push hl + call _program_vectors + pop hl + + im 1 ; set CPU interrupt mode + + ret + +;------------------------------------------------------------------------------ +; COMMON MEMORY PROCEDURES FOLLOW + + .area _COMMONMEM + +mapreg: .db 0 +mapsave: .db 0 + +_kernel_flag: + .db 1 ; We start in kernel mode + +_program_vectors: + ; we are called, with interrupts disabled, by both newproc() and crt0 + ; will exit with interrupts off + di ; just to be sure + pop de ; temporarily store return address + pop hl ; function argument -- base page number + push hl ; put stack back as it was + push de + + call map_process + + ; now install the interrupt vector at 0x0038 + ld a, #0xC3 ; JP instruction + ld (0x0038), a + ld hl, #interrupt_handler + ld (0x0039), hl + + ; set restart vector for FUZIX system calls + ld (0x0030), a ; (rst 30h is unix function call vector) + ld hl, #unix_syscall_entry + ld (0x0031), hl + + ld (0x0000), a + ld hl, #null_handler ; to Our Trap Handler + ld (0x0001), hl + +; +; Mapping set up for the SBCv2 +; +; The top 32K bank holds kernel code and pieces of common memory +; The lower 32K is switched between the various user banks. +; +; We know the ROM mapping is already off +; +map_kernel: + push af + ; ROMWBW TPA is last but one bank (last bank is high space) + ; so for now we hardcode this. We should ask ROMWBW at boot + ld a,#14 + ld (mapreg),a + out (0x78), a + pop af + ret +map_process: + ld a, h + or l + jr z, map_kernel +map_process_hl: + ld a, (hl) +map_for_swap: +map_process_a: ; used by bankfork + dec a ; We bias by 1 because 0 is a valid user + ld (mapreg), a ; bank + out (0x78), a + inc a ; cheaper than push/pop + ret + +map_process_always: + push af + push hl + ld hl, #U_DATA__U_PAGE + call map_process_hl + pop hl + pop af + ret + +map_save: push af + ld a, (mapreg) + ld (mapsave), a + pop af + ret + +map_restore: + push af + ld a, (mapsave) + ld (mapreg), a + out (0x78), a + pop af + ret + +outchar: + push af +twait: in a,(0x6D) + bit 5,a + jr z, twait + pop af + out (0x68),a + ret + +; +; PropIO v2 block transfers +; + +; FIXME: Move these somewhere better +BLKPARAM_ADDR_OFFSET .equ 0 +BLKPARAM_IS_USER_OFFSET .equ 2 +BLKPARAM_SWAP_PAGE .equ 3 + + .globl _platform_prop_sd_read + .globl _platform_prop_sd_write + + .globl _blk_op + +_platform_prop_sd_read: + ld a,(_blk_op + BLKPARAM_IS_USER_OFFSET) + ld hl, (_blk_op + BLKPARAM_ADDR_OFFSET) + or a + jr z, do_read + dec a + ld a, (_blk_op + BLKPARAM_SWAP_PAGE) + jr nz, do_read_a + ld a, (U_DATA__U_PAGE) +do_read_a: call map_process_a +do_read: ld bc,#0xAB + inir + inir + jp map_kernel + +_platform_prop_sd_write: + ld a,(_blk_op + BLKPARAM_IS_USER_OFFSET) + ld hl, (_blk_op + BLKPARAM_ADDR_OFFSET) + or a + jr z, do_write + dec a + ld a, (_blk_op + BLKPARAM_SWAP_PAGE) + jr nz, do_write_a + ld a, (U_DATA__U_PAGE) +do_write_a: call map_process_a +do_write: ld bc,#0xAB + otir + otir + jp map_kernel diff --git a/Kernel/platform-sbcv2/target.mk b/Kernel/platform-sbcv2/target.mk new file mode 100644 index 00000000..3bffcde0 --- /dev/null +++ b/Kernel/platform-sbcv2/target.mk @@ -0,0 +1 @@ +export CPU = z80 diff --git a/Kernel/platform-sbcv2/tricks.s b/Kernel/platform-sbcv2/tricks.s new file mode 100644 index 00000000..ee50c077 --- /dev/null +++ b/Kernel/platform-sbcv2/tricks.s @@ -0,0 +1,5 @@ + + .include "../kernel.def" + .include "kernel.def" + + .include "../lib/z80fixedbank.s"