
   MODULE DirtyHandler


   MACRO
   VersionString
   DCS     "Handle      asm 0.05/09  03 Dec 84 16:36:32",0
   MEND


;THIS IS THE ACTUAL IMPLEMENTATION MODULE OF DirtyHandler
; (SEE ALSO DEFINITION MODULE DirtyHandler)

  EXPORTC  DirtyHandler__DirtyHandler      = '_DirtyHandler'
  EXPORTC  DirtyHandler_Version            = 'Version'
  EXPORTC  DirtyHandler_Initialise         = 'Initialise'
  EXPORTC  DirtyHandler_Signal             = 'Signal'
  EXPORTC  DirtyHandler_CurrentMod         = 'CurrentMod'
  EXPORTC  DirtyHandler_MakeClosure        = 'MakeClosure'
  EXPORTC  DirtyHandler_LongJump           = 'LongJump'
  EXPORTC  DirtyHandler_SystemSignal       = 'SystemSignal'
  EXPORTC  DirtyHandler_CallConditionProc  = 'CallConditionProc'
  EXPORTC  DirtyHandler_CallEventProc      = 'CallEventProc'

;******************************

  IMPORTC  String_CopyLC                  = 'String'.'CopyLC'

  IMPORTC  Debug_WriteH                   = 'Debug'.'WriteH'
  IMPORTC  Debug_Writeln                  = 'Debug'.'Writeln'

  IMPORTC  Handler_PANOSEventHandler      = 'Handler'.'PANOSEventHandler'
  IMPORTC  Handler_SignalHandler          = 'Handler'.'SignalHandler'
  IMPORTC  Handler_ConditionHandlerOf     = 'Handler'.'ConditionHandlerOf'
  IMPORTC  Handler_GetUsersEventStackHigh = 'Handler'.'GetUsersEventStackHigh'
  IMPORTC  Handler_GetUsersCondStackHigh  = 'Handler'.'GetUsersCondStackHigh'
  IMPORTC  Handler_GetProgEndEnvironment  = 'Handler'.'GetProgEndEnvironment'
  IMPORTC  Handler_PopEnvironment         = 'Handler'.'PopEnvironment'
  IMPORTC  Handler_NS32000Error           = 'Handler'.'NS32000Error'
  IMPORTC  Program_Stop                   = 'Program'.'Stop'

;**********************************************************************
                                     
;Format of stack frame after exception
;(after entry to DirtyException) follows:

ExceptionReason EQU       12
ExceptionFP     EQU       16
ExceptionPC     EQU       20
ExceptionMOD    EQU       24
ExceptionPSR    EQU       26

;**********************************************************************

;Format of stack frame after Signal 
;(after entry to DirtySignal) follows:


SignalFP     EQU  24
SignalPC     EQU  28
SignalMod    EQU  32
SignalCause  EQU  36
SignalBuffer EQU  40

;**********************************************************************

;Format of stack frame after event
;(after entry to DirtyEvent) is:

EventFP         EQU        0
EventTKPC       EQU        4
EventTKMOD      EQU        8
EventTKPSR      EQU       10
EventY          EQU       12
EventX          EQU       16
EventNumber     EQU       20
EventPC         EQU       24
EventMOD        EQU       28
EventPSR        EQU       30

;**********************************************************************

;For signal, exceptions and events the frame looks like:

EnvSave         EQU      -24
SPSave          EQU      -28
SavedR5         EQU      -32
SavedR6         EQU      -36
SavedR7         EQU      -40

env             EQU      -4
res             EQU      -8


;**********************************************************************

; for signal and exceptions:
calltype        EQU      -12
E1              EQU      -16
E2              EQU      -20

;**********************************************************************

;for events:

EventCode        EQU      -12
Data1            EQU      -16
Data2            EQU      -20

;**********************************************************************
;Format of  Environment record follows:

ENV_Validity  EQU          0
ENV_PC        EQU          4
ENV_SP1       EQU          8
ENV_FP        EQU          12
ENV_UserPSR   EQU          16
ENV_Mod       EQU          20
                  
ENV_R0       EQU           24
ENV_R1       EQU           28
ENV_R2       EQU           32
ENV_R3       EQU           36
ENV_R4       EQU           40
ENV_R5       EQU           44
ENV_R6       EQU           48
ENV_R7       EQU           52



;**********************************************************************
;Format of queued EVENT record follows:

SizeOfEventRecord      EQU 16
ECode                  EQU 0
EData1                 EQU 4
EData2                 EQU 8

;**********************************************************************

TV_Pulse                      EQU 4
ContextChangeEvent            EQU 252
EventRecordsAvailable         EQU 16

SizeOfEnvRecord    EQU 88

TK_ABORT             EQU 17
TK_TAKE_OVER_VDT     EQU 40
TK_SET_EVENT_HANDLER EQU 30
TK_CONTROL_EVENT     EQU 57

;**********************************************************************

;GLOBAL DATA AREA

  AREADEF        DirtyHandler_data_frame, [DATA], DOUBLE  
  AREA           DirtyHandler_data_frame
  EXPORT DirtyHandler_1
  EXPORT DirtyHandler_2

DirtyHandler_1
DirtyHandler_2

  DEFSB          DirtyHandler_1
  ADDRESS        DirtyHandler_4


