8080: core enabling
authorAlan Cox <alan@linux.intel.com>
Wed, 6 Feb 2019 14:02:02 +0000 (14:02 +0000)
committerAlan Cox <alan@linux.intel.com>
Wed, 6 Feb 2019 14:02:02 +0000 (14:02 +0000)
(Incomplete)

Kernel/lib/8080fixedbank-core.s [new file with mode: 0644]
Kernel/lib/8080fixedbank.s [new file with mode: 0644]
Kernel/lowlevel-8080.s [new file with mode: 0644]
Kernel/usermem_std-8080.s [new file with mode: 0644]

diff --git a/Kernel/lib/8080fixedbank-core.s b/Kernel/lib/8080fixedbank-core.s
new file mode 100644 (file)
index 0000000..0c7cb83
--- /dev/null
@@ -0,0 +1,243 @@
+!
+!      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
diff --git a/Kernel/lib/8080fixedbank.s b/Kernel/lib/8080fixedbank.s
new file mode 100644 (file)
index 0000000..191327d
--- /dev/null
@@ -0,0 +1,15 @@
+#
+
+#include "../lib/8080fixedbank-core.s"
+
+bankfork:
+!
+!      FIXME: copy the user memory between bank a and c
+!
+       ret
+!
+!      Fast copy 512 bytes from H to D
+!
+copy512:
+! FIXME: TODO
+       ret
diff --git a/Kernel/lowlevel-8080.s b/Kernel/lowlevel-8080.s
new file mode 100644 (file)
index 0000000..d8d345d
--- /dev/null
@@ -0,0 +1,529 @@
+#
+!
+!      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'
diff --git a/Kernel/usermem_std-8080.s b/Kernel/usermem_std-8080.s
new file mode 100644 (file)
index 0000000..2094fad
--- /dev/null
@@ -0,0 +1,100 @@
+!
+!      Simple implementation for now. Should be optimized
+!
+
+.sect .commonmem
+
+.define __uputc
+
+__uputc:
+       pop b
+       pop d
+       pop h
+       push h
+       push d
+       push b
+       call map_process_always
+       mov m,e
+       jp map_kernel
+
+.define __uputw
+
+__uputw:
+       pop b
+       pop d
+       pop h
+       push h
+       push d
+       push b
+       call map_process_always
+       mov m,e
+       inx h
+       mov m,d
+       jp map_kernel
+
+.define __ugetc
+
+__ugetc:
+       pop b
+       pop d
+       pop h
+       push h
+       push d
+       push b
+       call map_process_always
+       mov l,m
+       jp map_kernel
+
+.define __ugetw
+
+__ugetw:
+       pop b
+       pop d
+       pop h
+       push h
+       push d
+       push b
+       call map_process_always
+       mov a,m
+       inx h
+       mov h,m
+       mov l,a
+       jmp map_kernel
+
+.define __uget
+
+__uget:
+       ! TODO
+       ret
+
+.define __uput
+
+__uput:
+       ! TODO
+       ret
+
+.define __uzero
+
+__uzero:
+       pop d
+       pop h
+       pop b
+       push b
+       push h
+       push d
+       mov a,b
+       ora c
+       rz
+!
+!      Simple loop. Wants unrolling a bit
+!
+       call map_process_always
+       xra a
+zeroloop:
+       mov m,a
+       inx h
+       dcx b
+       mov a,b
+       ora c
+       jnz zeroloop
+       jmp map_kernel