From: Alan Cox Date: Sun, 22 Mar 2015 21:48:33 +0000 (+0000) Subject: px4plus: Initial cut of banking support X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=d0ef999330a207ed929d8eac258edb095b6e5325;p=FUZIX.git px4plus: Initial cut of banking support Nothing runnable yet but we now build the PX4/PX4 Plus as a set of banked ROM images which is what is needed. The actual box has 64K RAM (some used for video) 32K OS ROM (CP/M) - overlays low 32K if switched in 2 x up to 32K ROM - overlay 0x6000-0xDFFF The "intelligent" RAMdisc and the sidecar RAM discs are not memory mapped but can be used for task switching/swap. The floppy drive is serial attached at a whopping 19200 baud. --- diff --git a/Kernel/platform-px4plus/README b/Kernel/platform-px4plus/README index 799b1f9f..87db9257 100644 --- a/Kernel/platform-px4plus/README +++ b/Kernel/platform-px4plus/README @@ -9,48 +9,38 @@ top window is awkward as we need to get udata and our kernel data/common in that space if possible. We can hide the font/video below that under the top of the ROM however. - -Intended Memory Map - - -0x0000-0x00FF Vectors -0x0100-0x7CFF (RAM) User program (and discard area) -(could go to 0xBFFF for 48K but our swap is very limiting and might need - smarter algorithms for swap - eg 16K banking for swap alone) -0x7D00-0xCFFF Space for things we can bank under the ROM - (secondary floppy cache ??) -0xD000-0xDFFF Framebuffer, font, video code -0xE000-0xF7FFish Data for kernel -0xF800-0xFCFF Common (currently ends FBCC) -0xFD00-0xFFFF Udata - -In kernel execution modes we then are either - -0x0000-0x00FF Vectors -0x0100-0x5FFF Lower part of user -0x6000-0xDFFF Kernel code in ROM -0xE000-0xF7FFish Data for kernel -0xF800-0xFCFF Common (currently ends FBCC) -0xFD00-0xFFFF Udata - -and we will need to tuck the video code/font/framebuffer at 0xD000 or -similar in RAM under the ROM area. May need to hide the floppy driver -there too as its all a little bit tight - -In practice it appears the answer is - -1. Yes -2. But only if the linker is taught to do banking. In fact once the linker -does its own banking there is plenty of space although the bootloader might -be a bit odd to make it work. - -A better layout given the 128K total swap limit might appear to be - -0x0000-0x00FF Vectors -0x0100-0x7CFF Application -0x7D00-0x7FFF Uarea - -but we actually can't do this because the 32K ROM is always mapped from -0x6000-0xDFFF and needs to access the Uarea - +Banked Memory Map +----------------- + +0x0000-0x00FF Vectors (which IM ? PX8 is IM2) +0x0100-0x5FFF Kernel mappings +0x6000-0xDFFF Switched segments 8/16/32K ROM x 2 or RAM + 0x6000-0xDFFF Application space (32K) [need to use a bit under + as 120K not 128K of swap] + 0x6000-0xDFFF CODE1/CODE2 } Both with copies of some of common + 0x6000-0xDFFF CODE3/Video } and rodata at same address range + [ Do we want to generate interleaved banking ? ] + +0xE000-0xFCFF Writable kernel data + Framebuffer (4K) +0xFD00-0xFFFF UDATA + +We also need to put a catalogue in the middle of one of the two ROM blocks +annoyingly. However that plays into our hands in other ways as we can +minimally fake a disk rom holding a CP/M app which in fact runs the OS. + + +Applications are swapped to/from the PX4Plus RAM disc (120K) allowing about +4 apps of just under 32K each. Storage I/O is via the serial floppy and/or +optional RAM/ROM cartriges. External 128K cartridges would also work for +swap with floppy for OS. If the swap is custom handled in switching then +we can switch the 32K rather than copy and gain another process, plus real +floppy swap option. + +CP/M BIOS can be used (it's another 32K map over 0-7FFF, but as that maps +over the vectors we must ensure its always called with interrupts off). + +The PX-8 is different: There is only a single 32K system ROM, but no video +overhead. In theory its sufficient if we are replacing the OS ROM, and using +the intelligent RAM disc, or the homebrew 512K one, plus floppies diff --git a/Kernel/platform-px4plus/config.h b/Kernel/platform-px4plus/config.h index f8522b1f..da94d3c6 100644 --- a/Kernel/platform-px4plus/config.h +++ b/Kernel/platform-px4plus/config.h @@ -12,8 +12,6 @@ #define CONFIG_VT /* We want the 8x8 font for now (actually we want 6x8) */ #define CONFIG_FONT8X8 -/* And we only want 128 symbols of it (1K) for now */ -#define CONFIG_FONT8X8SMALL /* CP/M emulation */ #undef CONFIG_CPM_EMU /* Fixed banking */ @@ -31,14 +29,16 @@ /* FIXME: the OVL timer isn't quite 100/sec and we have an accurate 1Hz timer available, so needs some tweaking */ #define TICKSPERSEC 100 /* Ticks per second */ -#define PROGBASE 0x0000 /* also data base */ -#define PROGLOAD 0x0100 -#define PROGTOP 0x4000 /* Top of program for debug */ +#define PROGBASE 0x6000 /* also data base */ +#define PROGLOAD 0x6000 +#define PROGTOP 0xDD00 /* Top of program */ -#define SWAP_SIZE 0x40 /* 32K in blocks (with uarea means 31K max app size) */ -#define SWAPBASE 0x0000 /* We swap the lot in one, include the */ -#define SWAPTOP 0x8000 /* vectors so its a round number of sectors */ -#define MAX_SWAPS 4 /* We have a whopping 128K of RAMDISC! */ +/* FIXME: treat the banks of the ramdisc as memory not swap, also trim + to 30K as only have 120K of RAMdisc */ +#define SWAP_SIZE 0x3C /* 30K in blocks (with uarea means 29.25K max app size) */ +#define SWAPBASE (uint8_t *)0x5D00 /* We swap the lot in one, include the */ +#define SWAPTOP (uint8_t *)0xDD00 /* vectors so its a round number of sectors */ +#define MAX_SWAPS 4 /* We have a whopping 120K of RAMDISC! */ #define BOOT_TTY (512 + 1)/* Set this to default device for stdio, stderr */ /* In this case, the default is the first TTY device */ @@ -60,4 +60,4 @@ #define VT_BOTTOM 7 -#define PFTABSIZE 4 /* All we have room for right now */ +#define PFTABSIZE 5 /* All we have room for right now */ diff --git a/Kernel/platform-px4plus/crt0.s b/Kernel/platform-px4plus/crt0.s index d559e89e..558ed26c 100644 --- a/Kernel/platform-px4plus/crt0.s +++ b/Kernel/platform-px4plus/crt0.s @@ -6,26 +6,33 @@ ; WRS: Note we list all our segments here, even though ; we don't use them all, because their ordering is set ; when they are first seen. - .area _CODE - .area _CODE2 + + ; Stuff that ends up in RAM, initialized bits first then data + ; We will need to pull the initialized bits into ROM for crt0.s + ; to ldir down + .area _COMMONMEM .area _CONST - .area _DATA .area _INITIALIZED - .area _COMMONMEM + .area _STUBS + .area _DATA .area _BSEG .area _BSS .area _HEAP .area _GSINIT .area _GSFINAL - - .area _DISCARD + ; Udata ends up just below program code (so we can swap it easily) .area _UDATA - ; This is fixed up by the compile tool but we need it somewhere - ; so the copier can fix it up ! - .area _INITIALIZER - + ; First ROM is CODE (CODE2 folded in) + .area _CODE + ; Second ROM is CODE3 VIDEO FONT and initialized data to copy down + .area _CODE3 .area _FONT .area _VIDEO + .area _INITIALIZER + ; Discard needs splitting code/data! + .area _DISCARD + ; and the bitmap display lives at E000-FFFF + ; imported symbols .globl _fuzix_main @@ -62,3 +69,6 @@ init: stop: halt jr stop + .area _STUBS +stubs: + .ds 768 diff --git a/Kernel/platform-px4plus/fuzix.lnk b/Kernel/platform-px4plus/fuzix.lnk index 533af34e..2dbacb51 100644 --- a/Kernel/platform-px4plus/fuzix.lnk +++ b/Kernel/platform-px4plus/fuzix.lnk @@ -1,19 +1,19 @@ -mwxuy -i fuzix.ihx +-b _COMMONMEM=0x0100 +-b _UDATA=0x5D00 -b _DISCARD=0x4000 --b _UDATA=0xFD00 -b _CODE=0x6000 --b _DATA=0xE000 --b _FONT=0x5000 --b _INITIALIZER=0x3000 +-b _CODE3=0x6000 -l z80 +-r platform-px4plus/crt0.rel platform-px4plus/commonmem.rel platform-px4plus/px4plus.rel platform-px4plus/main.rel start.rel version.rel -lowlevel-z80.rel +lowlevel-z80-banked.rel platform-px4plus/tricks.rel timer.rel kdata.rel diff --git a/Kernel/platform-px4plus/px4plus.s b/Kernel/platform-px4plus/px4plus.s index 30e00d03..b9bcddfc 100644 --- a/Kernel/platform-px4plus/px4plus.s +++ b/Kernel/platform-px4plus/px4plus.s @@ -48,6 +48,27 @@ .globl _ramd_uaddr + .globl __bank_0_1 + .globl __bank_0_2 + .globl __bank_0_3 + .globl __bank_1_2 + .globl __bank_1_3 + .globl __bank_2_1 + .globl __bank_2_3 + .globl __bank_3_1 + .globl __bank_3_2 + + .globl __stub_0_1 + .globl __stub_0_2 + .globl __stub_0_3 + .globl __stub_1_2 + .globl __stub_1_3 + .globl __stub_2_1 + .globl __stub_2_3 + .globl __stub_3_1 + .globl __stub_3_2 + + .include "kernel.def" .include "../kernel.def" @@ -89,14 +110,18 @@ init_hardware: ; set up interrupt vectors for the kernel ld hl, #0 push hl + push af call _program_vectors + pop af pop hl ; IRQ enables ld a, #0xB ; OVF (timer), RXRDY (gapnio), 7508 out (0x04), a + push af call _vtinit + pop af im 1 ; set CPU interrupt mode ret @@ -234,3 +259,194 @@ hd_xoloop: inc (hl) dec hl jr hd_xiloop + + +; +; FIXME +current_map: + .byte 0 +switch_bank: + ret +; +; +; Banking helpers +; +; FIXME: these are from zx128 - not yet converted to px4plus. We +; should also be able to dump all to/from bank2 versions +; +; +; Logical Physical +; 0 COMMON (0x4000) +; 1 0 +; 2 1 +; 3 7 +; +; +__bank_0_1: + xor a ; switch to physical bank 0 (logical 1) +bankina0: + ; + ; Get the target address first, otherwise we will change + ; bank and read it from the wrong spot! + ; + pop hl ; Return address (points to true function address) + ld e, (hl) ; DE = function to call + inc hl + ld d, (hl) + inc hl + push hl ; Restore corrected return pointer + ld bc, (current_map) ; get current bank into B + call switch_bank ; Move to new bank + ; figure out which bank to map on the return path + ld a, c + or a + jr z, __retmap1 + dec a + jr z, __retmap2 + jr __retmap3 + +callhl: jp (hl) +__bank_0_2: + ld a, #1 ; logical 2 -> physical 1 + jr bankina0 +__bank_0_3: + ld a, #7 ; logical 3 -> physical 7 + jr bankina0 + +__bank_1_2: + ld a, #1 +bankina1: + pop hl ; Return address (points to true function address) + ld e, (hl) ; DE = function to call + inc hl + ld d, (hl) + inc hl + push hl ; Restore corrected return pointer + call switch_bank ; Move to new bank +__retmap1: + ex de, hl + call callhl ; call the function + xor a ; return to bank 1 (physical 0) + jp switch_bank + +__bank_1_3: + ld a, #7 + jr bankina1 +__bank_2_1: + xor a +bankina2: + pop hl ; Return address (points to true function address) + ld e, (hl) ; DE = function to call + inc hl + ld d, (hl) + inc hl + push hl ; Restore corrected return pointer + call switch_bank ; Move to new bank +__retmap2: + ex de, hl + call callhl ; call the function + ld a, #1 ; return to bank 2 + jp switch_bank +__bank_2_3: + ld a, #7 + jr bankina2 +__bank_3_1: + xor a +bankina3: + pop hl ; Return address (points to true function address) + ld e, (hl) ; DE = function to call + inc hl + ld d, (hl) + inc hl + push hl ; Restore corrected return pointer + call switch_bank ; Move to new bank +__retmap3: + ex de, hl + call callhl ; call the function + ld a, #7 ; return to bank 0 + jp switch_bank + +__bank_3_2: + ld a, #1 + jr bankina3 + +; +; Stubs need some stack munging and use DE +; + +__stub_0_1: + xor a +__stub_0_a: + pop hl ; the return + ex (sp), hl ; write it over the discard + ld bc, (current_map) + call switch_bank + ld a, c + or a + jr z, __stub_1_ret + dec a + jr z, __stub_2_ret + jr __stub_3_ret +__stub_0_2: + ld a, #1 + jr __stub_0_a +__stub_0_3: + ld a, #7 + jr __stub_0_a + +__stub_1_2: + ld a, #1 +__stub_1_a: + pop hl ; the return + ex (sp), hl ; write it over the discad + call switch_bank +__stub_1_ret: + ex de, hl + call callhl + xor a + call switch_bank + pop de + push de ; dummy the caller will discard + push de + ret +__stub_1_3: + ld a, #7 + jr __stub_1_a + +__stub_2_1: + xor a +__stub_2_a: + pop hl ; the return + ex (sp), hl ; write it over the discad + call switch_bank +__stub_2_ret: + ex de, hl ; DE is our target + call callhl + ld a,#1 + call switch_bank + pop de + push de ; dummy the caller will discard + push de + ret +__stub_2_3: + ld a, #7 + jr __stub_2_a + +__stub_3_1: + xor a +__stub_3_a: + pop hl ; the return + ex (sp), hl ; write it over the discad + call switch_bank +__stub_3_ret: + ex de, hl + call callhl + ld a,#7 + call switch_bank + pop de + push de ; dummy the caller will discard + push de + ret +__stub_3_2: + ld a, #1 + jr __stub_3_a diff --git a/Kernel/platform-px4plus/tricks.s b/Kernel/platform-px4plus/tricks.s index 25710903..00a546e3 100644 --- a/Kernel/platform-px4plus/tricks.s +++ b/Kernel/platform-px4plus/tricks.s @@ -37,7 +37,9 @@ ; This function can have no arguments or auto variables. _switchout: di + push af call _chksigs + pop af ; save machine state ld hl, #0 ; return code set here is ignored, but _switchin can @@ -53,10 +55,14 @@ _switchout: ld (_inint), a ; find another process to run (may select this one again) + push af call _getproc + pop af push hl + push af call _switchin + pop af ; we should never get here call _trap_monitor @@ -68,6 +74,7 @@ swapped: .ascii "_switchin: SWAPPED" _switchin: di + pop hl pop bc ; return address pop de ; new process pointer ; @@ -75,6 +82,7 @@ _switchin: ; push de ; restore stack push bc ; restore stack + push hl push de ld hl, #P_TAB__P_PAGE_OFFSET @@ -95,11 +103,15 @@ _switchin: ; We will always swap out the current process ld hl, (U_DATA__U_PTAB) push hl + push af call _swapout + pop af pop hl pop hl push de + push af call _swapper + pop af pop de pop hl ld a, (hl) @@ -156,10 +168,12 @@ _dofork: ; always disconnect the vehicle battery before performing maintenance di ; should already be the case ... belt and braces. + pop bc pop de ; return address pop hl ; new process p_tab* push hl push de + push bc ld (fork_proc_ptr), hl @@ -189,7 +203,9 @@ _dofork: ld hl, (U_DATA__U_PTAB) push hl + push af call _swapout + pop af pop hl ; now the copy operation is complete we can get rid of the stuff @@ -201,7 +217,9 @@ _dofork: ; Make a new process table entry, etc. ld hl, (fork_proc_ptr) push hl + push af call _newproc + pop af pop bc ; runticks = 0;