NIL                 DCD        #X80000000
LastEventAdded      DCD        0          ; points at last event to be added 
                                          ; in pending area           
NumberOfPulses      DCD        0          ; initially no outstanding pulses

InUsersEventHandler     DCD        0
InUsersConditionHandler DCD        0  

SavedEventsAreaEnd  DCD        0
EventQptr           DCD        0

ProgEnv             DCD        0
;***********************************************************************

EventDescriptor  CDESC      DirtyHandler_DirtyEvent

;***********************************************************************

VDT_Table

  CDESC  DirtyHandler_NVIproc
  CDESC  DirtyHandler_NMIproc
  CDESC  DirtyHandler_ABTproc
  CDESC  DirtyHandler_FPUproc
  CDESC  DirtyHandler_ILLproc
  CDESC  DirtyHandler_SVCproc
  CDESC  DirtyHandler_DVZproc
  CDESC  DirtyHandler_FLGproc
  CDESC  DirtyHandler_BPTproc
  CDESC  DirtyHandler_TRCproc
  CDESC  DirtyHandler_UNDproc

;***********************************************************************

SavedEventsArea

    ALLOCD SizeOfEventRecord*EventRecordsAvailable    ;space for 16 entries

;***********************************************************************

CodeArea

  AREADEF DirtyHandler_code_frame, [CODE, READ], DOUBLE
  AREA DirtyHandler_code_frame
DirtyHandler_0


;******************************************************************************
DirtyHandler_Initialise

            ENTER  [R6,R7],8 

;****install all 10 BBC event handlers (ie 0,1...9)
            MOVQD  =0,R7       
NextHandler CMPD   =10,R7     
            BLE    AllHandlersInstalled       
            MOVZBD =TK_SET_EVENT_HANDLER,R0  
            MOVD   R7,R1     
            MOVD   EventDescriptor,R2
            SVC       
            DCB    0  
            MOVQD  =0,R0 
            ADDQD  =1,R7  
            BR     NextHandler      
;instal event 255 handler
            MOVZBD =TK_SET_EVENT_HANDLER,R0  
            MOVD   =255,R1     
            MOVD   EventDescriptor,R2
            SVC       
            DCB    0  

AllHandlersInstalled

;****install event handler for Tiny Kernel event "context change event"
            MOVZBD =TK_SET_EVENT_HANDLER,R0  
            MOVD   =ContextChangeEvent,R1
            MOVD   EventDescriptor,R2
            SVC       
            DCB    0  

;****initialise circular buffer used for events pending
            MOVD   =EventRecordsAvailable,R7
            ADDR   SavedEventsArea,R6
InitNext
            MOVD   NIL,0(R6)
            ADDD   =SizeOfEventRecord,R6
            SUBD   =1,R7
            CMPD   =0,R7
            BNE    InitNext
            ADDR   SavedEventsArea,SavedEventsAreaEnd
            ADDD  =(EventRecordsAvailable*SizeOfEventRecord),SavedEventsAreaEnd
            ADDR   SavedEventsArea,LastEventAdded

;take over VDT 
            ADDR   VDT_Table,R1   
            MOVZBD =TK_TAKE_OVER_VDT,R0  
            SVC   
            DCB    0

            MOVD  =0,InUsersEventHandler   

            EXIT   [R6,R7]
            RXP 0       



;****************************************************************************
DirtyHandler_DirtyEvent
            ENTER   [R5,R6,R7],28
            SPRD    SP,SPSave(FP)  
            ADJSPW  =SizeOfEnvRecord           ;grab space for environ. record
            SPRD    SP,R7                      ;and point R7 at it
            MOVD    R7,EnvSave(FP)
            CMPD    EventNumber(FP),=ContextChangeEvent             
            BEQ     ContextChangeEventReceived
            BSR     QueueEvent
            TBITB   =8,EventPSR(FP)            ;if event whilst in supervisor
                                               ;request context change event
            BFC     EventInSup
            CMPD    InUsersEventHandler,=1
            BEQ     EventReturn                ;if event in users handler
                                               ;then just return
            ;if event in dirty handler return
            CMPW    EventDescriptor,EventMOD(FP)  ;is it mod of dirty handler?
            BNE     DeliverEvent               ;if not same mod then
                                               ;in ordinary user code - deliver
            ;otherwise its in the mod of the dirty handler
            ;(and its in user mode!) therefore return.
            BR      EventReturn
ContextChangeEventReceived
            ;if event in users handler then just return
            CMPD    InUsersEventHandler,=1
            BEQ     EventReturn
            ;*****TO GET ROUND BUG IN TK IMPLEMENATION OF SVC 57****
            ;*****IF PSR INDICATES IN SUP MODE THEN JUST RETURN ****
            ;*****THUS ENSURING THAT ANOTHER CONTEXT EVENT WILL ****
            ;*****BE GIVEN AFTER NEXT SVC                       ****
            TBITB    =8,EventPSR(FP)  
            BFC  EventReturn                   ;if U=0 ,in sup mode so return
            ;else in ordinary user code so disable any
            ;further end of svc events and give event
            BSR DisableContextEvent
            BR  DeliverEvent
