From: Alan Cox Date: Mon, 26 Nov 2018 13:55:03 +0000 (+0000) Subject: zxdiv: split more stuff out into dev/zx/ X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=449231f220e85fd25fade44ba28a02aef3861e7b;p=FUZIX.git zxdiv: split more stuff out into dev/zx/ Share all the video and tricks code we can --- diff --git a/Kernel/dev/zx/tricks.s b/Kernel/dev/zx/tricks.s new file mode 100644 index 00000000..7b259ace --- /dev/null +++ b/Kernel/dev/zx/tricks.s @@ -0,0 +1,471 @@ +; Based on the Z80 Pack banked code +; +; Should unify this somewhat with lib/banked +; + + .module tricks + + .globl _ptab_alloc + .globl _newproc + .globl _getproc + .globl _platform_monitor + .globl trap_illegal + .globl _platform_switchout + .globl _switchin + .globl _low_bank + .globl _dup_low_page + .globl _dofork + .globl _runticks + .globl unix_syscall_entry + .globl interrupt_handler + .globl current_map + .globl _ptab + .globl _swapper + .globl _int_disabled + .globl switch_bank + + ; imported debug symbols + .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex + + .include "kernel.def" + .include "../kernel.def" + + .area _COMMONMEM + +; 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 a,(current_map) + push af + + ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin + + ; + ; We are now running on the sleeping process stack. The switchin + ; will simply go back to the saved SP above and discard anything + ; here + ; + + ; Stash the uarea back into process memory + ld hl, (U_DATA__U_PAGE) + ld a, l + ld bc, #0x7ffd + or #BANK_BITS + out (c), a + + ; This includes the stacks, so be careful on restore + ld hl, #U_DATA + ld de, #U_DATA_STASH + ld bc, #U_DATA__TOTALSIZE + ldir + ld a, (current_map) + or #BANK_BITS + ld bc, #0x7ffd + out (c), a + + ; find another process to run (may select this one again) + push af + call _getproc + pop af ; we can't optimise this as the linker + ; is entitled to patch the 5 bytes here into a + ; banked call + push hl + push af + call _switchin + + ; we should never get here + call _platform_monitor + +badswitchmsg: .ascii "_switchin: FAIL" + .db 13, 10, 0 + +_switchin: + di + pop hl ; far padding + 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 + push hl ; far padding + + push de + ld hl, #P_TAB__P_PAGE_OFFSET + add hl, de ; process ptr + pop de + ; + ; Get ourselves a valid private stack ASAP. We are going to + ; copy udata around and our main stacks are in udata + ; + ld sp, #_swapstack + + ld a, (hl) ; 0 swapped, not zero is the bank for C000 + or a + jr nz, not_swapped + + ; Swap the process in (this may swap something else out first) + ; The second pushes are C function arguments. SDCC can trample + ; these + + ; Turn this one once we have it all sorted and debugged + ; ei + ; xor a + ; ld (_int_disabled),a + push hl ; Save + push de + push hl ; Arguments + push de + push af + call _swapper + pop af + pop af + pop af + pop de ; Restore + pop hl + ld a,#1 + ld (_int_disabled),a + di + ld a, (hl) ; We should now have a page assigned +not_swapped: + ld hl,(U_DATA__U_PTAB) + or a + sbc hl,de +; Turn this on once debugged +; jr z, skip_copyback + + ; We are in DI so we can poke these directly but must not invoke + ; any code outside of common + or #BANK_BITS ; ROM + ; Pages please ! + ld bc, #0x7ffd + out (c), a + + ; Copy the stash from the user page back down into common + ; The alternate registers are free - we use them for the + ; block copy and for the flipper + ; + ; FIXME: Add Tormod's optimisation from the 6809 tree + ; + exx + ld hl, #U_DATA_STASH + ld de, #U_DATA + ld bc, #U_DATA__TOTALSIZE + ldir + exx + ; + ; Remap the kernel proper + ; + + ld a, (current_map) + or #BANK_BITS + ld bc, #0x7ffd + out (c), a + + ; Is our low data in 0x8000 already or do we need to flip + ; it with bank 6. _low_bank holds the page pointer of the + ; task owning the space + + ld hl, (_low_bank) ; who owns low memory + or a + sbc hl, de ; preserve DE + jr z, nofliplow ; skip the flip if we own low bank +; +; Flip low banks over. Preserve DE +; +fliplow: + exx + ld hl, #0x8000 + ld de, #0xc000 + ld a, #6 + BANK_BITS + ld bc, #0x7ffd + out (c), a +flip2: + ld b, #0 ; 256 bytes per outer loop (16K total) +flip1: + ld c, (hl) + ld a, (de) + ex de, hl + ld (hl), c + ld (de), a + inc hl + inc de + djnz flip1 + xor a + cp d ; Wrapped to 0x0000 ? + jr nz, flip1 + + ld a, (current_map) + or #BANK_BITS + ld bc, #0x7ffd + out (c), a + exx + ld (_low_bank), de ; we own it now + +nofliplow: + + ; 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 == HL + jr nz, switchinfail + + ; wants optimising up a bit + ld ix, (U_DATA__U_PTAB) + ; next_process->p_status = P_RUNNING + ld P_TAB__P_STATUS_OFFSET(ix), #P_RUNNING + + ; Fix any moved page pointers + ; Just do one byte as that is all we use on this platform + ld a, P_TAB__P_PAGE_OFFSET(ix) + ld (U_DATA__U_PAGE), a + ; 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) + + ; + ; We can now use the stack again + ; + + pop af + pop iy + pop ix + pop hl ; return code + + ; Make sure we have the right kernel bank to return to + call switch_bank + + ; 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 + +; Interrupts should be off when this is called +_dup_low_page: + di ; FIXME: check callers properly + ld a, #0x06 + BANK_BITS ; low page alternate + ld bc, #0x7ffd + out (c), a + + ld hl, #0x8000 ; fixed + ld de, #0xC000 ; page we just mapped in + ld bc, #16384 + ldir + + ld a, (current_map) ; restore mapping + or #BANK_BITS ; ROM bits + ld bc, #0x7ffd + out (c), a + ret + + +; +; 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 bc + pop de ; return address + pop hl ; new process p_tab* + push hl + push de + push bc + + 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 + + ld a,(current_map) + push af + + ; 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. + + ; Need to write a new 16K bank copy here, then copy the live uarea + ; into the stash of the new process + + ; --------- copy process --------- + + ld hl, (fork_proc_ptr) + ld (_low_bank), hl ; low bank will become the child + ld de, #P_TAB__P_PAGE_OFFSET ; bank number + add hl, de + ; load p_page + ld c, (hl) + ld hl, (U_DATA__U_PAGE) + ld a, l + + ; + ; Copy the high page via the bounce buffer + ; + + call bankfork ; do the bank to bank copy + + ; FIXME: if we support small apps at C000-FBFF we need to tweak this + ; Now copy the 0x8000-0xBFFF area directly + + ld a, #0x06 + BANK_BITS ; low page alternate + ld bc, #0x7ffd + out (c), a + + ld hl, #0x8000 ; Fixed + ld de, #0xC000 ; Page we just mapped in + ld bc, #16384 + ldir + + ; Copy done + + ld a, (U_DATA__U_PAGE) ; parent memory + or #BANK_BITS ; get the right ROMs + ld bc, #0x7ffd + out (c), a ; Switch context to parent in 0xC000+ + + ; We are going to copy the uarea into the parents uarea stash + ; we must not touch the parent uarea after this point, any + ; changes only affect the child + ld hl, #U_DATA ; copy the udata from common into the + ld de, #U_DATA_STASH ; target process + ld bc, #U_DATA__TOTALSIZE + ldir + + ; + ; And back into the kernel + ; + ld bc, #0x7ffd + ld a, (current_map) + or #BANK_BITS + out (c), a + ; 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 iy + pop ix + pop bc + + ; Make a new process table entry, etc. + ld hl, (fork_proc_ptr) + push hl + push af + call _newproc + pop af + pop bc + + ; 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 + +; +; This is related so we will keep it here. Copy the process memory +; for a fork. a is the page base of the parent, c of the child +; (this API will be insufficient once we have chmem and proper use of +; banks - as well as needing to support fork to disk) +; +; Assumption - fits into a fixed number of whole 256 byte blocks +; +; +; Note: this needs reviewing. We now have a lot more program memory +; we can use with a lazy copying model +; +bankfork: + or #BANK_BITS ; ROM bits for the bank + ld b, #0x3E ; 64 x 256 minus 2 sets for the uarea stash/irqs + ld hl, #0xC000 ; base of memory to fork (vectors included) +bankfork_1: + push bc ; Save our counter and also child offset + push hl + ld bc, #0x7ffd + out (c), a ; switch to parent bank + ld de, #bouncebuffer + ld bc, #256 + ldir ; copy into the bounce buffer + pop de ; recover source of copy to bounce + ; as destination in new bank + pop bc ; recover child port number + push bc + ld b, a ; save the parent bank id + ld a, c ; switch to the child + push bc ; save the bank pointers + ld bc, #0x7ffd + or #BANK_BITS ; ROM bits + out (c), a + ld hl, #bouncebuffer + ld bc, #256 + ldir ; copy into the child + pop bc ; recover the bank pointers + ex de, hl ; destination is now source for next bank + ld a, b ; parent back is wanted in a + pop bc + djnz bankfork_1 ; rinse, repeat + ret +; +; For the moment +; + .area _COMMONDATA +bouncebuffer: + .ds 256 +; We can keep a stack in common because we will complete our +; use of it before we switch common block. In this case we have +; a true common so it's even easier. We never use both at once +; so share with bouncebuffer +_swapstack: +_low_bank: + .dw _ptab ; Init starts owning this + +fork_proc_ptr: + .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry diff --git a/Kernel/dev/zx/video.s b/Kernel/dev/zx/video.s new file mode 100644 index 00000000..ef87e253 --- /dev/null +++ b/Kernel/dev/zx/video.s @@ -0,0 +1,371 @@ +; +; zx128 vt primitives +; + ; exported symbols + .globl zx_plot_char + .globl zx_scroll_down + .globl zx_scroll_up + .globl zx_cursor_on + .globl zx_cursor_off + .globl zx_cursor_disable + .globl zx_clear_lines + .globl zx_clear_across + .globl zx_do_beep + .globl _fontdata_8x8 + .globl _curattr + .globl _vtattr + +videopos: + ld a,e + and #7 + rrca + rrca + rrca + add a,d + ld d,e + ld e,a + ld a,d + and #0x18 + or #0x40 ; Standard screen + ld d,a + ret + +videoattr: + ; 32 x E + D into HL + ld a,e + rrca + rrca + rrca ; A is now 32xE with the top bits overflowed + ; into the low 2 bits + ld l,a + and #3 ; Extract the low 2 bits for the high + add #0x58 ; Attributes start 0x5800 + ld h,a + ld a,l + and #0xE0 ; mask the bits that are valid + add d ; add the low 5 bits from D + ld l,a ; and done (the add can't overflow) + ret + + .if ZXVID_ONLY +_plot_char: + .endif +zx_plot_char: + pop iy + pop hl + pop de ; D = x E = y + pop bc + push bc + push de + push hl + push iy + + push de + 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 + + ; We do underline for now - not clear italic or bold are useful + ; with the font we have. + ld bc,(_vtattr) ; c is vt attributes + + ; printing +plot_char_loop: + ld a, (hl) + ld (de), a + inc l ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc l ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc l ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc l ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc l ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc l ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc l ; 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 + + pop de + call videoattr + ld a,(_curattr) + ld (hl),a + ret + +last_ul: + ld a,#0xff + jr plot_attr + + .if ZXVID_ONLY +_clear_lines: + .endif +zx_clear_lines: + pop bc + pop hl + pop de ; E = line, D = count + push de + push hl + push bc + ; 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, #32 ; clear 32 cols + push bc + push de + push af + call _clear_across + pop af + pop hl ; clear stack + pop hl + + pop de + inc e +nextline: + dec d + jr nz, clear_next_line + + ret + + + .if ZXVID_ONLY +_clear_across: + .endif +zx_clear_across: + pop iy + pop hl + pop de ; DE = coords + pop bc ; C = count + push bc + push de + push hl + push iy + ld a,c + or a + ret z ; No work to do - bail out + push de + push bc + call videopos ; first pixel line of first character in DE + push de + pop hl ; copy to hl + xor a + + ; no boundary checks. Assuming that D + C < SCREEN_WIDTH + +clear_line: + ld b, #8 ; 8 pixel lines to clear for this char +clear_char: + ld (de), a + inc d + djnz clear_char + + ex de, hl + inc de + push de + pop hl + + dec c + jr nz, clear_line + pop bc + pop de + call videoattr + ld a,(_curattr) + ld b,c +setattr: + ld (hl),a + inc hl + djnz setattr + ret + +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 + inc d + inc h + dec c + jr nz, copy_line_nextchar + ret + + ; TODO: the LDIR way should be much faster + + .if ZXVID_ONLY +_scroll_down: + .endif +zx_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 + +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 + + ; Attributes + ld hl,#0x5ADF + ld de,#0x5AFF + ld bc,#0x02E0 + lddr + + ret + + + .if ZXVID_ONLY +_scroll_up: + .endif +zx_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 + +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 + + ld hl,#0x5820 + ld de,#0x5800 + ld bc,#0x02E0 + ldir + ret + + .if ZXVID_ONLY +_cursor_on: + .endif +zx_cursor_on: + pop bc + pop hl + pop de + push de + push hl + push bc + ld (cursorpos), de + + call videopos + ld a, #7 + add a, d + ld d, a + ld a, #0xFF + ld (de), a + ret + .if ZXVID_ONLY +_cursor_disable: +_cursor_off: + .endif +zx_cursor_disable: +zx_cursor_off: + ld de, (cursorpos) + call videopos + ld a, #7 + add a, d + ld d, a + xor a + ld (de), a + + .if ZXVID_ONLY +_do_beep: + .endif +zx_do_beep: + ret + + .area _DATA + +cursorpos: + .dw 0 diff --git a/Kernel/platform-zxdiv/loader.s b/Kernel/platform-zxdiv/loader.s deleted file mode 100644 index a8661819..00000000 --- a/Kernel/platform-zxdiv/loader.s +++ /dev/null @@ -1,199 +0,0 @@ -; -; DivIDE is a bit of a pain as all the firmware is designed around -; ROM BASIC and snapshots. We trick it by providing a fake BOOT.BIN. -; Fatware thinks that this is the Fatware code it wants to put in -; bank3 and then lock. In fact it's our loader which it will load -; and lock for us. -; - .area BOOT (ABS) - - .globl null_handler - .globl unix_syscall_entry - .globl interrupt_handler - - .org 0 - -; -; We don't have a JP at 0 as we'd like so our low level code needs -; to avoid that check -; -loader: - di - ld a,#0x80 - out (0xE3),a - ; Page the EEPROM in and control transfers there - ; not to the jp below -loader5: - ; This is where the EEPROM calls us - jp start -rst_8: - .ds 8 -rst_10: - .ds 8 -rst_18: - .ds 8 -rst_20: - .ds 8 -rst_28: - .ds 8 -rst_30: - jp unix_syscall_entry - .ds 5 -rst_38: - jp interrupt_handler - .ds 0x66-0x3B -nmi: ret ; magic... - retn - -; -; Load and go -; -start: - ld bc,#0x7ffd - - ; Map some RAM (must not be RAM2) in 2000-3FFF - ld a,#0x40 - out (0xE3),a - - ; Stack in the first 512 bytes of our data space - ld sp,#0x2200 - - ; Select the shadow screen bank - ld a,#0x17 - out (c), a - - ; Clear the shadow screen - ld hl,#0xc000 - ld de,#0xc001 - ld bc,#6144 - ld (hl),#0 - ldir - ; Attributes to green writing on black - ld (hl),#4 - ld bc,#767 - ldir - - ; Black border - xor a - out (254),a - - ; Shadow screen on, bank 0 back at C000-FFFF - ld bc,#0x7ffd - ld a,#0x18 - out (c),a - - ; Screen is now on bank 7 - ; Memory is on bank 0 - - ; Put some RAM in 0x2000-3FFF and keep us locked in the low 8K - ; Do not use #0x42, this is magic for allram mode on later DivIDE - ld a,#0x40 - out (0xE3),a - ; - ; Ensure the master drive is selected - ; -wait1: - in a,(191) - rla - jr c, wait1 - ld a,#0xE0 - out (187),a - nop -wait2: - in a,(191) - and #0xC0 - cp #0x40 ; want busy off, drdy - jr nz, wait2 - - ; - ; Load sectors. We shortcut stuff here because we never - ; load over 256 sectors - ; - ; - ; We load 112 sectors into 2000-FFFF using bank 0 as the top bank - ; We then load 32 sectors into the 16K at C000-FFFF bank 1 - ; And finally the same for bank 7 - ; 0x2000 should start ZB then the execution address - ; - ; For simplicity we don't bother with a stack, we just use IX - ; - xor a ; LBA 0 - out (175),a - out (179),a - ld de,#0x7001 ; Load 111 sectors (2200-FFFF) - ; from sector 1 - ld hl,#0x2200 ; Starting address to load - call load_loop - - ld a,#0x19 ; Select bank 1 - ld bc,#0x7ffd - ld d,#0x20 ; Load 32 sectors (C000-FFFF) - ld hl,#0xc000 - call load_loop - - ld a,#0x1F ; Select bank 7 - ld bc,#0x7ffd - out (c),a - ld d,#0x20 ; Load 32 sectors (C000-FFFF) - ld hl,#0xC000 - call load_loop - - ld a,#0x18 - ld bc,#0x7ffd - out (c),a ; Switch back to bank 0 - ld hl,#0x2200 - ; 0x2200 should start with a signature of ZB then the execute - ; address - ld a,(hl) - cp #'Z' - jr nz, failed - inc hl - ld a,(hl) - cp #'B' - jr nz, failed - inc hl - ld a,(hl) - inc hl - ld h,(hl) - ld l,a - jp (hl) - -load_loop: - ld a,e - inc e - out (183),a ; sector number to load - ld a,#1 ; load one sector - out (171),a - ld a,#0x20 ; READ - out (191),a - nop -wait3: - in a, (191) - rlca - jr c, wait3 ; Busy - bit 4,a ; DRQ ? - jr z, failed ; Nope - bad - ld bc,#163 ; Data port - inir - inir - dec d - jr nz, load_loop - ret - -failed: - ld hl,#1 - jp OutJPHL ; Into Spectrum ROM and reboot - - - .area BOOT1FF7 - - ; - ; For compatibility with FatWare - ; -OutEI: ei -OutRet: ret -OutJPHL: jp (hl) - - .area BOOT1FFE -RomSign: - .db 0,14 diff --git a/Kernel/platform-zxdiv/tricks.s b/Kernel/platform-zxdiv/tricks.s index 7b259ace..c3339105 100644 --- a/Kernel/platform-zxdiv/tricks.s +++ b/Kernel/platform-zxdiv/tricks.s @@ -1,471 +1,2 @@ -; Based on the Z80 Pack banked code -; -; Should unify this somewhat with lib/banked -; - .module tricks - - .globl _ptab_alloc - .globl _newproc - .globl _getproc - .globl _platform_monitor - .globl trap_illegal - .globl _platform_switchout - .globl _switchin - .globl _low_bank - .globl _dup_low_page - .globl _dofork - .globl _runticks - .globl unix_syscall_entry - .globl interrupt_handler - .globl current_map - .globl _ptab - .globl _swapper - .globl _int_disabled - .globl switch_bank - - ; imported debug symbols - .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex - - .include "kernel.def" - .include "../kernel.def" - - .area _COMMONMEM - -; 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 a,(current_map) - push af - - ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin - - ; - ; We are now running on the sleeping process stack. The switchin - ; will simply go back to the saved SP above and discard anything - ; here - ; - - ; Stash the uarea back into process memory - ld hl, (U_DATA__U_PAGE) - ld a, l - ld bc, #0x7ffd - or #BANK_BITS - out (c), a - - ; This includes the stacks, so be careful on restore - ld hl, #U_DATA - ld de, #U_DATA_STASH - ld bc, #U_DATA__TOTALSIZE - ldir - ld a, (current_map) - or #BANK_BITS - ld bc, #0x7ffd - out (c), a - - ; find another process to run (may select this one again) - push af - call _getproc - pop af ; we can't optimise this as the linker - ; is entitled to patch the 5 bytes here into a - ; banked call - push hl - push af - call _switchin - - ; we should never get here - call _platform_monitor - -badswitchmsg: .ascii "_switchin: FAIL" - .db 13, 10, 0 - -_switchin: - di - pop hl ; far padding - 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 - push hl ; far padding - - push de - ld hl, #P_TAB__P_PAGE_OFFSET - add hl, de ; process ptr - pop de - ; - ; Get ourselves a valid private stack ASAP. We are going to - ; copy udata around and our main stacks are in udata - ; - ld sp, #_swapstack - - ld a, (hl) ; 0 swapped, not zero is the bank for C000 - or a - jr nz, not_swapped - - ; Swap the process in (this may swap something else out first) - ; The second pushes are C function arguments. SDCC can trample - ; these - - ; Turn this one once we have it all sorted and debugged - ; ei - ; xor a - ; ld (_int_disabled),a - push hl ; Save - push de - push hl ; Arguments - push de - push af - call _swapper - pop af - pop af - pop af - pop de ; Restore - pop hl - ld a,#1 - ld (_int_disabled),a - di - ld a, (hl) ; We should now have a page assigned -not_swapped: - ld hl,(U_DATA__U_PTAB) - or a - sbc hl,de -; Turn this on once debugged -; jr z, skip_copyback - - ; We are in DI so we can poke these directly but must not invoke - ; any code outside of common - or #BANK_BITS ; ROM - ; Pages please ! - ld bc, #0x7ffd - out (c), a - - ; Copy the stash from the user page back down into common - ; The alternate registers are free - we use them for the - ; block copy and for the flipper - ; - ; FIXME: Add Tormod's optimisation from the 6809 tree - ; - exx - ld hl, #U_DATA_STASH - ld de, #U_DATA - ld bc, #U_DATA__TOTALSIZE - ldir - exx - ; - ; Remap the kernel proper - ; - - ld a, (current_map) - or #BANK_BITS - ld bc, #0x7ffd - out (c), a - - ; Is our low data in 0x8000 already or do we need to flip - ; it with bank 6. _low_bank holds the page pointer of the - ; task owning the space - - ld hl, (_low_bank) ; who owns low memory - or a - sbc hl, de ; preserve DE - jr z, nofliplow ; skip the flip if we own low bank -; -; Flip low banks over. Preserve DE -; -fliplow: - exx - ld hl, #0x8000 - ld de, #0xc000 - ld a, #6 + BANK_BITS - ld bc, #0x7ffd - out (c), a -flip2: - ld b, #0 ; 256 bytes per outer loop (16K total) -flip1: - ld c, (hl) - ld a, (de) - ex de, hl - ld (hl), c - ld (de), a - inc hl - inc de - djnz flip1 - xor a - cp d ; Wrapped to 0x0000 ? - jr nz, flip1 - - ld a, (current_map) - or #BANK_BITS - ld bc, #0x7ffd - out (c), a - exx - ld (_low_bank), de ; we own it now - -nofliplow: - - ; 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 == HL - jr nz, switchinfail - - ; wants optimising up a bit - ld ix, (U_DATA__U_PTAB) - ; next_process->p_status = P_RUNNING - ld P_TAB__P_STATUS_OFFSET(ix), #P_RUNNING - - ; Fix any moved page pointers - ; Just do one byte as that is all we use on this platform - ld a, P_TAB__P_PAGE_OFFSET(ix) - ld (U_DATA__U_PAGE), a - ; 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) - - ; - ; We can now use the stack again - ; - - pop af - pop iy - pop ix - pop hl ; return code - - ; Make sure we have the right kernel bank to return to - call switch_bank - - ; 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 - -; Interrupts should be off when this is called -_dup_low_page: - di ; FIXME: check callers properly - ld a, #0x06 + BANK_BITS ; low page alternate - ld bc, #0x7ffd - out (c), a - - ld hl, #0x8000 ; fixed - ld de, #0xC000 ; page we just mapped in - ld bc, #16384 - ldir - - ld a, (current_map) ; restore mapping - or #BANK_BITS ; ROM bits - ld bc, #0x7ffd - out (c), a - ret - - -; -; 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 bc - pop de ; return address - pop hl ; new process p_tab* - push hl - push de - push bc - - 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 - - ld a,(current_map) - push af - - ; 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. - - ; Need to write a new 16K bank copy here, then copy the live uarea - ; into the stash of the new process - - ; --------- copy process --------- - - ld hl, (fork_proc_ptr) - ld (_low_bank), hl ; low bank will become the child - ld de, #P_TAB__P_PAGE_OFFSET ; bank number - add hl, de - ; load p_page - ld c, (hl) - ld hl, (U_DATA__U_PAGE) - ld a, l - - ; - ; Copy the high page via the bounce buffer - ; - - call bankfork ; do the bank to bank copy - - ; FIXME: if we support small apps at C000-FBFF we need to tweak this - ; Now copy the 0x8000-0xBFFF area directly - - ld a, #0x06 + BANK_BITS ; low page alternate - ld bc, #0x7ffd - out (c), a - - ld hl, #0x8000 ; Fixed - ld de, #0xC000 ; Page we just mapped in - ld bc, #16384 - ldir - - ; Copy done - - ld a, (U_DATA__U_PAGE) ; parent memory - or #BANK_BITS ; get the right ROMs - ld bc, #0x7ffd - out (c), a ; Switch context to parent in 0xC000+ - - ; We are going to copy the uarea into the parents uarea stash - ; we must not touch the parent uarea after this point, any - ; changes only affect the child - ld hl, #U_DATA ; copy the udata from common into the - ld de, #U_DATA_STASH ; target process - ld bc, #U_DATA__TOTALSIZE - ldir - - ; - ; And back into the kernel - ; - ld bc, #0x7ffd - ld a, (current_map) - or #BANK_BITS - out (c), a - ; 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 iy - pop ix - pop bc - - ; Make a new process table entry, etc. - ld hl, (fork_proc_ptr) - push hl - push af - call _newproc - pop af - pop bc - - ; 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 - -; -; This is related so we will keep it here. Copy the process memory -; for a fork. a is the page base of the parent, c of the child -; (this API will be insufficient once we have chmem and proper use of -; banks - as well as needing to support fork to disk) -; -; Assumption - fits into a fixed number of whole 256 byte blocks -; -; -; Note: this needs reviewing. We now have a lot more program memory -; we can use with a lazy copying model -; -bankfork: - or #BANK_BITS ; ROM bits for the bank - ld b, #0x3E ; 64 x 256 minus 2 sets for the uarea stash/irqs - ld hl, #0xC000 ; base of memory to fork (vectors included) -bankfork_1: - push bc ; Save our counter and also child offset - push hl - ld bc, #0x7ffd - out (c), a ; switch to parent bank - ld de, #bouncebuffer - ld bc, #256 - ldir ; copy into the bounce buffer - pop de ; recover source of copy to bounce - ; as destination in new bank - pop bc ; recover child port number - push bc - ld b, a ; save the parent bank id - ld a, c ; switch to the child - push bc ; save the bank pointers - ld bc, #0x7ffd - or #BANK_BITS ; ROM bits - out (c), a - ld hl, #bouncebuffer - ld bc, #256 - ldir ; copy into the child - pop bc ; recover the bank pointers - ex de, hl ; destination is now source for next bank - ld a, b ; parent back is wanted in a - pop bc - djnz bankfork_1 ; rinse, repeat - ret -; -; For the moment -; - .area _COMMONDATA -bouncebuffer: - .ds 256 -; We can keep a stack in common because we will complete our -; use of it before we switch common block. In this case we have -; a true common so it's even easier. We never use both at once -; so share with bouncebuffer -_swapstack: -_low_bank: - .dw _ptab ; Init starts owning this - -fork_proc_ptr: - .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry + .include "../dev/zx/tricks.s" diff --git a/Kernel/platform-zxdiv/zxvideo.s b/Kernel/platform-zxdiv/zxvideo.s index 509b0b8d..78b40519 100644 --- a/Kernel/platform-zxdiv/zxvideo.s +++ b/Kernel/platform-zxdiv/zxvideo.s @@ -18,336 +18,11 @@ .globl _curattr .globl _vtattr - .area _VIDEO - - ; colors are ignored everywhere for now - -videopos: - ld a,e - and #7 - rrca - rrca - rrca - add a,d - ld d,e - ld e,a - ld a,d - and #0x18 - or #0x40 ; Standard screen - ld d,a - ret - -videoattr: - ; 32 x E + D into HL - ld a,e - rrca - rrca - rrca ; A is now 32xE with the top bits overflowed - ; into the low 2 bits - ld l,a - and #3 ; Extract the low 2 bits for the high - add #0x58 ; Attributes start 0x5800 - ld h,a - ld a,l - and #0xE0 ; mask the bits that are valid - add d ; add the low 5 bits from D - ld l,a ; and done (the add can't overflow) - ret - -_plot_char: - pop iy - pop hl - pop de ; D = x E = y - pop bc - push bc - push de - push hl - push iy - - push de - 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 - - ; We do underline for now - not clear italic or bold are useful - ; with the font we have. - ld bc,(_vtattr) ; c is vt attributes - - ; printing -plot_char_loop: - ld a, (hl) - ld (de), a - inc l ; next byte of char data - inc d ; next screen line - - ld a, (hl) - ld (de), a - inc l ; next byte of char data - inc d ; next screen line - - ld a, (hl) - ld (de), a - inc l ; next byte of char data - inc d ; next screen line - - ld a, (hl) - ld (de), a - inc l ; next byte of char data - inc d ; next screen line - - ld a, (hl) - ld (de), a - inc l ; next byte of char data - inc d ; next screen line - - ld a, (hl) - ld (de), a - inc l ; next byte of char data - inc d ; next screen line - - ld a, (hl) - ld (de), a - inc l ; 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 - - pop de - call videoattr - ld a,(_curattr) - ld (hl),a - ret - -last_ul: - ld a,#0xff - jr plot_attr - -_clear_lines: - pop bc - pop hl - pop de ; E = line, D = count - push de - push hl - push bc - ; 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, #32 ; clear 32 cols - push bc - push de - push af - call _clear_across - pop af - pop hl ; clear stack - pop hl - - pop de - inc e -nextline: - dec d - jr nz, clear_next_line - - ret - - -_clear_across: - pop iy - pop hl - pop de ; DE = coords - pop bc ; C = count - push bc - push de - push hl - push iy - ld a,c - or a - ret z ; No work to do - bail out - push de - push bc - call videopos ; first pixel line of first character in DE - push de - pop hl ; copy to hl - xor a - - ; no boundary checks. Assuming that D + C < SCREEN_WIDTH - -clear_line: - ld b, #8 ; 8 pixel lines to clear for this char -clear_char: - ld (de), a - inc d - djnz clear_char + ; Build the video library as the only driver - ex de, hl - inc de - push de - pop hl +ZXVID_ONLY .equ 1 - dec c - jr nz, clear_line - pop bc - pop de - call videoattr - ld a,(_curattr) - ld b,c -setattr: - ld (hl),a - inc hl - djnz setattr - ret - -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 - inc d - inc h - dec c - jr nz, copy_line_nextchar - ret - - ; TODO: the LDIR way should be much faster - -_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 - -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 - - ; Attributes - ld hl,#0x5ADF - ld de,#0x5AFF - ld bc,#0x02E0 - lddr - - ret - - -_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 - -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 - - ld hl,#0x5820 - ld de,#0x5800 - ld bc,#0x02E0 - ldir - ret - -_cursor_on: - pop bc - pop hl - pop de - push de - push hl - push bc - ld (cursorpos), de - - call videopos - ld a, #7 - add a, d - ld d, a - ld a, #0xFF - ld (de), a - ret -_cursor_disable: -_cursor_off: - ld de, (cursorpos) - call videopos - ld a, #7 - add a, d - ld d, a - xor a - ld (de), a - -_do_beep: - ret + .area _VIDEO - .area _DATA + .include "../dev/zx/video.s" -cursorpos: - .dw 0