| ;@(#)signal.s 2.15 90/10/14 21:57:55, AMD |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| ; Copyright 1990 Advanced Micro Devices, Inc. |
| ; |
| ; This software is the property of Advanced Micro Devices, Inc (AMD) which |
| ; specifically grants the user the right to modify, use and distribute this |
| ; software provided this notice is not removed or altered. All other rights |
| ; are reserved by AMD. |
| ; |
| ; AMD MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH REGARD TO THIS |
| ; SOFTWARE. IN NO EVENT SHALL AMD BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL |
| ; DAMAGES IN CONNECTION WITH OR ARISING FROM THE FURNISHING, PERFORMANCE, OR |
| ; USE OF THIS SOFTWARE. |
| ; |
| ; So that all may benefit from your experience, please report any problems |
| ; or suggestions about this software to the 29K Technical Support Center at |
| ; 800-29-29-AMD (800-292-9263) in the USA, or 0800-89-1131 in the UK, or |
| ; 0031-11-1129 in Japan, toll free. The direct dial number is 512-462-4118. |
| ; |
| ; Advanced Micro Devices, Inc. |
| ; 29K Support Products |
| ; Mail Stop 573 |
| ; 5900 E. Ben White Blvd. |
| ; Austin, TX 78741 |
| ; 800-292-9263 |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| .file "signal.s" |
| |
| ; SigEntry is the address of an array of C-level user code signal handlers. |
| ; They must return to the top-level before doing a sigret() return function. |
| ; Nested signals are supported. |
| |
| .extern V_SPILL, V_FILL |
| .extern fill ; In crt0.s |
| |
| .align 4 |
| .comm WindowSize, 4 |
| .data |
| SigEntry: |
| .word 0 ; reserved |
| .word 0 ; adds. of #2 SIGINT handler |
| .word 0 ; reserved |
| .word 0 ; reserved |
| .word 0 ; reserved |
| .word 0 ; reserved |
| .word 0 ; reserved |
| .word 0 ; adds. of #8 SIGFPE handler |
| |
| .text |
| |
| .reg v0, gr96 |
| .reg v1, gr97 |
| .reg v2, gr98 |
| .reg v3, gr99 |
| |
| .reg tav, gr121 |
| .reg tpc, gr122 |
| .reg lrp, gr123 |
| .reg slp, gr124 |
| .reg msp, gr125 |
| .reg rab, gr126 |
| .reg rfb, gr127 |
| |
| ;=================================================================== setjmp() |
| ; int |
| ; setjmp(label_t jmpbuf) |
| ; { |
| ; *jmpbuf = {gr1, msp, lr0, lr1}; |
| ; return 0; |
| ; } |
| ; |
| .global _setjmp |
| _setjmp: |
| store 0, 0, gr1, lr2 |
| add lr2, lr2, 4 |
| store 0, 0, msp, lr2 |
| add lr2, lr2, 4 |
| store 0, 0, lr0, lr2 |
| add lr2, lr2, 4 |
| store 0, 0, lr1, lr2 |
| jmpi lr0 |
| const v0, 0 |
| ; |
| ;==================================================================== longjmp() |
| ; int |
| ; longjmp(label_t jmpbuf, int value) |
| ; { |
| ; /* BUG: check for this |
| ; if (msp > jmpbuf->msp || gr1 > jmpbuf->gr1) |
| ; longjmperror(); |
| ; */ |
| ; |
| ; gr1 = jmpbuf->gr1; |
| ; lr2addr = jmpbuf->gr1 + 8; |
| ; msp = jmpbuf->msp; |
| ; |
| ; /* saved lr1 is invalid if saved lr2addr > rfb */ |
| ; if (lr2addr > rfb) { |
| ; /* |
| ; * None of the registers are useful. |
| ; * Set rfb to lr2addr - 512 & rab to rfb - 512. |
| ; * the FILL assert will take care of filling |
| ; */ |
| ; lr1 = jmpbuf->lr1; |
| ; rab = lr2addr - windowsize; |
| ; rfb = lr2addr; |
| ; } |
| ; |
| ; lr0 = jmpbuf->lr0; |
| ; if (rfb < lr1) |
| ; raise V_FILL; |
| ; return value; |
| ; } |
| ; |
| .global _longjmp |
| _longjmp: |
| load 0, 0, tav, lr2 ; copy in gr1 |
| add v1, lr2, 4 ; v1 points to msp |
| ; make sure we return a non-zero value |
| cpeq v0, lr3, 0 |
| srl v0, v0, 31 |
| or v0, lr3, v0 |
| |
| add gr1, tav, 0 ; now update gr1 |
| add tav, tav, 8 ; calculate lr2addr |
| load 0, 0, msp, v1 ; update msp from jmpbuf |
| cpleu v3, tav, rfb ; if (lr2addr > rfb) |
| jmpt v3, $1 ; { |
| add v1, v1, 4 ; v1 points to lr0 |
| add v2, v1, 4 ; v2 points to lr1 |
| load 0, 0, lr1, v2 ; lr1 = value from jmpbuf |
| sub v3, rfb, rab ; |
| sub rab, tav, v3 ; rab = lr2addr - windowsize |
| add rfb, tav, 0 ; rfb = lr2addr |
| $1: ; } |
| load 0, 0, lr0, v1 |
| jmpi lr0 |
| asgeu V_FILL, rfb, lr1 ; may fill from rfb to lr1 |
| ; |
| ;================================================================== sigcode |
| ; About to deliver a signal to a user mode signal handler. |
| ; msp+(15*4) = signal_number |
| ; msp+(14*4) = gr1 |
| ; msp+(13*4) = rab |
| ; msp+(12*4) = PC0 |
| ; msp+(11*4) = PC1 |
| ; msp+(10*4) = PC2 |
| ; msp+( 9*4) = CHA |
| ; msp+( 8*4) = CHD |
| ; msp+( 7*4) = CHC |
| ; msp+( 6*4) = ALU |
| ; msp+( 5*4) = OPS |
| ; msp+( 4*4) = gr121 |
| ; msp+( 3*4) = gr99 |
| ; msp+( 2*4) = gr98 |
| ; msp+( 1*4) = gr97 |
| ; msp = gr96 |
| ; The state of all the registers (except for msp, chc and rab) |
| ; is the same as when the process was interrupted. |
| ; |
| ; We must make the stack and window consistent before calling the handler |
| ; The orignal rab value is on the stack. The interrupt handler placed |
| ; rfb-Windowsize in rab. This is required to support nested interrupts. |
| ; |
| ; Note that the window becomes incosistent only during certain |
| ; critical sections in spill, fill, longjmp and sigcode. |
| ; rfb - rab > windowsize => we are in spill |
| ; rfb - rab < windowsize => we are in fill |
| ; gr1 + 8 > rfb => we are in long-longjmp case |
| ; In case of spill, fill and lonjmp; rab is modified first, |
| ; so if we are in one of these critical sections, |
| ; we set rab to rfb - WINDOWSIZE. |
| ; |
| .equ SIGCTX_SIZE, (16)*4 |
| .equ SIGCTX_SIGNUMB, (15)*4 |
| .equ SIGCTX_GR1_OFFSET, (14)*4 |
| .equ SIGCTX_RAB_OFFSET, (13)*4 |
| .equ SIGCTX_PC0_OFFSET, (12)*4 |
| .equ SIGCTX_PC1_OFFSET, (11)*4 |
| .equ SIGCTX_PC2_OFFSET, (10)*4 |
| .equ SIGCTX_CHC_OFFSET, (7)*4 |
| .equ SIGCTX_OPS_OFFSET, (5)*4 |
| .equ SIGCTX_TAV_OFFSET, (4)*4 |
| .global sigcode |
| sigcode: |
| ; -------------------------------------------------------- R-Stack fixup |
| const v0, WindowSize ; get register cache size |
| consth v0, WindowSize |
| load 0, 0, v0, v0 |
| add v2, msp, SIGCTX_RAB_OFFSET |
| load 0, 0, v2, v2 ; get interrupted rab value |
| sub v1, rfb, v2 ; determine if rfb-rab <= WINDOW_SIZE |
| cpgeu v1, v1, v0 ; |
| jmpt v1, nfill ; jmp if spill or 'normal' interrupt |
| add v1, gr1, 8 |
| cpgt v1, v1, rfb ; interrupted longjmp can look like fill |
| jmpf v1, nfill ; test for long-longjmp interruption |
| nop ; jmp if gr1+8 <= rfb |
| ; Fixup signal stack to re-start interrupted fill |
| ; backup pc1 -- this is needed for the partial fill case. |
| ; Clear chc so an interrupted load/store does not restart. |
| ; Reset rab to a window distance below rfb, rab shall be |
| ; decremented again on re-starting the interrupted fill. |
| ; The interrupt handler set rab=rfb-WindowSize. |
| ; |
| add v0, msp, SIGCTX_RAB_OFFSET |
| store 0, 0, rab, v0 ; re-store (rfb-WindowSize) for rab |
| const v2, fill |
| consth v2, fill |
| add v0, msp, SIGCTX_PC1_OFFSET |
| store 0, 0, v2, v0 |
| sub v2, v2, 4 ; determine pc0 |
| add v0, msp, SIGCTX_PC0_OFFSET |
| store 0, 0, v2, v0 |
| const v2, 0 ; clear chc |
| add v0, msp, SIGCTX_CHC_OFFSET |
| store 0, 0, v2, v0 |
| |
| nfill: |
| cpgt v0, gr1, rfb ; if gr1 > rfb then gr1 = rfb |
| jmpt v0, lower |
| cplt v0, gr1, rab ; if gr1 < rab then gr1 = rab |
| jmpt v0, raise |
| nop |
| ; -------------------------------------------------------- save_regs |
| sig1: sub msp, msp, (4+2+25)*4 ; reserve space for regs |
| mfsr gr96, ipc |
| mfsr gr97, ipa |
| mfsr gr98, ipb |
| mfsr gr99, q |
| mtsrim cr, 4-1 |
| storem 0, 0, gr96, msp |
| ; "push" registers stack support |
| add gr96, lr1, 0 |
| add gr97, rfb, 0 |
| mtsrim cr, 2-1 |
| add gr99, msp, 2*4 |
| storem 0, 0, gr96, gr99 |
| ; "push" remaining global registers |
| mtsrim cr, 25-1 ; gr100-gr124 |
| add gr96, msp, (4+2)*4 |
| storem 0, 0, gr100, gr96 |
| ; |
| ; -------------------------------------------------------- Dummy Call |
| .equ RALLOC, 4*4 ; make space for function calls |
| add v0, rfb, 0 ; store original rfb |
| sub gr1, gr1, RALLOC |
| asgeu V_SPILL, gr1, rab |
| add lr1, v0, 0 ; set lr1 = original rfb |
| add v1, msp, (4+2+25)*4 + SIGCTX_SIGNUMB |
| load 0, 0, lr2, v1 ; restore signal number |
| sub v1, lr2, 1 ; get handler index |
| sll v1, v1, 2 ; point to addresses |
| ; |
| ; -------------------------------------------------------- call C-level |
| ; Handler must not use HIF services other than the _sigret() type. |
| const v0, SigEntry |
| consth v0, SigEntry |
| add v0, v0, v1 |
| load 0, 0, v0, v0 ; determine if handler registered |
| cpeq v1, v0, 0 |
| jmpt v1, NoHandler |
| nop |
| calli lr0, v0 ; call C-level signal handler |
| nop |
| ; |
| ; -------------------------------------------------------- default return |
| NoHandler: |
| jmp __sigdfl |
| nop |
| |
| ; -------------------------------------------------------- support bits |
| lower: sll gr1, rfb, 0 |
| jmp sig1 |
| nop |
| raise: sll gr1, rab, 0 |
| jmp sig1 |
| nop |
| /* |
| ; -------------------------------------------------------- repair_regs |
| mtsrim cr, 4-1 |
| loadm 0, 0, gr96, msp |
| mtsr ipc, gr96 |
| mtsr ipa, gr97 |
| mtsr ipb, gr98 |
| mtsr Q, gr99 |
| ; "pop" registers stack support |
| mtsrim cr, 2-1 |
| add gr99, msp, 2*4 |
| loadm 0, 0, gr96, gr99 |
| add lr1, gr96, 0 |
| add rfb, gr97, 0 |
| ; "pop" remaining global registers |
| mtsrim cr, 25-1 ; gr100-gr124 |
| add gr96, msp, (4+2)*4 |
| loadm 0, 0, gr100, gr96 |
| add msp, msp, (4+2+25)*4 ; repair msp to save_regs entry value |
| ; -------------------------------------------------------- end repair |
| */ |
| |
| ; ======================================================== _sigret() |
| .global __sigret |
| __sigret: |
| ; repair_regs |
| ; -------------------------------------------------------- repair_regs |
| mtsrim cr, 4-1 |
| loadm 0, 0, gr96, msp |
| mtsr ipc, gr96 |
| mtsr ipa, gr97 |
| mtsr ipb, gr98 |
| mtsr q, gr99 |
| ; "pop" registers stack support |
| mtsrim cr, 2-1 |
| add gr99, msp, 2*4 |
| loadm 0, 0, gr96, gr99 |
| add lr1, gr96, 0 |
| add rfb, gr97, 0 |
| ; "pop" remaining global registers |
| mtsrim cr, 25-1 ; gr100-gr124 |
| add gr96, msp, (4+2)*4 |
| loadm 0, 0, gr100, gr96 |
| add msp, msp, (4+2+25)*4 ; repair msp to save_regs entry value |
| ; -------------------------------------------------------- end repair |
| const tav, 323 ; HIF _sigret |
| asneq 69, gr1,gr1 |
| halt ; commit suicide if returns |
| |
| ; ======================================================== _sigdfl() |
| .global __sigdfl |
| __sigdfl: |
| ; repair_regs |
| ; -------------------------------------------------------- repair_regs |
| mtsrim cr, 4-1 |
| loadm 0, 0, gr96, msp |
| mtsr ipc, gr96 |
| mtsr ipa, gr97 |
| mtsr ipb, gr98 |
| mtsr q, gr99 |
| ; "pop" registers stack support |
| mtsrim cr, 2-1 |
| add gr99, msp, 2*4 |
| loadm 0, 0, gr96, gr99 |
| add lr1, gr96, 0 |
| add rfb, gr97, 0 |
| ; "pop" remaining global registers |
| mtsrim cr, 25-1 ; gr100-gr124 |
| add gr96, msp, (4+2)*4 |
| loadm 0, 0, gr100, gr96 |
| add msp, msp, (4+2+25)*4 ; repair msp to save_regs entry value |
| ; -------------------------------------------------------- end repair |
| const tav, 322 ; HIF _sigdfl |
| asneq 69, gr1,gr1 |
| halt ; commit suicide if returns |
| |
| ; ======================================================== _sigrep() |
| __sigrep: |
| .global __sigrep |
| ; repair_regs |
| ; -------------------------------------------------------- repair_regs |
| mtsrim cr, 4-1 |
| loadm 0, 0, gr96, msp |
| mtsr ipc, gr96 |
| mtsr ipa, gr97 |
| mtsr ipb, gr98 |
| mtsr q, gr99 |
| ; "pop" registers stack support |
| mtsrim cr, 2-1 |
| add gr99, msp, 2*4 |
| loadm 0, 0, gr96, gr99 |
| add lr1, gr96, 0 |
| add rfb, gr97, 0 |
| ; "pop" remaining global registers |
| mtsrim cr, 25-1 ; gr100-gr124 |
| add gr96, msp, (4+2)*4 |
| loadm 0, 0, gr100, gr96 |
| add msp, msp, (4+2+25)*4 ; repair msp to save_regs entry value |
| ; -------------------------------------------------------- end repair |
| const tav, 324 ; HIF _sigrep |
| asneq 69, gr1,gr1 |
| halt ; commit suicide if returns |
| |
| ; ======================================================== _sigskp() |
| .global __sigskp |
| __sigskp: |
| ; repair_regs |
| ; -------------------------------------------------------- repair_regs |
| mtsrim cr, 4-1 |
| loadm 0, 0, gr96, msp |
| mtsr ipc, gr96 |
| mtsr ipa, gr97 |
| mtsr ipb, gr98 |
| mtsr q, gr99 |
| ; "pop" registers stack support |
| mtsrim cr, 2-1 |
| add gr99, msp, 2*4 |
| loadm 0, 0, gr96, gr99 |
| add lr1, gr96, 0 |
| add rfb, gr97, 0 |
| ; "pop" remaining global registers |
| mtsrim cr, 25-1 ; gr100-gr124 |
| add gr96, msp, (4+2)*4 |
| loadm 0, 0, gr100, gr96 |
| add msp, msp, (4+2+25)*4 ; repair msp to save_regs entry value |
| ; -------------------------------------------------------- end repair |
| const tav, 325 ; HIF _sigskp |
| asneq 69, gr1,gr1 |
| halt ; commit suicide if returns |
| |
| ; ======================================================== _sendsig() |
| ; lr2 = signal number |
| .global _raise |
| .global __sendsig |
| _raise: |
| __sendsig: |
| const tav, 326 ; HIF sendsig |
| asneq 69, gr1,gr1 |
| jmpi lr0 |
| nop |
| |
| ; |
| ; ======================================================== signal() |
| ; lr2 = signal number |
| ; lr3 = handler address |
| .global _signal |
| _signal: |
| ; the memory variable WindowSize must be initalised at the |
| ; start when rfb and rab are a window size apart. |
| const v0, WindowSize ; get register cache size |
| consth v0, WindowSize |
| load 0, 0, v1, v0 |
| cpeq v1, v1, 0 |
| jmpf v1, WindowSizeOK |
| sub v1, rfb, rab ; rfb-rab = WINDOW_SIZE |
| store 0, 0, v1, v0 |
| WindowSizeOK: |
| const v1, SigEntry |
| consth v1, SigEntry |
| sub v3, lr2, 1 ; get handler index |
| sll v3, v3, 2 ; pointer to addresses |
| add v1, v1, v3 |
| store 0,0, lr3, v1 ; save new handler |
| |
| const lr2, sigcode |
| consth lr2, sigcode |
| ;Fall through to __signal |
| ; ======================================================== _signal() |
| .global __signal |
| __signal: |
| const tav, 321 ; HIF signal |
| asneq 69, gr1,gr1 |
| jmpi lr0 |
| nop |