EventInSup
            ;if event occured whilst in supervisor mode
            ;ask for context change event and return.
            BSR EnableContextEvent
            BR  EventReturn
DeliverEvent
            MOVD    EnvSave(FP),R7
            BSR     SaveEventContext           ;save event environ. in R7.Env
            BSR DirtyHandler_EmptyQueue        ;empty queue
            BSR RestoreEventContext
EventReturn ;resume processing from state in Env(pointed at by R7 )
            LPRD SP,SPSave(FP)
            EXIT   [R5,R6,R7]
            RXP 0


;******************************************************************   
EnableContextEvent
            MOVD R1,TOS
            MOVD R2,TOS
            MOVD =ContextChangeEvent,R1        ;(end of svc event actually!)
            MOVD =1,R2                         ;disable the event 
            SVC
            DCB TK_CONTROL_EVENT
            MOVD TOS,R2
            MOVD TOS,R1

            RET 0


;******************************************************************   
DisableContextEvent
            MOVD R1,TOS
            MOVD R2,TOS
            MOVD =ContextChangeEvent,R1        ;(end of svc event actually!)
            MOVD =0,R2                         ;disable the event 
            SVC
            DCB TK_CONTROL_EVENT
            MOVD TOS,R2
            MOVD TOS,R1

            RET 0



;******************************************************************   
QueueEvent
;  For all events except TV pulse place event on
;  circular queue of events.If event is TV pulse then
;  make a record of the pulse.
; 
; EventNumber(FP)
; EventX(FP)
; EventY(FP)

; IF (LastEventAdded + SizeOfEventRecord) > SavedEventsAreaEnd
;    THEN add to start of area ie at start of pending area
; ELSE
;    add to (LastEventAdded + SizeOfEventRecord)
; END
; Update LastEventAdded


            CMPD =TV_Pulse,EventNumber(FP)
            BEQ ItsAPulse

            ADDD =SizeOfEventRecord,LastEventAdded
            CMPD LastEventAdded,SavedEventsAreaEnd
            BLT AddToQueue
            ADDR SavedEventsArea,LastEventAdded
AddToQueue
            MOVD EventNumber(FP),ECode(LastEventAdded)
            MOVD EventX(FP),EData1(LastEventAdded)
            MOVD EventY(FP),EData2(LastEventAdded)
            RET 0
ItsAPulse
            ADDD =1,NumberOfPulses
            RET 0



;******************************************************************   
DirtyHandler_EmptyQueue

; Calls handlers for all events in event queue(including TV pulse)
; Remove first non NIL entry after LastEventAdded and make that 
; entry NIL.
; On entry R7 points at environment record.

            MOVD    R4,TOS                    ;work register
Dequeue
            CMPD    NIL,ECode(LastEventAdded)
            BEQ     EmptyQueueDone            ;return,all emptied
            MOVD    LastEventAdded,EventQptr
            MOVD    =1,R4
nextincircle
            ADDD    =SizeOfEventRecord,EventQptr
            CMPD    EventQptr,SavedEventsAreaEnd
            BLT     TestIt
            ADDR    SavedEventsArea,EventQptr
TestIt
            CMPD    NIL,ECode(EventQptr)
            BEQ     nextincircle
nonNILfound
;here,EventQptr points at entry to be removed
           MOVD         =1,InUsersEventHandler        ;flag in users handler
;enter users event procedure with new stack
;NB. users event handler can not be iterrupted .
;**           CXP          Handler_GetUsersEventStackHigh
           BISPSRW      =#X0200               ;switch to user stack-STILL SUP.
;**           LPRD         SP,R0
           BISPSRW      =#X0800               ;ENABLE INTS.
           BISPSRW      =#X0100               ;switch to user MODE
           MOVD         R7,TOS                ;environment pointer
           MOVD         EData2(EventQptr),TOS
           MOVD         EData1(EventQptr),TOS
           MOVD         ECode(EventQptr),TOS
           MOVD         NIL,ECode(EventQptr)  ;remove from queue

           CXP Handler_PANOSEventHandler  

;back to supervisor mode and supervisor stack
           SVC
           DCB 100
           BICPSRW =#X0800                    ;disable events
           MOVD =0,InUsersEventHandler             ;flag out of users handler
           CMPD EventQptr,LastEventAdded
           BNE  nextincircle
EmptyQueueDone                                ;NB. ints are here disabled.
           CMPD =0,NumberOfPulses
           BNE  Pulse
           MOVD TOS,R4
           RET 0
Pulse
;ADD pseudo pulse event to queue and continue
           ADDD =SizeOfEventRecord,LastEventAdded
           CMPD LastEventAdded,SavedEventsAreaEnd
           BLT AddQueue
           ADDR SavedEventsArea,LastEventAdded
AddQueue
           MOVD =TV_Pulse,ECode(LastEventAdded)
           MOVD  NumberOfPulses,EData1(LastEventAdded)
           MOVD  =0,EData2(LastEventAdded)
           MOVD LastEventAdded,EventQptr
           MOVQD =0,NumberOfPulses
           BR   nonNILfound



