--- /dev/null
+!
+! For a purely bank based architecture this code is common and can be
+! used by most platforms
+!
+! The caller needs to provide the standard map routines along with
+! map_kernel_a which maps in the kernel bank in a. This code assumes
+! that the bank can be encoded in 8bits.
+!
+
+.sect .common
+
+.define _platform_switchout
+
+!
+! Verify ABI exact rules but I think we don't need to stack any
+! register state.
+!
+
+!
+! Switch a process out and run the next one
+!
+_platform_switchout:
+ lxi h,0
+ push h ! Save a 0 argment
+ dad sp
+ shld U_DATA__U_SP ! Save the sp for a switch in
+ call map_process_always_di
+ !
+ ! Save the udata into process state
+ !
+ lxi h,U_DATA
+ lxi d,U_DATA_STASH
+ call copy512 ! No ldir 8(
+ ! Back to kernel
+ call map_kernel_di
+ call _getproc ! Who goes next
+ push h
+ call _switchin ! Run it
+ ! Should never hit this
+ call _platform_monitor
+
+!
+! Switch a process back in
+!
+.define _switchin
+
+!
+! Switch to a given process
+!
+_switchin:
+ di
+ pop b
+ pop d ! DE is now our process to run
+ push d
+ push b
+
+ call map_kernel_di
+
+ !
+ ! Is it swapped (page 0)
+ !
+ lxi h,P_TAB__P_PAGE_OFFSET
+ dad d
+
+ lxi sp,_swapstack
+ mov a,m
+ ora a
+ jnz not_swapped
+ !
+ ! Swapping time. Interrupts back on
+ !
+ ei
+ xra a
+ sta _int_disabled
+ !
+ ! Can we rely on the compiler not mashing the stacked var ?
+ !
+ push h
+ push d
+ call _swapper
+ pop d
+ pop h
+ !
+ ! It should now be back in memory
+ !
+ mvi a,1
+ sta _int_disabled
+ di
+ mov a,m
+ !
+ ! Check if we need to recover the udata (we were last to run)
+ !
+not_swapped:
+ mov c,a
+ lhld U_DATA__U_PTAB
+ mov a,h
+ cmp d
+ jnz copyback
+ mov a,l
+ cmp e
+ jz skip_copyback
+ !
+ ! Recover the udata
+ !
+copyback:
+ mov a,c
+ call map_process_a
+
+ lxi h,U_DATA_STASH
+ lxi d,U_DATA
+ call copy512
+
+ lhld U_DATA__U_SP ! A valid stack to map on
+ sphl
+
+ call map_kernel
+ !
+ ! Did we find the right process ?
+ !
+ lhld U_DATA__U_PTAB
+ mov a,h
+ cmp d
+ jnz switchinfail
+ mov a,l
+ cmp e
+ jnz switchinfail
+
+skip_copyback:
+ !
+ ! Mark us as running, clear our preemption counter
+ ! and set the interrupt flags
+ !
+ lhld U_DATA__U_PTAB
+ mvi a,P_RUNNING
+ mov m,a
+ lxi d,P_TAB__P_PAGE_OFFSET
+ dad d
+ mov a,m
+ sta U_DATA__U_PTAB
+ lxi h,0
+ shld _runticks
+ lhld U_DATA__U_SP
+ sphl
+ !
+ ! Recover our return code
+ !
+ pop h
+ lda U_DATA__U_ININTERRUPT
+ sta _int_disabled
+ ora a
+ rnz
+ ei
+ ret
+
+switchinfail:
+ call outhl
+ lxi h,badswitchmsg
+ call outstring
+ call _platform_monitor
+
+badswitchmsg:
+ .asciz 'badsw'
+
+
+fork_proc_ptr:
+ .data2 0
+
+.define _dofork
+!
+! The heart of fork
+!
+_dofork:
+ pop d
+ pop h ! new process
+ push h
+ push d
+
+ shld fork_proc_ptr
+
+ lxi d,P_TAB__P_PID_OFFSET
+ dad d
+ mov a,m
+ inx h
+ mov h,m
+ mov l,a
+ !
+ ! We don't have any state to save but the pid
+ !
+ push h
+ lxi h,0
+ dad sp
+ shld U_DATA__U_SP
+ !
+ ! We are now in a safe state to work
+ !
+ lhld fork_proc_ptr
+ lxi d,P_TAB__P_PAGE_OFFSET
+ dad d
+ mov c,m
+ lda U_DATA__U_PAGE
+
+ call bankfork
+
+ call map_process_always
+ !
+ ! Clone the parent udata and stack into the child stash
+ !
+ lxi h,U_DATA
+ lxi d,U_DATA_STASH
+ call copy512
+
+ call map_kernel
+
+ pop h ! Get rid of saved pid
+
+ !
+ ! Manufacture the child udata state
+ !
+ lxi h,_udata
+ push h
+ lhld fork_proc_ptr
+ push h
+ call _makeproc
+ pop b
+ pop b
+ !
+ ! Timer ticks
+ !
+ lxi h,0
+ shld _runticks
+ ret
+
+.define bouncebuffer
+.define _swapstack
+
+bouncebuffer:
+ .space 256 ! Do we really need 256 ?
+_swapstack:
+
+.define _need_resched
+
+_need_resched:
+ .data1 0
--- /dev/null
+#
+!
+! 8080 low level code
+!
+! Much the same as the Z80 code except we don't provide in and out
+! helpers because it's impossible to make them re-entrant for any port
+!
+
+#include "kernel-8080.def"
+
+.sect .common
+
+deliver_signals:
+ lda U_DATA__U_CURSIG
+ ora a
+ rz
+deliver_signals_2:
+ mov l,a
+ mvi h,0
+ push h
+ dad h
+ lxi d,U_DATA__U_SIGVEC
+ dad d
+ mov e,m
+ inx h
+ mov d,m
+ xra a
+ sta U_DATA__U_CURSIG
+ !
+ ! Do we need to zero check de here ?
+ !
+ lxi b,signal_return
+ push b
+ xchg
+ ei
+ pchl
+
+signal_return:
+ pop h
+ di
+ lxi h,0
+ dad sp
+ shld U_DATA__U_SYSCALL_SP
+ lxi sp,kstack_top
+ mvi a,1
+ sta _int_disabled
+ call map_kernel_di
+ call _chksigs
+ call map_process_always_di
+ lhld U_DATA__U_SYSCALL_SP
+ sphl
+ jmp deliver_signals
+
+.define unix_syscall_entry
+
+unix_syscall_entry:
+ di
+ push b ! for now
+ push d ! will go away when we fix the ABI
+ lxi h,8 ! Find arguments on stack frame FIXME: work out
+ ! right offset
+ dad sp
+ mov a,m
+ sta U_DATA__U_CALLNO
+ inx h
+ inx h
+ ! Oh for LDIR
+ ! Unroll this for speed. Syscall arguments into constant locations
+ mov a,m
+ sta U_DATA__U_ARGN
+ inx h
+ mov a,m
+ sta U_DATA__U_ARGN+1
+ inx h
+ mov a,m
+ sta U_DATA__U_ARGN+2
+ inx h
+ mov a,m
+ sta U_DATA__U_ARGN+3
+ inx h
+ mov a,m
+ sta U_DATA__U_ARGN+4
+ inx h
+ mov a,m
+ sta U_DATA__U_ARGN+5
+ inx h
+ mov a,m
+ sta U_DATA__U_ARGN+6
+ inx h
+ mov a,m
+ sta U_DATA__U_ARGN+7
+ ! We are now in kernel space
+ mvi a,1
+ sta U_DATA__U_INSYS
+ ! Switch stacks
+ ! On 8080 this is a bit more long winded as we have to go via HL
+ lxi h,0
+ dad sp
+ shld U_DATA__U_SYSCALL_SP
+ lxi sp, kstack_top
+ !
+ ! Now map the kernel and call it
+ !
+ call map_kernel_di
+ ei
+ call _unix_syscall
+ !
+ ! Remember fork and execve don't necessarily return this wand fork
+ ! can do it twice
+ !
+ di
+ call map_process_always
+ xra a
+ sta U_DATA__U_INSYS
+ ! Switch stack back
+ lhld U_DATA__U_SYSCALL_SP
+ sphl
+ lhld U_DATA__U_RETVAL
+ xchg
+ lhld U_DATA__U_ERROR
+ !
+ ! Signal check
+ !
+ lda U_DATA__U_CURSIG
+ ora a
+ jnz via_signal
+unix_return:
+ mov a,h
+ ora l
+ jnz not_error
+ stc
+ jmp unix_pop
+not_error:
+ xchg
+unix_pop:
+ pop d
+ pop b
+ ! ret must directly follow the ei
+ ei
+ ret
+via_signal:
+ !
+ ! Stack the state (a signal doing a syscall will change the
+ ! U_DATA fields but we must return the old error/status)
+ !
+ lhld U_DATA__U_ERROR
+ push h
+ lhld U_DATA__U_RETVAL
+ push h
+ !
+ ! And into the signal delivery path
+ !
+ call deliver_signals_2
+ pop d
+ pop h
+ jmp unix_return
+
+!
+! Called when execve() completes to transition to the user, as we
+! don't return from execve() via the syscall path
+!
+!
+.define _doexec
+
+_doexec:
+ di
+ call map_process_always
+ pop b
+ pop d
+ lhld U_DATA__U_ISP
+ sphl
+ xra a
+ sta U_DATA__U_INSYS
+ xchg
+ lxi d,PROGLOAD
+ ei
+ pchl
+!
+! NULL trap. Must live in common space
+!
+! FIXME: Rewrite 68000 style as a synchronous trap
+!
+.define null_handler
+
+null_handler:
+ lda U_DATA__U_INSYS
+ ora a
+ jnz trap_illegal
+ lda _inint
+ ora a
+ jnz trap_illegal
+ lxi h,7
+ push h
+ lhld U_DATA__U_PTAB
+ lxi d,P_TAB__P_PID_OFFSET
+ dad d
+ mov e,m
+ inx h
+ mov d,m
+ push d
+ lxi h,39
+ push h
+ call unix_syscall_entry
+ lxi h,0xffff ! exit -1
+ push h
+ dcx h
+ push h
+ call unix_syscall_entry
+ ! Never returns
+
+trap_illegal:
+ lxi h,illegalmsg
+traphl:
+ call outstring
+ call _platform_monitor
+
+.define nmi_handler
+
+nmi_handler:
+ call map_kernel_di
+ lxi h,nmimsg
+ jmp traphl
+
+illegalmsg:
+ .asciz '[illegal]'
+nmimsg:
+ .asciz '[NMI]'
+
+!
+! Interrupts are similar to Z80 but we have a lot less state
+! to store, and rather trickier juggling to get signals nice
+!
+.define interrupt_handler
+
+interrupt_handler:
+ push psw
+ push b
+ push d
+ push h
+ call platform_interrupt_all
+ ! Switch stacks
+ lxi h,0
+ dad sp
+ shld istack_switched_sp
+ lxi sp,istack_top
+ !
+ ! Map the kernel
+ !
+ lda 0
+ call map_save_kernel
+ cpi 0xC3
+ cnz null_pointer_trap
+ !
+ ! Set up state and enter kernel
+ !
+ mvi a,1
+ sta _inint
+ sta U_DATA__U_ININTERRUPT
+ sta _int_disabled
+ call _platform_interrupt
+ !
+ ! Undo state
+ !
+ xra a
+ sta _inint
+ !
+ ! Do we need to task switch ?
+ !
+ lda _need_resched
+ ora a
+ jnz preemption
+ !
+ ! Switch stacks back
+ !
+ call map_restore
+ lhld istack_switched_sp
+ sphl
+intout:
+ xra a
+ sta U_DATA__U_ININTERRUPT
+ lda U_DATA__U_INSYS
+ ora a
+ jnz interrupt_pop
+ call deliver_signals
+ !
+ ! Restore registers and done
+ !
+interrupt_pop:
+ xra a
+ sta _int_disabled
+ pop h
+ pop d
+ pop b
+ pop psw
+ ei
+ ret
+
+null_pointer_trap:
+ mvi a,0xc3
+ sta 0
+ lxi h,11
+trap_signal:
+ push h
+ lhld U_DATA__U_PTAB
+ push h
+ call _ssig
+ pop h
+ pop h
+ ret
+
+!
+! Now the scary stuff - preempting
+!
+preemption:
+ xra a
+ sta _need_resched
+ call map_restore
+ !
+ ! Save our original stack in syscall_s
+ ! Move to our kernel stack (free because we don't preempt
+ ! in kernel
+ !
+ lhld istack_switched_sp
+ shld U_DATA__U_SYSCALL_SP
+ lxi sp,kstack_top
+ !
+ ! Fix up the mappings
+ !
+ call map_kernel_di
+ !
+ ! Mark ourselves as in a system call
+ !
+ mvi a,1
+ sta U_DATA__U_INSYS
+ call _chksigs
+ lhld U_DATA__U_PTAB
+ mvi a,P_RUNNING
+ cmp m
+ jnz not_running
+ mvi m,P_READY
+not_running:
+ !
+ ! We will disappear into this and reappear somewhere else. In
+ ! time we will reappear here
+ !
+ call _platform_switchout
+ !
+ ! We are back in the land of the living so no longer in
+ ! syscall or interrupt state
+ !
+ xra a
+ sta U_DATA__U_ININTERRUPT
+ sta U_DATA__U_INSYS
+ !
+ ! Get our mapping back
+ !
+ call map_process_always_di
+ !
+ ! And our stack
+ !
+ lhld U_DATA__U_SYSCALL_SP
+ sphl
+ lda U_DATA__U_CURSIG
+ ora a
+ cnz deliver_signals_2
+ jmp interrupt_pop
+
+!
+! Debug code
+!
+.define outstring
+
+outstring:
+ mov a,m
+ ora a
+ rz
+ call outchar
+ inx h
+ jmp outstring
+
+.define outstringhex
+
+outstringhex:
+ mov a,m
+ ora a
+ rz
+ call outcharhex
+ mvi a,0x20
+ call outchar
+ inx h
+ jmp outstringhex
+
+.define outnewline
+
+outnewline:
+ mvi a,0x0d
+ call outchar
+ mvi a,0x0a
+ jmp outchar
+
+.define outhl
+
+outhl:
+ push psw
+ mov a,h
+ call outcharhex
+ mov a,l
+ call outcharhex
+ pop psw
+ ret
+
+.define outde
+
+outde:
+ push psw
+ mov a,d
+ call outcharhex
+ mov a,e
+ call outcharhex
+ pop psw
+ ret
+
+.define outbc
+
+outbc:
+ push psw
+ mov a,b
+ call outcharhex
+ mov a,c
+ call outcharhex
+ pop psw
+ ret
+
+.define outcharhex
+
+outcharhex:
+ push b
+ push psw
+ mov c,a
+ rar
+ rar
+ rar
+ rar
+ call outnibble
+ mov a,c
+ call outnibble
+ pop psw
+ pop b
+ ret
+
+outnibble:
+ ani 0x0f
+ cpi 10
+ jc numeral
+ adi 7
+numeral:
+ adi 0x30 ! '0'
+ jmp outchar
+
+
+.define ___hard_ei
+
+___hard_ei:
+ xra a
+ sta _int_disabled
+ ei
+ ret
+
+.define ___hard_di
+
+___hard_di:
+ lxi h, _int_disabled
+ di
+ mov a,m
+ mvi m,1
+ mov l,a ! Check ABI
+ ret
+
+.define ___hard_irqrestore
+
+___hard_irqrestore:
+ pop d
+ pop h
+ push h
+ push d
+ di
+ mov a,l
+ sta _int_disabled
+ ora a
+ rnz
+ ei
+ ret
+
+!
+! We need to worry about bits of this in interrupt save and restore
+!
+
+.define .trapproc, .retadr,.bcreg,.areg,.tmp1
+
+.trapproc: .data2 0
+.retadr: .data2 0
+.bcreg: .data2 0
+.areg: .data1 0
+.tmp1: .data2 0
+
+!
+! Errors from the runtime
+!
+.define eunimpl,eoddz,ecase,eidivz
+
+eunimpl:
+ lxi h,unimp
+ jmp kerboom
+eoddz:
+ lxi h,ddz
+ jmp kerboom
+ecase:
+ lxi h,case
+ jmp kerboom
+eidivz:
+ lxi h,divz
+kerboom:
+ call outstring
+ call _platform_monitor
+
+unimp: .asciz 'rt:unimp'
+ddz: .asciz 'rt:ddz'
+case: .asciz 'rt:case'
+divz: .asciz 'rt:div0'