;************ biostrap.z8k ************************** ;* ;* Trap handlers for P-CP/M (tm) BIOS ;* ;* 821013 S. Savitzky (Zilog) -- created ;* 821123 D. Dunlop (Zilog) -- added Olivetti M20- ;* specific code to invalidate track buffer ;* contents when disk drive motor stops ;* (fixes directory-overwrite on disk change) ;* 830305 D. Sallume (Zilog) -- added FPE trap ;* code. ;* __text: .sect ;**************************************************** ;* ;* NOTE ;* Trap and interrupt handlers are started up ;* in segmented mode. ;* ;**************************************************** .input "biosdefs.z8k" ;**************************************************** ;* ;* Externals ;* ;**************************************************** .global _bios ;C portion of BIOS .global memsc ;memory-management SC .global _tbvalid ;disk track buff valid .global _tbdirty ;disk track buff is dirty .global _sysseg, _usrseg, _sysstk, _psap ;**************************************************** ;* ;* M-20 ROM scratchpad RAM addresses ;* ;**************************************************** rtc_ext: .equ 82000022h ;Place to put address ; of list of functions ; for each clock tick motor_on: .equ 82000020h ;Disk motor timeout ;**************************************************** ;* ;* Global declarations ;* ;**************************************************** .global _trapinit .global _trapvec .global _trap .global xfersc ;**************************************************** ;* ;* Trap vector table ;* ;* entries 0..31 are misc. system traps ;* entries 32..47 are system calls 0..15 ;* ;**************************************************** __bss: .sect _trapvec: .block NTRAPS*4 ;**************************************************** ;* ;* System Call and General Trap Handler And Dispatch ;* ;* It is assumed that the system runs ;* non-segmented on a segmented CPU. ;* ;* _trap is jumped to segmented, with the ;* following information on the stack: ;* ;* trap type: WORD ;* reason: WORD ;* fcw: WORD ;* pc: LONG ;* ;* The trap handler is called as a subroutine, ;* with all registers saved on the stack, ;* IN SEGMENTED MODE. This allows the trap ;* handler to be in another segment (with some ;* care). This is useful mainly to the debugger. ;* ;* All registers except rr0 are also passed ;* intact to the handler. ;* ;**************************************************** __text: .sect sc_trap: ;system call trap server push @r14,@r14 _trap: sub r15,#30 ; push caller state ldm @r14,r0,#14 NONSEG ; go nonsegmented ldctl r1,NSP ld nr14(r15),r14 ex r1,nr15(r15) ; trap# now in r1 cpb rh1,#7Fh ; system call? jr ne trap_disp ; no ; yes: map it clrb rh1 add r1,#SC0TRAP ;=== need range check === trap_disp: ; dispatch sll r1,#2 ldl rr0,_trapvec(r1) testl rr0 jr z _trap_ret ; zero -- no action ; else call seg @rr0 pushl @r15,rr0 ; (done via kludge) SEG popl rr0,@r14 calr trap_1 jr _trap_ret trap_1: ; jp @rr0 pushl @r14,rr0 ret _trap_ret: ;return from trap or interrupt NONSEG ld r1,nr15(r15) ; pop state ld r14,nr14(r15) ldctl NSP,r1 SEG ; go segmented for the iret. ldm r0,@r14,#14 add r15,#32 iret ; return from interrupt ;**************************************************** ;* ;* Assorted Trap Handlers ;* ;**************************************************** epu_trap: push @r14,#EPUTRAP jr _trap pi_trap: push @r14,#PITRAP jr _trap seg_trap: push @r14,#SEGTRAP jr _trap nmi_trap: push @r14,#NMITRAP jr _trap ;**************************************************** ;* ;* Bios system call handler ;* ;**************************************************** ;biossc: ;call bios ; NONSEG ; ; r3 = operation code ; ; rr4= P1 ; ; rr6= P2 ; ; ld r0,scfcw+4(r15) ; if caller nonseg, normal ; and r0,#0C000h ; jr nz seg_ok ; ; ld r4,scseg+4(r15) ; then add seg to P1, P2 ; ld r6,r4 ;seg_ok: ; ; set up C stack frame ;;=== ; pushl @r15,rr6 ; pushl @r15,rr4 ; push @r15,r3 ; ; ; call C program ; call _bios ; ; ; clean stack & return ; add r15,#10 ; ldl cr6+4(r15),rr6 ; with long in rr6 ; ; SEG ; ret ; ;**************************************************** ;* ;* Context Switch System Call ;* ;* xfer(context) ;* long context; ;* ;* context is the physical (long) address of: ;* r0 ;* ... ;* r13 ;* r14 (normal r14) ;* r15 (normal r15) ;* ignored word ;* FCW (had better specify normal mode) ;* PC segment ;* PC offset ;* ;* The system stack pointer is not affected. ;* ;* Control never returns to the caller. ;* ;**************************************************** xfersc: ;enter here from system call SEG ; build frame on system stack ; when called from system call, the frame replaces ; the caller's context, which will never be resumed. inc r15,#4 ;discard return addr ldl rr4,rr14 ;move context ld r2,#FRAMESZ/2 ldir @r4,@r6,r2 jr _trap_ret ;restore context ;**************************************************** ;* ;* _motor_c -- check if disk motor still running. ;* Entered each clock tick. Invalidates ;* track buffer when motor stops ;* (Note: runs segmented) ;* ;**************************************************** _motor_c: ldl rr4,#motor_on ;Motor running? test @r4 ret nz ;Yes: do nothing ldar r4,$ ld r5,#_tbdirty ; Is track buff dirty? test @r4 ; Yes... ret nz ; ...return without invalidating ld r5,#_tbvalid clr @r4 ;No: mark track buffer ret ; invalid ; Table of functions run each real time clock tick _ticktab: .long -1 ;Will contain _motor_c .word 0ffffh ;Terminator ;**************************************************** ;* ;* _trapinit -- initialize trap system ;* ;**************************************************** ;* ;* PSA (Program Status Area) structure ;* ps .equ 8 ; size of a program status entry ; --- segmented --- psa_epu .equ 1*ps ; EPU trap offset psa_prv .equ 2*ps ; priviledged instruction trap psa_sc .equ 3*ps ; system call trap psa_seg .equ 4*ps ; segmentation trap psa_nmi .equ 5*ps ; non-maskable interrupt psa_nvi .equ 6*ps ; non-vectored interrupt psa_vi .equ 7*ps ; vectored interrupt psa_vec .equ psa_vi+(ps/2) ; vectors _trapinit: ; initialize trap table lda r2,_trapvec ld r0,#NTRAPS subl rr4,rr4 clrtraps: ldl @r2,rr4 inc r2,#4 djnz r0,clrtraps ld r2,_sysseg ; lda r3,biossc ; ldl _trapvec+(BIOS_SC+SC0TRAP)*4,rr2 lda r3,memsc ldl _trapvec+(MEM_SC+SC0TRAP)*4,rr2 ; lda r3,fp_epu ; ldl _trapvec+EPUTRAP*4,rr2 ; initialize some PSA entries. ; rr0 PSA entry: FCW (ints ENABLED) ; rr2 PSA entry: PC ; rr4 -> PSA slot ldl rr4,_psap SEG ldl rr0,#0000D800h add r5,#ps ; EPU trap ldar r2,epu_trap ldm @r4,r0,#4 add r5,#ps ; Priviledged Inst ldar r2,pi_trap ldm @r4,r0,#4 add r5,#ps ; System Call ldar r2,sc_trap ldm @r4,r0,#4 add r5,#ps ; segmentation ldar r2,seg_trap ldm @r4,r0,#4 add r5,#ps ; Non-Maskable Int. ldar r2,nmi_trap ldm @r4,r0,#4 ; Set up Real-Time Clock external call loc ldar r2,_motor_c ldar r4,_ticktab ldl @r4,rr2 ldl rr2,#rtc_ext ldl @r2,rr4 NONSEG ret ;**************************************************** ;****************************************************