;******************************************************************   
SaveEventContext

           BISPSRW =#X0200
           SPRD    SP,ENV_SP1(R7)               ;save user stack pointer
           BICPSRW =#X200
           MOVZBD  EventPSR(FP),ENV_UserPSR(R7) ;save PSR value
           MOVD    =#X1FFFF,ENV_Validity(R7)    ;all reg fields are valid
           MOVD    EventPC(FP),ENV_PC(R7)       ;PC
           MOVD    EventFP(FP),ENV_FP(R7)       ;FP
           MOVZWD  EventMOD(FP),ENV_Mod(R7)     ;MOD
           MOVD    R0,ENV_R0(R7)     
           MOVD    R1,ENV_R1(R7)     
           MOVD    R2,ENV_R2(R7)     
           MOVD    R3,ENV_R3(R7)     
           MOVD    R4,ENV_R4(R7)     
           MOVD    R5,ENV_R5(R7)     
           MOVD    SavedR5(FP),ENV_R5(R7)
           MOVD    SavedR6(FP),ENV_R6(R7)
           MOVD    SavedR7(FP),ENV_R7(R7)
           RET     0


;******************************************************************   
RestoreEventContext

           BISPSRW =#X0200
           LPRD    SP,ENV_SP1(R7)                ;RESTORE USER STACK POINTER
           BICPSRW =#X0200
           MOVB    ENV_UserPSR(R7),EventPSR(FP)  ;RESTORE user PSR
           MOVD    ENV_PC(R7),     EventPC(FP)   ;PC
           MOVD    ENV_FP(R7),     EventFP(FP)   ;FP
           MOVW    ENV_Mod(R7),    EventMOD(FP)  ;MOD
           MOVD    ENV_R0(R7),R0     
           MOVD    ENV_R1(R7),R1    
           MOVD    ENV_R2(R7),R2
           MOVD    ENV_R3(R7),R3     
           MOVD    ENV_R4(R7),R4     
           MOVD    ENV_R5(R7),R5     
           MOVD    ENV_R5(R7),SavedR5(FP)
           MOVD    ENV_R6(R7),SavedR6(FP)
           MOVD    ENV_R7(R7),SavedR7(FP)
           RET     0


;******************************************************************   
DirtyHandler_DirtyException

           ENTER   [R5,R6,R7],28 

           SPRD    SP,SPSave(FP)
           ADJSPW  =SizeOfEnvRecord  
           SPRD    SP,E2(FP)                           ;points at EnvException
           ADJSPW  =SizeOfEnvRecord  
           SPRD    SP,E1(FP)                           ;points at EnvNext
           MOVZBD  ExceptionPSR(FP),ENV_UserPSR(E2(FP));save user PSR value 
           MOVD    E2(FP),R7
           BSR     SaveExceptionContext                ;R7 points at env record
           MOVD    =2,calltype(FP) ;call type = Except
           MOVD    ENV_Validity(E2(FP))  ,ENV_Validity(E1(FP))
           MOVD    ENV_PC(E2(FP))        ,ENV_PC(E1(FP))
           MOVD    ENV_SP1(E2(FP))       ,ENV_SP1(E1(FP))
           MOVD    ENV_FP(E2(FP))        ,ENV_FP(E1(FP))
           MOVD    ENV_UserPSR(E2(FP))   ,ENV_UserPSR(E1(FP))
           MOVD    ENV_Mod(E2(FP))       ,ENV_Mod(E1(FP))
           MOVD    ENV_R0(E2(FP)),ENV_R0(E1(FP))
           MOVD    ENV_R1(E2(FP)),ENV_R1(E1(FP))
           MOVD    ENV_R2(E2(FP)),ENV_R2(E1(FP))
           MOVD    ENV_R3(E2(FP)),ENV_R3(E1(FP))
           MOVD    ENV_R4(E2(FP)),ENV_R4(E1(FP))
           MOVD    ENV_R5(E2(FP)),ENV_R5(E1(FP))
           MOVD    ENV_R6(E2(FP)),ENV_R6(E1(FP))
           MOVD    ENV_R7(E2(FP)),ENV_R7(E1(FP))
                  

Repeating
;to supervisor mode and supervisor stack
           SVC
           DCB     100
           BISPSRW =#X0800              ;disable interrupts

;switch to user stack 
           BISPSRW =#X0200              ;leave in supervisor mode
;enter users Condition handler .If condition did occur
;in condition handler then use existing temporary user stack.
;Otherwise ener with new stack.
;**           CMPD =1,InUsersConditionHandler
;**           BEQ  StacksFine
;**           ;give it new stack

;**           CXP Handler_GetUsersCondStackHigh
;**           LPRD SP,R0
;**StacksFine

;ints now off-left off by EmptyQueue

           MOVD    ENV_Mod(E1(FP)),TOS
           ADDR    res(FP),TOS ;for result
           CXP     Handler_ConditionHandlerOf  
           MOVD    E2(FP),TOS ;EnvException
           MOVD    E1(FP),TOS ;EnvNext

           MOVD    ExceptionReason(FP),TOS
           CXP     Handler_NS32000Error
           MOVD    R0,TOS
           MOVD    calltype(FP),TOS ;call type
