From: Alan Cox Date: Sat, 8 Dec 2018 17:29:44 +0000 (+0000) Subject: tbblue: first cut at tbblue support X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=c409b8dc5350a59ea50078784748f04fc0c95468;p=FUZIX.git tbblue: first cut at tbblue support Really more of a way to try and debug the bank8k code than anything else. Right now this is very very basic - an outline to get booting and work from. --- diff --git a/Kernel/platform-tbblue/Makefile b/Kernel/platform-tbblue/Makefile new file mode 100644 index 00000000..50d0a836 --- /dev/null +++ b/Kernel/platform-tbblue/Makefile @@ -0,0 +1,63 @@ +ASRCS = crt0.s tbblue.s tmxvideo.s +ASRCS += tricks.s commonmem.s +CSRCS = devtty.c devices.c main.c +CDSRCS = discard.c +DSRCS = ../dev/devsd.c ../dev/blkdev.c +DDSRCS = ../dev/devsd_discard.c ../dev/mbr.c +DZSRCS = ../dev/zx/divmmc.c ../dev/zx/zxkeyboard.c ../dev/zx/devinput.c +DDZSRCS = +NSRCS = ../dev/net/net_native.c + +COBJS = $(CSRCS:.c=.rel) +CDOBJS = $(CDSRCS:.c=.rel) +AOBJS = $(ASRCS:.s=.rel) +DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS)) +DDOBJS = $(patsubst ../dev/%.c,%.rel, $(DDSRCS)) +DZOBJS = $(patsubst ../dev/zx/%.c,%.rel, $(DZSRCS)) +DDZOBJS = $(patsubst ../dev/zx/%.c,%.rel, $(DDZSRCS)) +NOBJS = $(patsubst ../dev/net/%.c,%.rel, $(NSRCS)) + +OBJS = $(COBJS) $(CDOBJS) $(AOBJS) $(DOBJS) $(DDOBJS) $(DZOBJS) $(DDZOBJS) $(NOBJS) + +CROSS_CCOPTS += -I../dev/ -I../dev/zx/ -I../dev/net/ + +all: $(OBJS) + +$(COBJS): %.rel: %.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(CDOBJS): %.rel: %.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(DOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(DDOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(DZOBJS): %.rel: ../dev/zx/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(DDZOBJS): %.rel: ../dev/zx/%.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(NOBJS): %.rel: ../dev/net/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(AOBJS): %.rel: %.s + $(CROSS_AS) $(ASOPTS) $< + +clean: + rm -f $(OBJS) *.lst *.asm *.sym *.rst *.rel core *~ + rm -f FUZIX FUZIX.BIN load-esx.ihx load-esx.tmp + +image: + # Build an esxdos friendly setup + sdasz80 -o load-esx.s + sdldz80 -i load-esx.rel + makebin -s 8704 load-esx.ihx load-esx.tmp + # Generate the image file we need + dd if=load-esx.tmp of=FUZIX bs=8192 skip=1 + + dd if=/dev/zero bs=256 count=1 >FUZIX.BIN + cat ../fuzix.bin >>FUZIX.BIN diff --git a/Kernel/platform-tbblue/README b/Kernel/platform-tbblue/README new file mode 100644 index 00000000..9c922af6 --- /dev/null +++ b/Kernel/platform-tbblue/README @@ -0,0 +1,28 @@ +First wild guesses at TBBlue support + +8K paging also needs debug + +Currently goal is + +load kernel into pages 16-23 +switch 16-22 into memory +jump to kernel 0x0100 +switch 23 into memory +set up and go + +TODO: +DONE program_vectors +DONE review where font and video code needs to land + Use nextreg + memory sizing +DONEish set up page map properly + + See if we can make it boot + + +Bigger issues +- We actually want a banked kernel so that we can put networking in its + own bank and maybe external buffers. We have tons of RAM and fast DMA. +- Need to look at optimal inter bank copies for user copying and buffers. + + diff --git a/Kernel/platform-tbblue/commonmem.s b/Kernel/platform-tbblue/commonmem.s new file mode 100644 index 00000000..dc31c24e --- /dev/null +++ b/Kernel/platform-tbblue/commonmem.s @@ -0,0 +1,8 @@ +; +; Multiple app sizes and the fact the kernel and apps share the same banks +; means we need to put this somewhere low +; + .module commonmem + .area _COMMONDATA + + .include "../cpu-z80/std-commonmem.s" diff --git a/Kernel/platform-tbblue/config.h b/Kernel/platform-tbblue/config.h new file mode 100644 index 00000000..797fcdad --- /dev/null +++ b/Kernel/platform-tbblue/config.h @@ -0,0 +1,119 @@ +/* Enable to make ^Z dump the inode table for debug */ +#undef CONFIG_IDUMP +/* Enable to make ^A drop back into the monitor */ +#undef CONFIG_MONITOR +/* Profil syscall support (not yet complete) */ +#undef CONFIG_PROFIL +/* Multiple processes in memory at once */ +#define CONFIG_MULTI +/* Single tasking */ +#undef CONFIG_SINGLETASK + +/* Select a banked memory set up */ +#define CONFIG_BANK8 /* 8K pages */ +#define MAX_MAPS 96 /* Assume 512K for now FIXME */ +/* How big is each bank - in our case 8K */ +#define MAP_SIZE 0x2000 +#define TOP_SIZE 0x200 /* Udata to swap */ +/* How many banks do we have in our address space */ +#define CONFIG_BANKS 8 /* 8 x 8K will fix when do paging */ +#define PAGE_INVALID 0xFF /* A never used value */ + +/* Input layer support */ +#define CONFIG_INPUT +#define CONFIG_INPUT_GRABMAX 3 +/* Video terminal, not a serial tty */ +#define CONFIG_VT +/* Keyboard contains non-ascii symbols */ +#define CONFIG_UNIKEY +#define CONFIG_FONT8X8 +#define CONFIG_FONT8X8SMALL +/* Vt definitions */ +#define VT_WIDTH 64 +#define VT_HEIGHT 24 +#define VT_RIGHT 63 +#define VT_BOTTOM 23 + + + +/* + * Define the program loading area (needs to match kernel.def) + */ +#define PROGBASE 0x0000 /* Base of user */ +#define PROGLOAD 0x0100 /* Load and run here */ +#define PROGTOP 0xE000 /* Top of program, base of U_DATA stash */ +#define PROC_SIZE 56 /* Memory needed per process including stash */ + +/* + * Definitions for swapping - we don't need swap! + */ + +/* What is the maximum number of /dev/hd devices we have. In theory right now + it's actually 1 - the SD interface */ +#define MAX_BLKDEV 2 +/* Select IDE disk support, and PPIDE (parallel port IDE) as the interface */ +#define CONFIG_SD +#define SD_DRIVE_COUNT 1 + +#define BOOTDEVICENAMES "hd#" + +/* We will resize the buffers available after boot. This is the normal setting */ +#define CONFIG_DYNAMIC_BUFPOOL +/* Larger transfers (including process execution) should go directly not via + the buffer cache. For all small (eg bit) systems this is the right setting + as it avoids polluting the small cache with data when it needs to be full + of directory and inode information */ +#define CONFIG_LARGE_IO_DIRECT + +/* Specify this if there is a real time clock capable of reporting seconds. It + will be used to lock the kernel time better to reality. Other details like + Y2K support, or even supporting dates as well don't matter */ +#undef CONFIG_RTC +/* Specify that there is a full real time clock that can supply the date and + time to the system. */ +#undef CONFIG_RTC_FULL + +/* + * How fast does the clock tick (if present), or how many times a second do + * we simulate if not. For a machine without video 10 is a good number. If + * you have video you probably want whatever vertical sync/blank interrupt + * rate the machine has. For many systems it's whatever the hardware gives + * you. + * + * Note that this needs to be divisible by 10 and at least 10. If your clock + * is a bit slower you may need to fudge things somewhat so that the kernel + * gets 10 timer interrupt calls per second. + */ +#define TICKSPERSEC 10 /* Ticks per second */ + +/* Core networking support */ +#define CONFIG_NET +/* Or native (eg SLIP) */ +#define CONFIG_NET_NATIVE + +/* + * The device (major/minor) for the console and boot up tty attached to + * init at start up. 512 is the major 2, so all the tty devices are + * 512 + n where n is the tty. + */ +#define BOOT_TTY (512 + 1) /* Set this to default device for stdio, stderr */ + /* In this case, the default is the first TTY device */ +/* + * If you have a mechanism to pass in a root device configuration then + * this holds the address of the buffer (eg a CP/M command line or similar). + * If the configuration is fixed then this can be a string holding the + * configuration. NULL means 'prompt the user'. + */ +#define CMDLINE NULL /* Location of root dev name */ + +/* Device parameters */ +#define NUM_DEV_TTY 2 /* How many tty devices does the platform support */ +#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ +#define NBUFS 5 /* Number of block buffers. Must be 4+ and must match + kernel.def */ +#define NMOUNTS 4 /* Number of mounts at a time */ + +/* This can optionally be set to force a default baud rate, eg if the system + console should match a firmware set rate */ +#define TTY_INIT_BAUD B38400 /* To match ROMWBW */ + diff --git a/Kernel/platform-tbblue/crt0.s b/Kernel/platform-tbblue/crt0.s new file mode 100644 index 00000000..a58fa8f6 --- /dev/null +++ b/Kernel/platform-tbblue/crt0.s @@ -0,0 +1,114 @@ + .module crt0 + + .area _CODE + .area _CODE2 + .area _CODE3 + .area _VIDEO + .area _INITIALIZED + .area _HOME + .area _CONST + + ; + ; Beyond this point we just zero. + ; + + .area _DATA + .area _BSEG + .area _BSS + .area _HEAP + .area _GSINIT + .area _GSFINAL + ; + ; Finally the buffers so they can expand + ; + .area _BUFFERS + .area _INITIALIZER + + .area _DISCARD + ; Somewhere to throw it out of the way + + + ; Our common is mapped high + .area _COMMONDATA + .area _COMMONMEM + .area _FONT + + + + ; imported symbols + .globl _fuzix_main + .globl init_early + .globl init_hardware + .globl l__BUFFERS + .globl s__BUFFERS + .globl l__DATA + .globl s__DATA + .globl kstack_top + + .globl unix_syscall_entry + .globl nmi_handler + .globl interrupt_handler + + .include "../kernel.def" + .include "kernel.def" + + ; + ; startup code. Runs from 0x100. The kernel is mapped into pages + ; 16-23 and 16-22 are currently mapped. Stack is not valid on entry + ; and interrupts are off. + ; + + .area _CODE + + .globl _start + +_start: + ; Map in the top page (it couldn't be mapped by the loader as the + ; loader is living in it) + ld a,#0x57 ; MMU E000-FFFF + ld bc,#0x243B + out (c),a + ld a,#23 ; Top kernel page + inc b + out (c),a + + ; We need to wipe the BSS but the rest of the job is done. + + ld hl, #s__DATA + ld de, #s__DATA+1 + ld bc, #l__DATA-1 + ld (hl), #0 + ldir + ld hl, #s__BUFFERS + ld de, #s__BUFFERS+1 + ld bc, #l__BUFFERS-1 + ld (hl), #0 + ldir + + ld sp, #kstack_top + + ; Configure memory map + call init_early + + ; Hardware setup + call init_hardware + + ; Call the C main routine + call _fuzix_main + + ; main shouldn't return, but if it does... + di +stop: halt + jr stop + + .area _BUFFERS +; +; Buffers (we use asm to set this up as we need them in a special segment +; so we can recover the discard memory into the buffer pool +; + + .globl _bufpool + .area _BUFFERS + +_bufpool: + .ds BUFSIZE * NBUFS diff --git a/Kernel/platform-tbblue/devices.c b/Kernel/platform-tbblue/devices.c new file mode 100644 index 00000000..dac89120 --- /dev/null +++ b/Kernel/platform-tbblue/devices.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct devsw dev_tab[] = /* The device driver switch table */ +{ + /* 0: /dev/hd Hard disc block devices */ + { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl }, + /* 1: /dev/fd Floppy disc block devices: nope */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* 2: /dev/tty TTY devices */ + { tty_open, tty_close, tty_read, tty_write, gfx_ioctl }, + /* 3: /dev/lpr Printer devices */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* 4: /dev/mem etc System devices (one offs) */ + { no_open, no_close, sys_read, sys_write, sys_ioctl }, + /* 5: Pack to 7 with nxio if adding private devices and start at 8 */ +}; + +bool validdev(uint16_t dev) +{ + /* This is a bit uglier than needed but the right hand side is + a constant this way */ + if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) - 1) + return false; + else + return true; +} + +void device_init(void) +{ +#ifdef CONFIG_SD + devsd_init(); +#endif +} diff --git a/Kernel/platform-tbblue/devtty.c b/Kernel/platform-tbblue/devtty.c new file mode 100644 index 00000000..5e7dc531 --- /dev/null +++ b/Kernel/platform-tbblue/devtty.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char tbuf1[TTYSIZ]; + +uint8_t vtattr_cap = VTA_INVERSE|VTA_FLASH|VTA_UNDERLINE; +extern uint8_t curattr; + +static tcflag_t console_mask[4] = { + _ISYS, + _OSYS, + _CSYS, + _LSYS +}; + +tcflag_t *termios_mask[NUM_DEV_TTY + 1] = { + NULL, + console_mask +}; + + +struct s_queue ttyinq[NUM_DEV_TTY + 1] = { /* ttyinq[0] is never used */ + {NULL, NULL, NULL, 0, 0, 0}, + {tbuf1, tbuf1, tbuf1, TTYSIZ, 0, TTYSIZ / 2}, +}; + +/* tty1 is the screen */ + +/* Output for the system console (kprintf etc) */ +void kputchar(char c) +{ + if (c == '\n') + tty_putc(0, '\r'); + tty_putc(0, c); +} + +/* Both console and debug port are always ready */ +ttyready_t tty_writeready(uint8_t minor) +{ + minor; + return TTY_READY_NOW; +} + +void tty_putc(uint8_t minor, unsigned char c) +{ + minor; + vtoutput(&c, 1); +} + +int tty_carrier(uint8_t minor) +{ + minor; + return 1; +} + +void tty_setup(uint8_t minor, uint8_t flags) +{ + minor; +} + +void tty_sleeping(uint8_t minor) +{ + minor; +} + +void tty_data_consumed(uint8_t minor) +{ +} + + +/* This is used by the vt asm code, but needs to live in the kernel */ +uint16_t cursorpos; + +/* For now we only support 64 char mode - we should add the mode setting + logic an dother modes FIXME */ +static struct display specdisplay = { + 0, + 512, 192, + 512, 192, + 0xFF, 0xFF, + FMT_TIMEX64, + HW_UNACCEL, + GFX_VBLANK|GFX_MAPPABLE|GFX_TEXT, + 0 +}; + +static struct videomap specmap = { + 0, + 0, + 0x4000, + 14336, + 0, + 0, + 0, + MAP_FBMEM|MAP_FBMEM_SIMPLE +}; + +/* + * Graphics ioctls. Very minimal for this platform. It's a single fixed + * mode with direct memory mapping. + */ +int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr) +{ + if (minor != 1 || arg >> 8 != 0x03) + return vt_ioctl(minor, arg, ptr); + switch(arg) { + case GFXIOC_GETINFO: + return uput(&specdisplay, ptr, sizeof(struct display)); + case GFXIOC_MAP: + return uput(&specmap, ptr, sizeof(struct videomap)); + case GFXIOC_UNMAP: + return 0; + case GFXIOC_WAITVB: + /* Our system clock is vblank */ + timer_wait++; + psleep(&timer_interrupt); + timer_wait--; + chksigs(); + if (udata.u_cursig) { + udata.u_error = EINTR; + return -1; + } + return 0; + } + return -1; +} + +void vtattr_notify(void) +{ + /* Attribute byte fixups: not hard as the colours map directly + to the spectrum ones */ + if (vtattr & VTA_INVERSE) + curattr = ((vtink & 7) << 3) | (vtpaper & 7); + else + curattr = (vtink & 7) | ((vtpaper & 7) << 3); + if (vtattr & VTA_FLASH) + curattr |= 0x80; + /* How to map the bright bit - we go by either */ + if ((vtink | vtpaper) & 0x10) + curattr |= 0x40; +} diff --git a/Kernel/platform-tbblue/devtty.h b/Kernel/platform-tbblue/devtty.h new file mode 100644 index 00000000..40a67f5c --- /dev/null +++ b/Kernel/platform-tbblue/devtty.h @@ -0,0 +1,19 @@ +#ifndef __DEVTTY_DOT_H__ +#define __DEVTTY_DOT_H__ + +void tty_pollirq(void); +static void keydecode(void); + +#define KEY_ROWS 8 +#define KEY_COLS 5 +extern uint8_t keymap[8]; +extern uint8_t keyboard[8][5]; +extern uint8_t shiftkeyboard[8][5]; + +extern uint8_t timer_wait; + +extern int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr); + +extern uint8_t vtborder; + +#endif diff --git a/Kernel/platform-tbblue/discard.c b/Kernel/platform-tbblue/discard.c new file mode 100644 index 00000000..b5a04862 --- /dev/null +++ b/Kernel/platform-tbblue/discard.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +extern uint8_t kempston, kmouse; + +uint8_t platform_param(char *p) +{ + return 0; +} + +/* Nothing to do for the map of init */ +void map_init(void) +{ +} + +void pagemap_init(void) +{ + uint8_t i; + /* 8K pages that are above the kernel */ + /* FIXME: will depend upon size (<160 or < 224 for expanded) */ + for (i = 24; i < 96; i++) + pagemap_add(i); + /* We can arguably also steal the memory wasted on the DivMMC + that we don't use FIXME */ + + /* Low pages we can scavenge */ + /* + Reserved + 10-11: system screen (console 1) + 14-15: shadow screen (console 2) + + We should probably reserve Layer 2 buffers as well at some + point in time + */ + for (i = 0; i < 10; i++) + pagemap_add(i); + pagemap_add(12); + pagemap_add(13); + /* Common for init */ + pagemap_add(23); +} + +void platform_copyright(void) +{ + kempston = 1; + kmouse = 1; +} + diff --git a/Kernel/platform-tbblue/fuzix.lnk b/Kernel/platform-tbblue/fuzix.lnk new file mode 100644 index 00000000..f67939b7 --- /dev/null +++ b/Kernel/platform-tbblue/fuzix.lnk @@ -0,0 +1,50 @@ +-mwxuy +-i fuzix.ihx +-l z80 +-b _CODE=0x0100 +-b _COMMONDATA=0xF200 +-b _DISCARD=0xE200 +platform-tbblue/crt0.rel +platform-tbblue/commonmem.rel +platform-tbblue/tbblue.rel +platform-tbblue/tmxvideo.rel +platform-tbblue/main.rel +platform-tbblue/discard.rel +start.rel +version.rel +lowlevel-z80.rel +usermem_std-z80.rel +platform-tbblue/tricks.rel +timer.rel +kdata.rel +usermem.rel +platform-tbblue/devices.rel +devio.rel +filesys.rel +process.rel +inode.rel +syscall_exec16.rel +syscall_fs.rel +syscall_fs2.rel +syscall_fs3.rel +syscall_proc.rel +syscall_other.rel +syscall_net.rel +tty.rel +vt.rel +font8x8.rel +mm.rel +bank8k.rel +swap.rel +devsys.rel +devinput.rel +platform-tbblue/devtty.rel +platform-tbblue/devsd.rel +platform-tbblue/devsd_discard.rel +platform-tbblue/divmmc.rel +platform-tbblue/mbr.rel +platform-tbblue/blkdev.rel +platform-tbblue/devinput.rel +platform-tbblue/zxkeyboard.rel +platform-tbblue/net_native.rel +-e diff --git a/Kernel/platform-tbblue/kernel.def b/Kernel/platform-tbblue/kernel.def new file mode 100644 index 00000000..849a7684 --- /dev/null +++ b/Kernel/platform-tbblue/kernel.def @@ -0,0 +1,11 @@ +U_DATA .equ 0xF000 ; (this is struct u_data from kernel.h) +U_DATA__TOTALSIZE .equ 0x200 ; 256+256 bytes. + +Z80_TYPE .equ 1 + +PROGBASE .equ 0x0000 +PROGLOAD .equ 0x0100 + +NBUFS .equ 5 + +Z80_MMU_HOOKS .equ 0 diff --git a/Kernel/platform-tbblue/load-esx.s b/Kernel/platform-tbblue/load-esx.s new file mode 100644 index 00000000..48d1138f --- /dev/null +++ b/Kernel/platform-tbblue/load-esx.s @@ -0,0 +1,143 @@ +; +; TBBlue bootstrap via ESXDOS API +; +; We are loaded at 0x2000. We load the kernel into banks 16-23 and +; then map most of it in and jump to 0x0100 in the loaded image +; +; As we use higher pages we know that we can return to BASIC and +; stuff like the RAMdisc will remain intact. +; + + .area _BOOT(ABS) + .org 0x2000 + + ; We get run with a valid SP but it's lurking in high space so + ; move sp for banking. +start: + ld (escape),sp + ld sp,#0x8000 + xor a + rst 8 + .db 0x89 + ld (drive),a + + ld hl, #filename + ld b, #0x01 + ld a,(drive) + + rst 8 + .db 0x9A + + jr c, failure + + ld (handle),a + + ; + ; We load the image into high pages so that if we barf + ; everything is good even the ramdisc. + ; + ld a,#16 ; Stuff the first 16K in bank 16/17 + ld hl,#0xC000 + call load16k + + ld a,#18 ; Second bank into 18/19 + call load16k + + ld a,#20 ; Third bank + call load16k + + ld a,#22 + call load16k ; Fourth bank + + ld a,(handle) + rst 8 + .db 0x9B ; Close + + ld hl,#strap + ld de,#0xFF00 + ld bc,#0x0100 + ldir + + ; Now the delicate bit of the operation - taking over the DivMMC/IDE + ; ROM image + + ld hl,#0xFF00 + rst 0x20 ; Terminate esxdos command and return to + ; our bootstrap code we just moved + +load16k: + ld bc,#0x243B + ld e,#0x56 ; 0xC000 mapping register + out (c),e + inc b + out (c),a ; Page requested + inc b + out (c),b ; MMU register 7 + dec b ; back to control port + inc e ; next register + inc a ; next page + out (c),e + inc b + out (c),a + + ld a,(handle) ; Load 16K into that page + ld bc,#0x4000 + ld hl,#0xC000 ; We mapped it at 48K up + rst 8 + .byte 0x9D + ret nc +failure: + ld hl,#ohpoo +fail: + ld a,(hl) + inc hl + or a + jr z, faildone + rst 0x10 + jr fail + ; throw ourselves under the bus +faildone: + ld a,(handle) + or a + jr z, noclose + rst 8 + .byte 0x9B +noclose: + ld sp,(escape) + ret + +ohpoo: + .ascii 'Unable to load Fuzix image' + .db 13,0 +filename: + .asciz 'FUZIX.BIN' +handle: + .db 0 +drive: + .db 0 +escape: + .dw 0 + +; +; Code run from 0xFF00 +; +strap: + ; We are moving interrupt vectors and stuff + di + ; Page in 16/17/18/19/20/21/22 + ; not 23 as that will go over us. Instead the kernel entry will + ; fix that one up + ld a,#16 + ld bc,#0x243B + ld de,#0x5007 +mmuset: + out (c),d ; register + inc b + out (c),a ; data + dec b + inc a ; next page + inc d ; next register + dec e ; are we there yet ? + jr nz, mmuset + + jp 0x0100 diff --git a/Kernel/platform-tbblue/main.c b/Kernel/platform-tbblue/main.c new file mode 100644 index 00000000..cd8de9e4 --- /dev/null +++ b/Kernel/platform-tbblue/main.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include + +uint16_t ramtop = PROGTOP; + +/* On idle we spin checking for the terminals. Gives us more responsiveness + for the polled ports */ +void platform_idle(void) +{ + /* We don't want an idle poll and IRQ driven tty poll at the same moment */ + __asm + halt + __endasm; +} + +uint8_t timer_wait; + +void platform_interrupt(void) +{ + tty_pollirq(); + timer_interrupt(); + poll_input(); + if (timer_wait) + wakeup(&timer_interrupt); +} + +/* This points to the last buffer in the disk buffers. There must be at least + four buffers to avoid deadlocks. */ +struct blkbuf *bufpool_end = bufpool + NBUFS; + +/* + * We pack discard into the memory image is if it were just normal + * code but place it at the end after the buffers. When we finish up + * booting we turn everything from the buffer pool to the start of + * user space into buffers. + * + * Discard gets turned into buffers or user space + */ +void platform_discard(void) +{ + uint16_t discard_size = 0xE000 - (uint16_t)bufpool_end; + bufptr bp = bufpool_end; + + discard_size /= sizeof(struct blkbuf); + + kprintf("%d buffers added\n", discard_size); + + bufpool_end += discard_size; + + memset( bp, 0, discard_size * sizeof(struct blkbuf) ); + + for( bp = bufpool + NBUFS; bp < bufpool_end; ++bp ){ + bp->bf_dev = NO_DEVICE; + bp->bf_busy = BF_FREE; + } +} + +/* Adding dummy swapper since it is referenced by tricks.s */ +void swapper(ptptr p) +{ + p; +} diff --git a/Kernel/platform-tbblue/rules.mk b/Kernel/platform-tbblue/rules.mk new file mode 100644 index 00000000..b24847af --- /dev/null +++ b/Kernel/platform-tbblue/rules.mk @@ -0,0 +1 @@ +export CROSS_CC_SYS5=--codeseg CODE3 diff --git a/Kernel/platform-tbblue/target.mk b/Kernel/platform-tbblue/target.mk new file mode 100644 index 00000000..3bffcde0 --- /dev/null +++ b/Kernel/platform-tbblue/target.mk @@ -0,0 +1 @@ +export CPU = z80 diff --git a/Kernel/platform-tbblue/tbblue.s b/Kernel/platform-tbblue/tbblue.s new file mode 100644 index 00000000..6ba3087b --- /dev/null +++ b/Kernel/platform-tbblue/tbblue.s @@ -0,0 +1,285 @@ +; +; TBBlue hardware support +; + + .module tbblue + + ; exported symbols + .globl init_early + .globl init_hardware + .globl _program_vectors + .globl platform_interrupt_all + .globl interrupt_handler + .globl unix_syscall_entry + .globl null_handler + .globl nmi_handler + + .globl map_kernel + .globl map_process_always + .globl map_process + .globl map_kernel_di + .globl map_process_always_di + .globl map_save_kernel + .globl map_restore + .globl map_kernel_restore + .globl map_video + .globl current_map + + .globl _int_disabled + .globl _vtborder + + ; exported debugging tools + .globl _platform_monitor + .globl _platform_reboot + .globl outchar + + ; imported symbols + .globl _ramsize + .globl _procmem + + .globl _vtoutput + .globl _vtinit + + .globl outcharhex + .globl outhl, outde, outbc + .globl outnewline + .globl outstring + .globl outstringhex + + .include "kernel.def" + .include "../kernel.def" + +; ----------------------------------------------------------------------------- +; COMMON MEMORY BANK (above 0xE000) +; ----------------------------------------------------------------------------- + .area _COMMONMEM + +_platform_monitor: + ; + ; Not so much a monitor as wait for space + ; + ld a, #0x7F + in a, (0xFE) + rra + jr c, _platform_monitor + +_platform_reboot: + di + ; FIXME: put back 48K ROM + rst 0 ; back into our booter + +platform_interrupt_all: + ret + + .area _COMMONDATA + +_int_disabled: + .db 1 + +_vtborder: ; needs to be common + .db 0 + + +; ----------------------------------------------------------------------------- +; KERNEL CODE BANK (below 0xE000, only accessible when the kernel is mapped) +; ----------------------------------------------------------------------------- + .area _CODE + +init_early: + ret + + .area _DISCARD + +init_hardware: + ; set system RAM size + ld hl, #512 ; FIXME: probe not hardcode + ld (_ramsize), hl + ld hl, #448 ; FIXME: TBD + ld (_procmem), hl + + ; Reprogram the TBBlue registers + + ld a,#0x06 + ld de,#0x9B80 ; Turbo on, DivMMC paging off, Multiface off, + ; Sound mode AY + call tbblue_config + + ld a,#0x07 + ld de,#0x0302 ; 14Mhz + call tbblue_config + + ld a,#0x08 + ld de,#0xEECE ; 128K paging(?), no RAM contention, ABC stereo + ; Covox, Timex, Turbosound on + call tbblue_config + + ld a,#0x09 + ld de,#0xFC00 ; Kempston on, divMMC on + call tbblue_config + + ld a,#0x15 + ld de,#0xFF00 ; Lores off, sprites off, border off, normal order + call tbblue_config + + ; Activate Timex screen + ld a,#0x3E + out (0xFF),a + + ; screen initialization + call _vtinit + + ret + +tbblue_config: + ld bc,#0x243B + out (c),a + inc b + ld a,d ; mask + cpl ; bits to keep + in d,(c) ; read register + and d ; mask out bits to change + or e ; mask in new bits + out (c),a ; write register + ret + + +;------------------------------------------------------------------------------ +; COMMON MEMORY PROCEDURES FOLLOW + + .area _COMMONMEM + +_program_vectors: + pop de + pop hl + push hl + push de + call map_process + + ; write zeroes across all vectors + ld hl, #0 + ld de, #1 + ld bc, #0x007f ; program first 0x80 bytes only + ld (hl), #0x00 + ldir + + ; now install the interrupt vector at 0x0038 + ld a, #0xC3 ; JP instruction + ld (0x0038), a + ld hl, #interrupt_handler + ld (0x0039), hl + + ; set restart vector for FUZIX system calls + ld (0x0030), a ; (rst 30h is unix function call vector) + ld hl, #unix_syscall_entry + ld (0x0031), hl + + ld (0x0000), a + ld hl, #null_handler ; to Our Trap Handler + ld (0x0001), hl + + ld (0x0066), a ; Set vector for NMI + ld hl, #nmi_handler + ld (0x0067), hl + + jr map_kernel + +map_process: + ld a, h + or l + jr z, map_kernel +map_process_always: +map_process_always_di: + push af + push bc + push de + push hl + ld hl,(U_DATA__U_PAGE) +map_write_hl: + ; Switch this to nextreg at some point FIXME + ld bc,#0x243b + ld (current_map),hl + ld e,#0x0750 +map_write_loop: + ld a,(hl) + out (c),e + inc b + out (c),a + dec b + dec d + jr nz, map_write_loop + pop hl + pop de + pop bc + pop af + ret + +; +; Save and switch to kernel +; +map_save_kernel: + push hl + ld hl, (current_map) + ld (map_store), hl + pop hl +map_kernel_di: +map_kernel: +map_kernel_restore: + push af + push bc + push de + push hl + ld hl, #kernel_map + jr map_write_hl + +map_video: + push af + push bc + push de + push hl + ld hl, #video_map + jr map_write_hl + +map_restore: + push af + push bc + push de + push hl + ld hl, (map_store) + jr map_write_hl + +; +; We have no easy serial debug output instead just breakpoint this +; address when debugging. +; +outchar: + ld (_tmpout), a + push bc + push de + push hl + push ix + ld hl, #1 + push hl + ld hl, #_tmpout + push hl + call _vtoutput + pop af + pop af + pop ix + pop hl + pop de + pop bc + ret + + .area _COMMONDATA +_tmpout: + .db 1 + +current_map: ; place to store current page pointer + .dw 0 +map_store: ; and the saved one + .dw 0 + +kernel_map: + .db 16, 17, 18, 19, 20, 21, 22 +video_map: + .db 16, 17, 10, 11, 20, 21, 22 diff --git a/Kernel/platform-tbblue/tmxvideo.s b/Kernel/platform-tbblue/tmxvideo.s new file mode 100644 index 00000000..7acae6a9 --- /dev/null +++ b/Kernel/platform-tbblue/tmxvideo.s @@ -0,0 +1,414 @@ +; +; Timex VT primitives +; +; 512 pixel mode +; +; Need to move into one spot and share between tc2068/chloe/tbblue +; + + .module tmxvideo + + ; exported symbols + .globl _plot_char + .globl _scroll_down + .globl _scroll_up + .globl _cursor_on + .globl _cursor_off + .globl _cursor_disable + .globl _clear_lines + .globl _clear_across + .globl _do_beep + .globl _fontdata_8x8 + .globl _curattr + .globl _vtattr + .globl map_kernel + .globl map_video + + ; Build the video library as the only driver + ; We will make this includable at some point + +TMXVID_ONLY .equ 1 + + .area _VIDEO + +; +; zx128 vt primitives hacked a bit +; +; Will be replaced by Timex video shortly +; + ; exported symbols + .globl tmx_plot_char + .globl tmx_scroll_down + .globl tmx_scroll_up + .globl tmx_cursor_on + .globl tmx_cursor_off + .globl tmx_cursor_disable + .globl tmx_clear_lines + .globl tmx_clear_across + .globl tmx_do_beep + .globl _fontdata_8x8 + .globl _curattr + .globl _vtattr + +videopos: + srl d ; we alternate pixels between two screens + push af + ld a,e + and #7 + rrca + rrca + rrca + add a,d + ld d,e + ld e,a + pop af + jr c, rightside + ld a,d + and #0x18 + or #0x40 ; Left screen + ld d,a + jp map_video +rightside: + ld a,d + and #0x18 + or #0x60 ; Left screen + ld d,a + jp map_video + + .if TMXVID_ONLY +_plot_char: + .endif +tmx_plot_char: + pop hl + pop de ; D = x E = y + pop bc + push bc + push de + push hl + + ld hl,(_vtattr) ; l is vt attributes + push hl ; save attributes as inaccessible once vid mapped + + call videopos + + ld b, #0 ; calculating offset in font table + ld a, c + + or a ; clear carry + rla + rl b + rla + rl b + rla + rl b + ld c, a + + ld hl, #_fontdata_8x8-32*8 ; font + add hl, bc ; hl points to first byte of char data + + pop bc + ; We do underline for now - not clear italic or bold are useful + ; with the font we have. + + ; printing +plot_char_loop: + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + bit 1,c ; underline ? + jr nz, last_ul +plot_attr: + ld (de), a + jp map_kernel + +last_ul: + ld a,#0xff + jr plot_attr + + .if TMXVID_ONLY +_clear_lines: + .endif +tmx_clear_lines: + pop hl + pop de ; E = line, D = count + push de + push hl + ; This way we handle 0 correctly + inc d + jr nextline + +clear_next_line: + push de + ld d, #0 ; from the column #0 + ld b, d ; b = 0 + ld c, #64 ; clear 64 cols + push bc + push de + call _clear_across + pop hl ; clear stack + pop hl + + pop de + inc e +nextline: + dec d + jr nz, clear_next_line + + ret + + + .if TMXVID_ONLY +_clear_across: + .endif +tmx_clear_across: + pop hl + pop de ; DE = coords + pop bc ; C = count + push bc + push de + push hl + ld a,c + or a + ret z ; No work to do - bail out + call videopos ; first pixel line of first character in DE + + ; Save it in HL + ld h,d + ld l,e + + xor a + + ; TODO Figure out if starting L or R + bit 5,d + jr nz, clear_start_r + + + ; no boundary checks. Assuming that D + C < SCREEN_WIDTH +clear_line: + + ; Do the left character + ld b, #8 ; 8 pixel lines to clear for this char +clear_char_l: + ld (de), a + inc d + djnz clear_char_l + + ; Left was final char + dec c + jr z, lines_done + + ; Recover position from HL and move 8K up + ld d,h + ld e,l + set 5,d + +clear_start_r: + ld b, #8 ; 8 pixel lines to clear for this char +clear_char_r: + ld (de), a + inc d + djnz clear_char_r + + inc hl + ld d,h + ld e,l + + ; Next character ? + dec c + jr nz, clear_line +lines_done: + jp map_kernel + +copy_line: + ; HL - source, DE - destination + + ; convert line coordinates to screen coordinates both for DE and HL + push de + ex de, hl + call videopos + ex de, hl + pop de + call videopos + + ld c, #8 + +copy_line_nextchar: + push hl + push de + + ld b, #32 + +copy_pixel_line: + ld a, (hl) + ld (de), a + inc e + inc l + djnz copy_pixel_line + + pop de + pop hl + push hl + push de + set 5,d ; Even half + set 5,h + ld b,#32 +copy_pixel_line_r: + ld a,(hl) + ld (de),a + inc e + inc l + djnz copy_pixel_line_r + pop de + pop hl + inc d + inc h + dec c + jr nz, copy_line_nextchar + ret + + ; TODO: the LDIR way should be much faster + + .if TMXVID_ONLY +_scroll_down: + .endif +tmx_scroll_down: + ; set HL = (0,22), DE = (0, 23) + xor a + ld d, a + ld h, a + ld l, #22 + ld e, #23 + ld c, #23 ; 23 lines to move + + call map_video + +loop_scroll_down: + push hl + push de + push bc + + call copy_line + + pop bc + pop de + pop hl + + dec l + dec e + dec c + jr nz, loop_scroll_down + jp map_kernel + + + .if TMXVID_ONLY +_scroll_up: + .endif +tmx_scroll_up: + ; set HL = (0,1), DE = (0, 0) + xor a + ld d, a + ld e, a + ld h, a + ld l, #1 + ld c, #23 ; 23 lines to move + + call map_video + +loop_scroll_up: + push hl + push de + push bc + + call copy_line + + pop bc + pop de + pop hl + + inc l + inc e + dec c + jr nz, loop_scroll_up + jp map_kernel + + .if TMXVID_ONLY +_cursor_on: + .endif +tmx_cursor_on: + pop hl + pop de + push de + push hl + ld (cursorpos), de + + call videopos + ld a, #7 + add a, d + ld d, a + ld a, #0xFF + ld (de), a + jp map_kernel + .if TMXVID_ONLY +_cursor_disable: +_cursor_off: + .endif +tmx_cursor_disable: +tmx_cursor_off: + ld de, (cursorpos) + call videopos + ld a, #7 + add a, d + ld d, a + xor a + ld (de), a + jp map_kernel + + .if TMXVID_ONLY +_do_beep: + .endif +tmx_do_beep: + ret + + .area _DATA + +cursorpos: + .dw 0 + + .area _COMMONDATA + +_curattr: + .db 7 + diff --git a/Kernel/platform-tbblue/tricks.s b/Kernel/platform-tbblue/tricks.s new file mode 100644 index 00000000..62cfb047 --- /dev/null +++ b/Kernel/platform-tbblue/tricks.s @@ -0,0 +1,279 @@ +; 2013-12-21 William R Sowerbutts + + .module tricks + + .globl _ptab_alloc + .globl _makeproc + .globl _chksigs + .globl _getproc + .globl _platform_monitor + .globl trap_illegal + .globl _platform_switchout + .globl _switchin + .globl _doexec + .globl _dofork + .globl _runticks + .globl unix_syscall_entry + .globl interrupt_handler + .globl map_kernel + .globl _need_resched + .globl _int_disabled + .globl _udata + + ; imported debug symbols + .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex + + .include "kernel.def" + .include "../kernel.def" + + .area _COMMONMEM + +_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 + add hl, de ; process ptr + ld a,(hl) + inc hl + ld h,(hl) ; page pointer + ld l,a + + ld bc,#7 + add hl,bc ; common + + ld bc,#0x243B + ld a,#0x57 ; common bank MMU pointer + out (c),a + + ld a, (hl) + inc b + out (c), 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) + ld (_int_disabled),a + or a + ret nz ; in ISR, leave interrupts off + ei + ret ; return with interrupts on + +switchinfail: + call outhl + ld hl, #badswitchmsg + call outstring + ; something went wrong and we didn't switch in what we asked for + jp _platform_monitor + +fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry + +; +; Called from _fork. We are in a syscall, the uarea is live as the +; parent uarea. The kernel is the mapped object. +; +_dofork: + ; always disconnect the vehicle battery before performing maintenance + di ; should already be the case ... belt and braces. + + pop de ; return address + pop hl ; new process p_tab* + push hl + push de + + ld (fork_proc_ptr), hl + + ; prepare return value in parent process -- HL = p->p_pid; + ld de, #P_TAB__P_PID_OFFSET + add hl, de + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; Save the stack pointer and critical registers. + ; When this process (the parent) is switched back in, it will be as if + ; it returns with the value of the child's pid. + push hl ; HL still has p->p_pid from above, the return value in the parent + push ix + push iy + + ; save kernel stack pointer -- when it comes back in the parent we'll be in + ; _switchin which will immediately return (appearing to be _dofork() + ; returning) and with HL (ie return code) containing the child PID. + ; Hurray. + ld (U_DATA__U_SP), sp + + ; now we're in a safe state for _switchin to return in the parent + ; process. + + ; --------- we switch stack copies in this call ----------- + call fork_copy ; copy 0x000 to udata.u_top and the + ; uarea and return on the childs + ; common + ; We are now in the kernel child context + + ; now the copy operation is complete we can get rid of the stuff + ; _switchin will be expecting from our copy of the stack. + pop bc + pop bc + pop bc + + ; The child makes its own new process table entry, etc. + ld hl, #_udata + push hl + ld hl, (fork_proc_ptr) + push hl + call _makeproc + pop bc + pop bc + + ; any calls to map process will now map the childs memory + + ; runticks = 0; + ld hl, #0 + ld (_runticks), hl + ; in the child process, fork() returns zero. + ; + ; And we exit, with the kernel mapped, the child now being deemed + ; to be the live uarea. The parent is frozen in time and space as + ; if it had done a switchout(). + ret + +; +; FIXME: DMA for this ? +; +fork_copy: + ld hl, (fork_proc_ptr) + ld de, #P_TAB__P_PAGE_OFFSET + add hl,de + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + ex de,hl + + ; DE is now the 8 page pointers for the child + + ld hl, (U_DATA__U_PAGE) ; pointer to banks of parent + + ; HL for the parent + + ld b,#7 ; 7 full banks to copy + + ld a,#0xff ; never used page value +fork_copy_loop: + cp (hl) ; same as previous - don't copy + jr z, nocopy + ld a,(hl) + push bc + call do_copy + pop bc +nocopy: + inc hl + inc de + djnz fork_copy_loop + + exx + ld bc,#0x0200 ; 512 bytes at 0xF000 + ; will need changes if we move it! + ld hl,#0x3000 + ld de,#0x5000 + call do_partial_copy + ; + ; Put the MMU mappings back to sanity + ; + jp map_kernel + +do_copy: + ; On entry (HL) is the source bank (DE) is the target bank + ; BC is the size + ; + ; We preserve AF, DE, HL + exx + ld hl,#0x2000 + ld de,#0x4000 + ld bc,#0x2000 +do_partial_copy: + exx + push af + ld bc,#0x243B + ld a,#0x51 + out (c),a ; 2000-4000 + inc b + ld a,(hl) + out (c),a + dec b + ld a,#0x52 ; 4000-6000 + out (c),a + inc b + ld a,(de) + out (c),a + pop af + exx + ldir + exx + ret