From 117b143af365a0f12c290841f8bc7a0ac4ce54c3 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 19 Feb 2019 14:42:29 +0000 Subject: [PATCH] z80: unified z80 4 x 16 bank tricks code And apply it to rc2014 and zeta2 --- Kernel/lib/z80bank16.s | 210 ++++++++++++++++++++++++++++++ Kernel/platform-rc2014/rc2014.s | 5 +- Kernel/platform-rc2014/tricks.s | 194 +-------------------------- Kernel/platform-zeta-v2/tricks.s | 191 +-------------------------- Kernel/platform-zeta-v2/zeta-v2.s | 5 +- 5 files changed, 226 insertions(+), 379 deletions(-) create mode 100644 Kernel/lib/z80bank16.s diff --git a/Kernel/lib/z80bank16.s b/Kernel/lib/z80bank16.s new file mode 100644 index 00000000..fd0cde14 --- /dev/null +++ b/Kernel/lib/z80bank16.s @@ -0,0 +1,210 @@ +; Based on code 2013-12-21 William R Sowerbutts + +; +; This is intended to provide generic support for most 16K multibank +; platforms. +; +; The platform should define +; TOP_PORT the I/O port that the top page byte is +; written into +; +; top_bank must resolve to the byte used to store the top bank value +; in memory +; +; If the platform needs to maniuplate the page byte values then this +; code will need to be copied and tweaked, for now anyway. +; +; fork_copy remains platform specific. +; + + .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 _ramtop + .globl _need_resched + .globl top_bank + .globl _int_disabled + .globl _udata + + ; imported debug symbols + .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex + + .area _COMMONMEM + +; ramtop must be in common for single process swapping cases +; and its a constant for the others from before init forks so it'll be fine +; here +_ramtop: + .dw 0 +_need_resched: + .db 0 + +; Switchout switches out the current process, finds another that is READY, +; possibly the same process, and switches it in. When a process is +; restarted after calling switchout, it thinks it has just returned +; from switchout(). +_platform_switchout: + ; save machine state + + ld hl, #0 ; return code set here is ignored, but _switchin can + ; return from either _switchout OR _dofork, so they must both write + ; U_DATA__U_SP with the following on the stack: + push hl ; return code + push ix + push iy + ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin + + ; find another process to run (may select this one again) + call _getproc + + push hl + call _switchin + + ; we should never get here + call _platform_monitor + +badswitchmsg: .ascii "_switchin: FAIL" + .db 13, 10, 0 + +_switchin: + di + pop bc ; return address + pop de ; new process pointer +; +; FIXME: do we actually *need* to restore the stack ! +; + push de ; restore stack + push bc ; restore stack + + ld hl, #P_TAB__P_PAGE_OFFSET+3 ; Common + add hl, de ; process ptr + ld a, (hl) + ld (top_bank),a + out (TOP_PORT), 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 + diff --git a/Kernel/platform-rc2014/rc2014.s b/Kernel/platform-rc2014/rc2014.s index 69ba516e..f6bf94ae 100644 --- a/Kernel/platform-rc2014/rc2014.s +++ b/Kernel/platform-rc2014/rc2014.s @@ -21,6 +21,7 @@ .globl platform_interrupt_all .globl _copy_common .globl mpgsel_cache + .globl top_bank .globl _kernel_pages .globl _platform_reboot .globl _bufpool @@ -522,7 +523,9 @@ _copy_common: ; MPGSEL registers are read only, so their content is cached here mpgsel_cache: - .db 0,0,0,0 + .db 0,0,0 +top_bank: ; the shared tricks code needs this name for cache+3 + .db 0 ; kernel page mapping _kernel_pages: diff --git a/Kernel/platform-rc2014/tricks.s b/Kernel/platform-rc2014/tricks.s index 871fd0fc..b7f6d3dd 100644 --- a/Kernel/platform-rc2014/tricks.s +++ b/Kernel/platform-rc2014/tricks.s @@ -1,201 +1,15 @@ -; 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 _ramtop - .globl _need_resched - .globl mpgsel_cache - .globl _int_disabled - .globl _udata - - ; imported debug symbols - .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex - .include "kernel.def" .include "../kernel.def" - .area _COMMONMEM - -; ramtop must be in common for single process swapping cases -; and its a constant for the others from before init forks so it'll be fine -; here -_ramtop: - .dw 0 -_need_resched: - .db 0 - -; Switchout switches out the current process, finds another that is READY, -; possibly the same process, and switches it in. When a process is -; restarted after calling switchout, it thinks it has just returned -; from switchout(). -; -; This function can have no arguments or auto variables. -_platform_switchout: - ; save machine state - - ld hl, #0 ; return code set here is ignored, but _switchin can - ; return from either _switchout OR _dofork, so they must both write - ; U_DATA__U_SP with the following on the stack: - push hl ; return code - push ix - push iy - ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin - - ; find another process to run (may select this one again) - call _getproc - - push hl - call _switchin - - ; we should never get here - call _platform_monitor - -badswitchmsg: .ascii "_switchin: FAIL" - .db 13, 10, 0 - -_switchin: - di - pop bc ; return address - pop de ; new process pointer -; -; FIXME: do we actually *need* to restore the stack ! -; - push de ; restore stack - push bc ; restore stack - - ld hl, #P_TAB__P_PAGE_OFFSET+3 ; Common - add hl, de ; process ptr - ld a, (hl) - out (MPGSEL_3), a ; *CAUTION* our stack just left the building - - ; ------- No stack ------- - ; check u_data->u_ptab matches what we wanted - ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab - or a ; clear carry flag - sbc hl, de ; subtract, result will be zero if DE==IX - jr nz, switchinfail - - ; wants optimising up a bit - ld hl, #P_TAB__P_STATUS_OFFSET - add hl, de - ld (hl), #P_RUNNING - - ; runticks = 0 - ld hl, #0 - ld (_runticks), hl +TOP_PORT .equ MPGSEL_3 - ; restore machine state -- note we may be returning from either - ; _switchout or _dofork - ld sp, (U_DATA__U_SP) + .include "../lib/z80bank16.s" - ; ---- 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 + .area _COMMONMEM - ; 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 + .globl mpgsel_cache fork_copy: ld hl, (U_DATA__U_TOP) diff --git a/Kernel/platform-zeta-v2/tricks.s b/Kernel/platform-zeta-v2/tricks.s index c0e8da2b..b7f6d3dd 100644 --- a/Kernel/platform-zeta-v2/tricks.s +++ b/Kernel/platform-zeta-v2/tricks.s @@ -1,198 +1,15 @@ -; 2013-12-21 William R Sowerbutts - .module tricks - .globl _ptab_alloc - .globl _makeproc - .globl _udata - .globl _chksigs - .globl _getproc - .globl _platform_monitor - .globl trap_illegal - .globl _platform_switchout - .globl _switchin - .globl _doexec - .globl _dofork - .globl _runticks - .globl unix_syscall_entry - .globl interrupt_handler - .globl map_kernel - .globl _ramtop - .globl _need_resched - .globl mpgsel_cache - - ; imported debug symbols - .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex - .include "kernel.def" .include "../kernel.def" - .area _COMMONMEM - -; ramtop must be in common for single process swapping cases -; and its a constant for the others from before init forks so it'll be fine -; here -_ramtop: - .dw 0 -_need_resched: - .db 0 - -; Switchout switches out the current process, finds another that is READY, -; possibly the same process, and switches it in. When a process is -; restarted after calling switchout, it thinks it has just returned -; from switchout(). -_platform_switchout: - di - ; save machine state - - ld hl, #0 ; return code set here is ignored, but _switchin can - ; return from either _switchout OR _dofork, so they must both write - ; U_DATA__U_SP with the following on the stack: - push hl ; return code - push ix - push iy - ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin - - ; find another process to run (may select this one again) - call _getproc - - push hl - call _switchin - - ; we should never get here - call _platform_monitor - -badswitchmsg: .ascii "_switchin: FAIL" - .db 13, 10, 0 - -_switchin: - di - pop bc ; return address - pop de ; new process pointer -; -; FIXME: do we actually *need* to restore the stack ! -; - push de ; restore stack - push bc ; restore stack - - ld hl, #P_TAB__P_PAGE_OFFSET+3 ; Common - add hl, de ; process ptr - ld a, (hl) - out (MPGSEL_3), a ; *CAUTION* our stack just left the building - - ; ------- No stack ------- - ; check u_data->u_ptab matches what we wanted - ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab - or a ; clear carry flag - sbc hl, de ; subtract, result will be zero if DE==IX - jr nz, switchinfail - - ; wants optimising up a bit - ld hl, #P_TAB__P_STATUS_OFFSET - add hl, de - ld (hl), #P_RUNNING - - ; runticks = 0 - ld hl, #0 - ld (_runticks), hl +TOP_PORT .equ MPGSEL_3 - ; restore machine state -- note we may be returning from either - ; _switchout or _dofork - ld sp, (U_DATA__U_SP) + .include "../lib/z80bank16.s" - ; ---- New task stack ---- - - pop iy - pop ix - pop hl ; return code - - ; enable interrupts, if the ISR isn't already running - ld a, (U_DATA__U_ININTERRUPT) - or a - ret nz ; in ISR, leave interrupts off - ei - ret ; return with interrupts on - -switchinfail: - call outhl - ld hl, #badswitchmsg - call outstring - ; something went wrong and we didn't switch in what we asked for - jp _platform_monitor - -fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry - -; -; Called from _fork. We are in a syscall, the uarea is live as the -; parent uarea. The kernel is the mapped object. -; -_dofork: - ; always disconnect the vehicle battery before performing maintenance - di ; should already be the case ... belt and braces. - - pop de ; return address - pop hl ; new process p_tab* - push hl - push de - - ld (fork_proc_ptr), hl - - ; prepare return value in parent process -- HL = p->p_pid; - ld de, #P_TAB__P_PID_OFFSET - add hl, de - ld a, (hl) - inc hl - ld h, (hl) - ld l, a - - ; Save the stack pointer and critical registers. - ; When this process (the parent) is switched back in, it will be as if - ; it returns with the value of the child's pid. - push hl ; HL still has p->p_pid from above, the return value in the parent - push ix - push iy - - ; save kernel stack pointer -- when it comes back in the parent we'll be in - ; _switchin which will immediately return (appearing to be _dofork() - ; returning) and with HL (ie return code) containing the child PID. - ; Hurray. - ld (U_DATA__U_SP), sp - - ; now we're in a safe state for _switchin to return in the parent - ; process. - - ; --------- we switch stack copies in this call ----------- - call fork_copy ; copy 0x000 to udata.u_top and the - ; uarea and return on the childs - ; common - ; We are now in the kernel child context - - ; now the copy operation is complete we can get rid of the stuff - ; _switchin will be expecting from our copy of the stack. - pop bc - pop bc - pop bc - - ; The child makes its own new process table entry, etc. - ld hl, #_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 + .area _COMMONMEM - ; 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 + .globl mpgsel_cache fork_copy: ld hl, (U_DATA__U_TOP) diff --git a/Kernel/platform-zeta-v2/zeta-v2.s b/Kernel/platform-zeta-v2/zeta-v2.s index 891f8595..f85dd38e 100644 --- a/Kernel/platform-zeta-v2/zeta-v2.s +++ b/Kernel/platform-zeta-v2/zeta-v2.s @@ -18,6 +18,7 @@ .globl _irqvector .globl platform_interrupt_all .globl mpgsel_cache + .globl top_bank .globl _kernel_pages .globl _platform_reboot .globl _bufpool @@ -319,7 +320,9 @@ map_save_kernel: ; MPGSEL registers are read only, so their content is cached here mpgsel_cache: - .db 0,0,0,0 + .db 0,0,0 +top_bank: ; common library needs this name for the right byte + .db 0 ; kernel page mapping _kernel_pages: -- 2.34.1