;   CXPD res(FP) ;  and enable ints as enter
           MOVD    =1,InUsersConditionHandler
           MOVW    =0,TOS
           SPRW    MOD,TOS
           ADDR    ReturnPoint,TOS
           MOVW    =#X0B00,TOS         ;psr for exception handler-ints enabled!
           MOVW    res(FP),TOS         ;mod for exception handler
           MOVD    res(FP),TOS
           LSHD    =-16,0(SP)          ;pc offset
           MOVZWD  res(FP),TOS         ;zero extended MOD
           ADDD    8(0(SP)),4(SP)      ;add program base to offset
           CMPQD   =0,TOS
           RETT    0                   ;enter handler
;handler RXP's to here-still in user mode
ReturnPoint
           MOVD    =0,InUsersConditionHandler
           MOVD    R0,res(FP)             ;save result from user handler
           ;if value < 0 returned then no more repeating
           CMPD R0,=0
           BLT  endofrepeating
           ;if a Unwind had been requested and it didn't then no more repeating
           CMPD  =8,calltype(FP)  ;is call type Unwind?
           BNE notunwind
;return after unwind
           CMPQD =0,R0  ;not handled?
           BEQ endofrepeating
           ;unwind was success - call handler with type= ExceptPasssedOn
           MOVD =3,calltype(FP)
           BR Repeating
;return after except
notunwind
           ;if except was not handled recall handler asking for Unwind.
           MOVD    =8,calltype(FP)               ;SET call type to Unwind
           CMPD    res(FP),=0
           BEQ     Repeating

endofrepeating
;here if result from handler = 1(OkHandled),0(Nothandled) .
;back to supervisor mode and supervisor stack
           SVC
           DCB     100
           CMPQD   =0,res(FP) 
           BEQ     handlersaysabort    
;result from handler = 1 so resume user program at state pointed at by E1(FP)
resumeafterexception
           MOVD    E2(FP),R7
           MOVB    ENV_UserPSR(R7),ExceptionPSR(FP)  ;restore PSR value
           BSR     RestoreExceptionContext           ;R7 points at context
           LPRD    SP,SPSave(FP)
           BSR     DirtyHandler_EmptyQueue
 ;ints now off-left off by EmptyQueue
           EXIT    [R5,R6,R7]   
           RXP     4        ;return where ints are finally enabled



;******************************************************************   
DirtySignal

; STILL IN USER MODE           
          ENTER    [R5,R6,R7],28 
          SPRD     SP,SPSave(FP)  
          ADJSPW   =SizeOfEnvRecord    
          SPRD     SP,E2(FP)   
          MOVD     SPSave(FP),ENV_SP1(E2(FP)) 
          SPRW     UPSR,ENV_UserPSR(E2(FP))  ; PSR
;calculate user stack pointer just before signal(a,b)
          ADDD     =(SignalBuffer+4-SavedR7),ENV_SP1(E2(FP))
          MOVD     E2(FP),R7  
          BSR SaveSignalContext
;IF CAUSE IS NEGATIVE AND IF I BIT(BIT 14) IS SET THEN
;COPY BUFFER TO IMAGE OF R1
          CMPD     SignalCause(FP),=0
          BGE      NotNeg
          TBITB    =14,SignalCause(FP)
          BFC      NoInfo
;copy to R1
          MOVD     SignalBuffer(FP),ENV_R1(E2(FP))

NotNeg
NoInfo  
;enter users Condition handler .If Signal condition did occur
;in condition handler then use existing temporary user stack.
;Otherwise enter with new stack.
;**           CMPD =1,InUsersConditionHandler
;**           BEQ  StackisOK
;**           ;give it new stack
;**           CXP Handler_GetUsersCondStackHigh
;**           LPRD SP,R0
;**StackisOK
          MOVD     =1,InUsersConditionHandler
          MOVD     SignalCause(FP),TOS 
          MOVD     E2(FP),TOS   
          CXP      Handler_SignalHandler
        ;result =1  OkHandled     -so return to program
        ;       =0  NotHandled    -so Abort

          MOVD     R0,res(FP)
          MOVD     =0,InUsersConditionHandler

          CMPQD    =0,res(FP) 
          BEQ      handlersaysabort    
          MOVD     E2(FP),R7

  ;Handler did handle Signal
  ;therefore RESUME PROCESSING FROM STATE POINTED AT BY R7
resume

          BSR      RestoreSignalContext

         LPRD     SP,   ENV_SP1(R7)
         LPRD     FP,   ENV_FP(R7)
         MOVD     ENV_PC(R7),TOS
         LPRD     MOD, ENV_Mod(R7)
         MOVD        ENV_Mod(R7),R6

         LPRD     SB, 0(R6)
         MOVD     ENV_R6(R7),R6
         LPRB     UPSR,ENV_UserPSR(R7)         ; PSR
         MOVD     ENV_R7(R7),R7
         RET      0


;******************************************************************   
DirtyHandler_SystemSignal   ; ( ERROR : INTEGER ; NumberOfDoubles : CARDINAL);

; STILL IN USER MODE           
          ENTER    [R5,R6,R7],28 
          ADJSPW   =SizeOfEnvRecord    
          SPRD     SP,E2(FP)   
          MOVD     0(0(FP)),R6          ;fp(handler) -> fp(panoslibproc)
          MOVD     0(R6), ENV_FP(E2(FP))     ;FP of "user"
;calculate user stack pointer just before XLibraryProcedure(a1,a2..aN)
          MOVD    16(FP)  ,ENV_SP1(E2(FP));# Of Doubles pushed across interface
          LSHD    =2      ,ENV_SP1(E2(FP))
          ADDD    =12     ,ENV_SP1(E2(FP))
          ADDD    R6      ,ENV_SP1(E2(FP))     ;SP
          MOVD    4(R6)   ,ENV_PC(E2(FP))      ;PC
          MOVZWD  8(R6)   ,ENV_Mod(E2(FP))     ;MOD
          MOVD    =0      ,ENV_UserPSR(E2(FP)) 
          MOVD    =#X0017 ,ENV_Validity(E2(FP))
;enter users Condition handler .If Signal condition did occur
;in condition handler then use existing temporary user stack.
;Otherwise enter with new stack.
;**           CMPD =1,InUsersConditionHandler
;**           BEQ  StacksOK
;**           ;give it new stack
;**           CXP Handler_GetUsersCondStackHigh
;**           LPRD SP,R0
;**StacksOK
          MOVD     =1,InUsersConditionHandler
          MOVD     12(FP),TOS                ;error
          MOVD     E2(FP),TOS                ;ptr to environment
          CXP      Handler_SignalHandler
        ;result =1  OkHandled     -so return to program
        ;       =0  NotHandled    -so Abort
          MOVD     R0,res(FP)
          MOVD     =0,InUsersConditionHandler
          CMPQD    =0,res(FP) 
          BEQ      handlersaysabort    
          MOVD     E2(FP),R7

  ;Handler did handle Signal
  ;therefore RESUME PROCESSING 
         MOVD     E2(FP) ,R7  
         LPRD     SP,   ENV_SP1(R7)
         LPRD     FP,   ENV_FP(R7)
         MOVD     ENV_PC(R7),TOS
         LPRD     MOD, ENV_Mod(R7)
         MOVD        ENV_Mod(R7),R6
         LPRD     SB, 0(R6)
         MOVD        ENV_R0(R7),R0
         MOVD        ENV_R1(R7),R1
         MOVD        ENV_R2(R7),R2
         MOVD        ENV_R3(R7),R3
         MOVD        ENV_R4(R7),R4
         MOVD        ENV_R5(R7),R5
         MOVD        ENV_R6(R7),R6
         LPRB        UPSR,ENV_UserPSR(R7)         ; PSR

         MOVD        ENV_R7(R7),R7

         RET      0



;******************************************************************   
; PROCEDURE MakeClosure( VAR Closure : UsersEnvironment ) : BOOLEAN ;
; Saves the environment of the caller.
; Always returns TRUE.
; When LongJump(Closure) is performed, simulates a return to the caller of
; MakeClosure() with a result of FALSE.
; i.e.
;
;        IF MakeClosure( Closure ) THEN
;            (* Normal return *)
;                     ....
;        ELSE
;            (* LongJump has been performed on the closure *)
;
; Stack after entry is :
;
; Closure Variable                      12(FP)
; Closure Value of Caller's MOD          8(FP)
; Closure Value of Caller's PC           4(FP)
; Closure Value of Caller's FP           0(FP)
; Closure Value of Caller's SP           FP + 16

DirtyHandler_MakeClosure
         ENTER  [],0   
         MOVZWD 8(FP),        ENV_Mod(12(FP))
         MOVD   4(FP),        ENV_PC(12(FP))
         MOVD   0(FP),        ENV_FP(12(FP))
         ADDR   16(FP),       ENV_SP1(12(FP))
         MOVD   =#x1FFF,      ENV_Validity(12(FP)) ; All but FP are valid
         SPRD   UPSR ,        ENV_UserPSR(12(FP))

         MOVD  R0,            ENV_R0(12(FP))     
         MOVD  R1,            ENV_R1(12(FP))     
         MOVD  R2,            ENV_R2(12(FP))     
         MOVD  R3,            ENV_R3(12(FP))     
         MOVD  R4,            ENV_R4(12(FP))     
         MOVD  R5,            ENV_R5(12(FP))     
         MOVD  R6,            ENV_R6(12(FP))
         MOVD  R7,            ENV_R7(12(FP))

;        MOVD  12(FP), TOS
;        BSR   SaveFPRegisters
  
            MOVD  =0,InUsersEventHandler   

         MOVQD =1, R0               ; Return TRUE
         EXIT  []  
         RXP   4  


;******************************************************************   
; PROCEDURE LongJump( Closure : UsersEnvironmentPTR ) ;
; Resumes to the caller of MakeClosure(Closure). See MakeClosure for details.
; On Entry Closure pointer is at 12(FP)

DirtyHandler_LongJump
         ENTER  [],0   

;        MOVD   12(FP),           TOS
;        BSR    RestoreFPRegisters

         MOVD   ENV_R7(12(FP)),   R7
         MOVD   ENV_R6(12(FP)),   R6
         MOVD   ENV_R5(12(FP)),   R5
         MOVD   ENV_R4(12(FP)),   R4
         MOVD   ENV_R3(12(FP)),   R3
         MOVD   ENV_R2(12(FP)),   R2
         MOVD   ENV_R1(12(FP)),   R1
         MOVD   ENV_R0(12(FP)),   R0

         LPRD   UPSR ,            ENV_UserPSR(12(FP))

         LPRD   SP,               ENV_SP1(12(FP))
         MOVZWD ENV_Mod(12(FP)),  TOS
         MOVD   ENV_PC(12(FP)),   TOS
         LPRD   FP,               ENV_FP(12(FP))
 
         MOVQD  =0, R0                           ; Return FALSE
         RXP    0


;******************************************************************   
handlersaysabort   
;ABORT -- HANDLER DID NOT HANDLE Signal
          SVC
          DCB    21
          DCS    "Handler : ABORT in condition handler*0A*0D"
abort
          BR     abort    ;LOOP FOREVER
          ;***ABORT***


;******************************************************************   
SaveExceptionContext
   
          SPRB     UPSR,ENV_UserPSR(R7)         ; PSR
          MOVD   =#X1FFFF,ENV_Validity(R7)      ; All reg fields are valid
          MOVD   ExceptionPC(FP),ENV_PC(R7)     ; PC
          BISPSRW =#B001000000000                
          SPRD    SP,ENV_SP1(E2(FP))                  ;save user SP - (SP1)
          BICPSRW =#B001000000000

          MOVD   ExceptionFP(FP),ENV_FP(R7)     ; FP
          MOVZWD ExceptionMOD(FP),ENV_Mod(R7)   ; MOD

          MOVD   R0,ENV_R0(R7)     
          MOVD   R1,ENV_R1(R7)     
          MOVD   R2,ENV_R2(R7)     
          MOVD   R3,ENV_R3(R7)     
          MOVD   R4,ENV_R4(R7)     
          MOVD   R5,ENV_R5(R7)     
          MOVD   SavedR5(FP),ENV_R5(R7)
          MOVD   SavedR6(FP),ENV_R6(R7)
          MOVD   SavedR7(FP),ENV_R7(R7)
          RET    0


;******************************************************************   
RestoreExceptionContext

         MOVD  ENV_PC(R7),ExceptionPC(FP)                  ; PC
         MOVD  ENV_FP(R7), ExceptionFP(FP)                 ; FP
         MOVW  ENV_Mod(R7),ExceptionMOD(FP)                ; MOD 
         BISPSRW =#B001000000000                
         LPRD    SP,ENV_SP1(R7)                  ;RESTORE user SP - (SP1)
         BICPSRW =#B001000000000

         MOVD  ENV_R0(R7),R0     
         MOVD  ENV_R1(R7),R1     
         MOVD  ENV_R2(R7),R2     
         MOVD  ENV_R3(R7),R3     
         MOVD  ENV_R4(R7),R4     
         MOVD  ENV_R5(R7),R5     
         MOVD  ENV_R5(R7),SavedR5(FP)
         MOVD  ENV_R6(R7),SavedR6(FP)
         MOVD  ENV_R7(R7),SavedR7(FP)
         RET   0


;******************************************************************   
SaveSignalContext
   
         MOVD   =#X1FFFF,ENV_Validity(R7)   ; All reg fields are valid
         MOVD   SignalPC(FP),ENV_PC(R7)     ; PC

         MOVD   SignalFP(FP),ENV_FP(R7)     ; FP
         MOVZWD SignalMod(FP),ENV_Mod(R7)   ; MOD

         MOVD  R0,ENV_R0(R7)     
         MOVD  R1,ENV_R1(R7)     
         MOVD  R2,ENV_R2(R7)     
         MOVD  R3,ENV_R3(R7)     
         MOVD  R4,ENV_R4(R7)     
         MOVD  R5,ENV_R5(R7)     
         MOVD  SavedR5(FP),ENV_R5(R7)
         MOVD  SavedR6(FP),ENV_R6(R7)
         MOVD  SavedR7(FP),ENV_R7(R7)
         RET   0


;******************************************************************   
RestoreSignalContext


         MOVD  ENV_R0(R7),R0     
         MOVD  ENV_R1(R7),R1     
         MOVD  ENV_R2(R7),R2     
         MOVD  ENV_R3(R7),R3     
         MOVD  ENV_R4(R7),R4     
         MOVD  ENV_R5(R7),R5     
         MOVD  ENV_R5(R7),R5
         MOVD  ENV_R6(R7),R6
         RET   0


;******************************************************************   
DirtyHandler_CurrentMod
        ENTER [],0   
        MOVZWD 52(FP),R0  
        EXIT []  
        RXP  0  


;******************************************************************   
; Entry point to PROCEDURE NVIproc

DirtyHandler_NVIproc
        ENTER [],0   
        MOVQD =0,TOS    
        SPRD MOD,TOS   
        BSR DirtyHandler_DirtyException   
        EXIT []  
        RETT 0  


;******************************************************************   
; Entry point to PROCEDURE NMIproc

DirtyHandler_NMIproc
        ENTER [],0 
        MOVQD =1,TOS   
        SPRD MOD,TOS   
        BSR DirtyHandler_DirtyException   
        EXIT []   
        RETT 0    


;******************************************************************   
; Entry point to PROCEDURE ABTproc
DirtyHandler_ABTproc
        ENTER [],0 
        MOVQD =2,TOS   
        SPRD MOD,TOS   
        BSR DirtyHandler_DirtyException   
        EXIT []   
        RETT 0    


;******************************************************************   
; Entry point to PROCEDURE FPUproc
DirtyHandler_FPUproc
        ENTER [],0 
        MOVQD =3,TOS  
        SPRD MOD,TOS  
        BSR DirtyHandler_DirtyException   
        EXIT []   
        RETT 0    


;******************************************************************   
; Entry point to PROCEDURE ILLproc
DirtyHandler_ILLproc
        ENTER [],0
        MOVQD =4,TOS  
        SPRD MOD,TOS  
        BSR DirtyHandler_DirtyException   
        EXIT []   
        RETT 0    


;******************************************************************   
; Entry point to PROCEDURE SVCproc
DirtyHandler_SVCproc
        ENTER [],0 
  
  ;if SVC=100 then return to instruction
  ;just after SVC with supervisor stack and supervisor  mode.
        CMPB  =100,1(4(FP)) ;look at byte following SVC code
        BEQ  To_Supervisor
        MOVQD =5,TOS   
        SPRD MOD,TOS   
        BSR DirtyHandler_DirtyException   
        EXIT []   
        RETT 0    
To_Supervisor
        ADDQD =2,4(FP)         ;adjust PC
        ANDW   =#XFCFF,10(FP)   ;adjust U=0 and S=0
        EXIT []
        RETT 0


;******************************************************************   
; Entry point to PROCEDURE DVZproc
DirtyHandler_DVZproc
        ENTER [],0 
        MOVQD =6,TOS   
        SPRD MOD,TOS   
        BSR DirtyHandler_DirtyException   
        EXIT []   
        RETT 0    


;******************************************************************   
; Entry point to PROCEDURE FLGproc
DirtyHandler_FLGproc
        ENTER [],0
        MOVQD =7,TOS  
        SPRD MOD,TOS  
        BSR DirtyHandler_DirtyException  
        EXIT []  
        RETT 0   


;******************************************************************   
; Entry point to PROCEDURE BPTproc
DirtyHandler_BPTproc
        ENTER [],0 
        MOVZBD =8,TOS  
        SPRD MOD,TOS   
        BSR DirtyHandler_DirtyException   
        EXIT []   
        RETT 0    


;*******************************************************************   
; Entry point to PROCEDURE TRCproc
DirtyHandler_TRCproc
        ENTER [],0 
        MOVZBD =9,TOS  
        SPRD MOD,TOS   
        BSR DirtyHandler_DirtyException  
        EXIT []  
        RETT 0   


;******************************************************************   
; Entry point to PROCEDURE UNDproc
DirtyHandler_UNDproc
        ENTER [],0 
        MOVZBD =10,TOS 
        SPRD MOD,TOS   
        BSR DirtyHandler_DirtyException  
        EXIT []  
        RETT 0   


;******************************************************************   
; Entry point to PROCEDURE Signal
; ENTRY TO HERE IN USER MODE           

DirtyHandler_Signal
        ENTER  [],0
        SPRD MOD,TOS
        BSR    DirtySignal
        EXIT   []
        RXP    0



; ****************************************************************************
; PROCEDURE CallEventProc(Proc      : UserEventHandler;
;                         P1        : INTEGER;
;                         P2        : INTEGER;
;                         P3        : INTEGER;
;                         P4        : INTEGER;
;                         VAR Env   : UsersEnvironment);

DirtyHandler_CallEventProc

        ENTER  [R4-R7],0
        ADJSPB =5*4
        MOVMD  16(FP),0(SP),4
        MOVD   16+4*4(FP), 4*4(SP)
        CXPD   12(FP)
        EXIT   [R4-R7]
        RXP    6*4






; ****************************************************************************
;PROCEDURE CallConditionProc(Proc     : ConditionHandlerType;
;                            Type     : TypeCode;
;                            Param    : INTEGER;
;                            VAR Env1 : UsersEnvironment;
;                            VAR Env2 : UsersEnvironment):INTEGER;



DirtyHandler_CallConditionProc

        ENTER  [R4-R7],0
        ADJSPB =4*4
        MOVMD  16(FP),0(SP),4
        CXPD   12(FP)
        EXIT   [R4-R7]
        RXP    5*4




;******************************************************************************

SystemFail
        MOVD  res(FP),TOS
        CXP   Program_Stop

;******************************************************************   

; Entry point to MODULE DirtyHandler
DirtyHandler__DirtyHandler
      ENTER [],0 
      EXIT []   
      RXP 0   


;******************************************************************   
;   PROCEDURE Version( VAR String : ARRAY OF CHAR ) ;
;   BEGIN
;      CopyLC( "DirtyHandler    x.xx/xx dd-MMM-yy hh:mm" , String ) ;
;   END Version ;
;
String_Address        EQU 12
String_Size           EQU 16

DirtyHandler_Version
      ENTER [],0
      MOVD      String_Size(FP),      TOS
      MOVD      String_Address(FP),   TOS
      MOVZBD    Literal_Version,      TOS
      ADDR      Literal_Version+1,    TOS
      CXP       String_CopyLC
      EXIT []
      RXP 8

Literal_Version
      VersionString

;******************************************************************   
  
DirtyHandler_4
   CDESC   DirtyHandler__DirtyHandler
   CDESC   DirtyHandler_Version

  END




