; This source code in this file is licensed to You by Castle Technology
; Limited ("Castle") and its licensors on contractual terms and conditions
; ("Licence") which entitle you freely to modify and/or to distribute this
; source code subject to Your compliance with the terms of the Licence.
; 
; This source code has been made available to You without any warranties
; whatsoever. Consequently, Your use, modification and distribution of this
; source code is entirely at Your own risk and neither Castle, its licensors
; nor any other person who has contributed to this source code shall be
; liable to You for any loss or damage which You may suffer as a result of
; Your use, modification or distribution of this source code.
; 
; Full details of Your rights and obligations are set out in the Licence.
; You should have received a copy of the Licence with this source code file.
; If You have not received a copy, the text of the Licence is available
; online at www.castle-technology.co.uk/riscosbaselicence.htm
; 
        SUBT    Interupt handler and Event generator. ==> &.Arthur.Econet.Background

        ALIGN   $Alignment
Interrupt       ROUT
        Push    "lr"
        ADR     r14, IOC
        LDRB    r14, [ r14, #IOCIRQREQA ]               ; IRQ Request register
        TST     r14, #force_bit                         ; IRQ forced from FIQ
        Pull    "pc", EQ                                ; If it wasn't an FIQ to IRQ down-grade
        LD      r14, FIQStatus
        TEQ     r14, #FIQ_Owner                         ; Are we the owner of FIQ?
        Pull    "pc", NE                                ; If it wasn't us who did it, give it back
        TEQP    psr, #( IFlag + SVC_mode )              ; Goto SVC
        NOP
        Push    "r0-r4, lr"                             ; On supervisor stack
        [       DebugIRQ
        LDR     r2, =Border_Pink
        ADR     r3, VIDC
        STR     r2, [ r3, #0 ]
        ]
InterruptLoop
        TEQP    psr, #( FFlag + IFlag + SVC_mode )      ; Disable FIQ
        ADR     r1, IOC                                 ; Not mode dependent
        LDRB    r0, [ r1, #IOCIRQMSKA ]                 ; IRQ Mask register
        BIC     r0, r0, #force_bit                      ; Must clear it first in case it happens again!
        STRB    r0, [ r1, #IOCIRQMSKA ]                 ; IRQ Mask register
        TEQP    psr, #( IFlag + SVC_mode )              ; Enable FIQ
	NOP						; Next instruction uses wp hence it's mode dependent
        LD      r0, PeekPokeFlag                        ; First look for a peek or a poke memory check
        TEQ     r0, #0                                  ; Are we down grading a peek or a poke?
        BEQ     InterruptImmediate
        [       DebugIRQ
        LDR     r2, =Border_Grey
        ADR     r3, VIDC
        STR     r2, [ r3, #0 ]
        ]
        MOV     r3, #0
        ST      r3, PeekPokeFlag                        ; Clear the flag
        ADR     r2, ScoutBuffer + 4                     ; Here lies the start and end address+1
        LDMIA   r2, { r0, r1 }
        SWI     XOS_ValidateAddress
        [       PoduleCapable
        LDR     r1, HardwareAddress
        |
        LDR     r1, =EconetController                   ; Get the address of our chip
        ]
        BVS     DontAllowPeekOrPoke
        BCS     DontAllowPeekOrPoke
        MOV     r0, #2_11100111                         ; RTS, CLRTxST, CLRRxST, FlagIdle, 2Byte, PSE
        STRB    r0, [ r1, #:INDEX:CReg2 ]
        MOV     r0, #2_01000100                         ; RxRS, TxIE ; Start the transmitter interrupting
        STRB    r0, [ r1, #:INDEX:CReg1 ]
        B       InterruptLoop

DontAllowPeekOrPoke
        ; This code is similar to the sequence in the ReInit routine
        ; but it is executed in SVC mode and doesn't exit with RTFIQ
        ; Violently re-initialise things, take no chances
        MOV     r0, #2_11000001                         ; TxReset, RxReset, AC=1
        STRB    r0, [ r1, #:INDEX:CReg1 ]
        MOV     r0, #2_00011110                         ; NRZ, Rx8bits, Tx8bits
        STRB    r0, [ r1, #:INDEX:CReg4 ]
        MOV     r0, #2_00000000                         ; DTR, NONLOOP
        ST      r0, FIQBusy                             ; Show that FIQ is not busy, by storing a zero
        STRB    r0, [ r1, #:INDEX:CReg3 ]
        MOV     r0, #2_10000010                         ; TxReset, RxIE, AC=0
        STRB    r0, [ r1, #:INDEX:CReg1 ]
        MOV     r0, #2_01100111                         ; ClrTxStatus, ClrRxStatus, FlagIdle, 2Byte, PSE
        STRB    r0, [ r1, #:INDEX:CReg2 ]
        SetFIQ  StartReception, r0, r1, Long, Init, r2
        B       InterruptLoop

InterruptImmediate                                      ; Then look for an immediate operation
        LD      r0, LockOut                             ; Get the lockout state
        TEQ     r0, #0
        BEQ     InterruptTxOrRx                         ; No immediate operation outstanding
        [       DebugIRQ
        LDR     r2, =Border_Beige
        ADR     r1, VIDC
        STR     r2, [ r1, #0 ]
        ]
        LDRB    r0, ImmediateRecord + Offset_Control
        ADRL    r1, ArgumentsSize
        LD      r2, ArgumentsAddressOrNumber            ; Procedure number or Call address
        LDRB    r3, ImmediateRecord + Offset_Station
        LDRB    r4, ImmediateRecord + Offset_Network
        TEQ     r0, #BitSeven + Econet_JSR
        BEQ     DoJSR
        ASL     r2, 16
        ASR     r2, 16                                  ; Clear the top 16 bits of the procedure number
        TEQ     r0, #BitSeven + Econet_UserProcedureCall
        MOVEQ   r0, #Event_Econet_UserRPC
        MOVNE   r0, #Event_Econet_OSProc
        [       False ; Debug
        DREG    r0, "XOS_GenerateEvent called, R0 = &", cc
        DREG    r1, ", R1 = &", cc
        DREG    r1, ", R2 = &", cc
        DREG    r1, ", R3 = &", cc
        DREG    r1, ", R4 = &"
        ]
        SWI     XOS_GenerateEvent
CancelLockOut
        MOV     r1, #0
        ST      r1, LockOut                             ; Clear the lockout state
        B       InterruptLoop                           ; Start again

DoJSR
        CMP     r2, #-1                                 ; If the call address is -1 then call the buffer
        ADDEQ   r2, r1, #4
        ADR     lr, CancelLockOut
        MOV     pc, r2

InterruptTxOrRx                                         ; Scan both the Tx and Rx lists looking for
                                                        ; the oldest outstanding CB that needs eventing
        ; R0 => Event number to use
        ; R1 => Pointer to the CB to do
        ; R2 => Event sequence number
        [       DebugIRQ
        LDR     r2, =Border_Blue
        ADR     r1, VIDC
        STR     r2, [ r1, #0 ]
        ]
        MOV     r1, #0
        MOV     r2, #Event_NotReady

        ADR     r14, TxCBList - Offset_Link
InterruptTxLoop
        LDR     r14, [ r14, #Offset_Link ]
        TEQ     r14, #NIL                               ; Check for an empty list
        BEQ     InterruptRx
        LDR     r3, [ r14, #Offset_Event ]
        CMP     r3, r2
        MOVLO   r1, r14                                 ; Ready to be evented
        MOVLO   r0, #Event_Econet_Tx
        MOVLO   r2, r3                                  ; The number of the lowest encountered so far
        B       InterruptTxLoop

InterruptRx
        ADR     r14, RxCBList - Offset_Link
InterruptRxLoop
        LDR     r14, [ r14, #Offset_Link ]
        TEQ     r14, #NIL                               ; Check for an empty list
        BEQ     CheckForEvent
        LDR     r3, [ r14, #Offset_Event ]
        CMP     r3, r2
        MOVLO   r1, r14                                 ; Ready to be evented
        MOVLO   r0, #Event_Econet_Rx
        MOVLO   r2, r3                                  ; The number of the lowest encountered so far
        B       InterruptRxLoop

CheckForEvent
        MOVS    r14, r1                                 ; Possible CB pointer
        BEQ     InterruptFinished                       ; No CBs outstanding so start again
        [       DebugIRQ
        LDR     r2, =Border_White
        ADR     r3, VIDC
        STR     r2, [ r3, #0 ]
        ]
        MOV     r1, #Event_Done                         ; Event processed
        STR     r1, [ r14, #Offset_Event ]
        LDR     r1, [ r14, #Offset_Handle ]
        LDRB    r2, [ r14, #Offset_Status ]
        LDRB    r3, [ r14, #Offset_Port ]
        [       False ; Debug
        DREG    r0, "XOS_GenerateEvent called, R0 = &", cc
        DREG    r1, ", R1 = &", cc
        DREG    r2, ", R2 = &", cc
        DREG    r3, ", R3 = &", cc
        DREG    r4, ", R4 = &"
        ]
        SWI     XOS_GenerateEvent
        B       InterruptLoop                           ; Start again

InterruptFinished
        [       DebugIRQ
        LDR     r2, =Border_Yellow
        ADR     r3, VIDC
        STR     r2, [ r3, #0 ]
        ]
        Pull    "r0-r4, lr"                             ; Off supervisor stack
        TEQP    psr, #IFlag + IRQ_mode                  ; Return to original mode
        NOP
        Pull    "lr, pc"                                ; Off IRQ stack

        ALIGN   $Alignment
Event           ROUT
        ;       This is the stuff that actually handles to OSRPCs
        ;       This code will be entered in SWI mode because I called it from SWI mode
        ;       so there is no need to go to SWI mode to preserve R14 in SWIs
        TEQ     r0, #Event_Econet_OSProc
        MOVNES  pc, lr
        TEQ     r2, #Econet_OSCharacterFromNotify       ; Bottom byte of RPC number is what to do
        BEQ     InsertCharacter
        TEQ     r2, #Econet_OSCauseFatalError
        BEQ     CauseFatalError
        MOV     r0, #Event_Econet_OSProc
        BICS    pc, lr, #VFlag

InsertCharacter
        [       False ; Debug
        DREG    r0, "InsertCharacter called, R0 = &", cc
        DREG    r1, ", R1 = &", cc
        DREG    r2, ", R2 = &", cc
        DREG    r3, ", R3 = &", cc
        DREG    r4, ", R4 = &"
        ]
        MOV     r0, #138
        LDRB    r2, [ r1, #4 ]                          ; Pick up the character from the buffer
        MOV     r1, #0
        MOV     r3, lr
        SWI     XOS_Byte
        MOV     pc, r3

CauseFatalError
        MOV     r1, #0
        ST      r1, LockOut                             ; Clear the lockout state
        ADR     r0, ErrorRemoted
        [       UseMsgTrans
        ADR     lr, ExecuteFatalError
        B       MakeError
ExecuteFatalError
        SWI     OS_GenerateError

ErrorRemoted
        DCD     ErrorNumber_Remoted
        DCB     "Remoted", 0
        ALIGN
        |
        SWI     OS_GenerateError

        Err     Remoted
        ]

        LTORG

        OPT     OptPage
        ALIGN   $Alignment
Pacemaker       ROUT
        ;       Entered from the Ticker vector
        ;       And wp has the expected value, and doesn't need to be preserved
        ;       We will be in either IRQ or SVC mode with a valid stack
        Push    "r6, r7, lr"                            ; Note use of Non FIQ registers
        LD      r6, Time                                ; Also saves the IRQ state, which isn't assumed
        INC     r6
        ST      r6, Time
        LD      r7, FIQStatus
        TEQ     r7, #FIQ_PoweredDown                    ; Is it OK to do anything?
        Pull    "r6, r7, pc", EQ                        ; No we aren't even alive
        Push    "r2-r5"
        MOV     r5, psr                                 ; Save mode in r5, should be IRQ might just be SVC
        LD      r7, TxCBList                            ; Now check the transmit queue to see what needs restarting
        B       %30

CheckTxList
        LDRB    r14, [ r7, #Offset_Status ]
        TEQ     r14, #Status_TxReady
        BNE     %20
        LDR     r14, [ r7, #Offset_Time ]
        CMP     r6, r14
        BPL     RestartRecord
20
        LDR     r7, [ r7, #Offset_Link ]
30
        TEQ     r7, #NIL
        BNE     CheckTxList
        [       PerthPowerDown
        ;       Now check if it is Power Down time yet
        LDR     r7, PowerDownTime
        CMP     r7, r6
        BGT     NoPowerDownYet                          ; Not time yet
        LDR     r7, TxCBList
40
        TEQ     r7, #NIL
        BEQ     %50                                     ; No TxCBs, check for RxCBs
        LDRB    r14, [ r7, #Offset_Status ]
        TEQ     r14, #Status_TxReady
        TEQNE   r14, #Status_Transmitting               ; If they are active then
        BEQ     %60                                     ; Nothing we can do here
        LDR     r7, [ r7, #Offset_Link ]
        B       %40

50
        LDR     r7, RxCBList
        TEQ     r7, #NIL
        BEQ     %70                                     ; Its OK, so lets do it
        TEQP    psr, #( IFlag + SVC_mode )              ; Goto SVC
        MOV     r2, #ServicePortable_TidyUp             ; Lets beg for it (non-mode dependent register)
        Push    "r1, lr"                                ; This may cause SWIs, which will change PowerDownTime
        MOV     r1, #Service_Portable
        SWI     XOS_ServiceCall
        Pull    "r1, lr"
        TEQP    psr, r5                                 ; Restore mode and interrupt state
        LDR     r7, RxCBList
        TEQ     r7, #NIL
60
        ADDNE   r7, r6, #PowerDownTimeout               ; Calculate time to try again
        STRNE   r7, PowerDownTime
        Pull    "r2-r7, pc", NE                         ; Still got things to do
70
        [       DebugPowerDown
        LDR     r7, =Border_Magenta
        ADR     r14, VIDC
        STR     r7, [ r14, #0 ]
        ]
        TEQP    psr, #( IFlag + SVC_mode )              ; Goto SVC
        NOP
        [       UsePortableModule
        Push    "r0, r1, lr"                            ; On supervisor stack
        MOV     r0, #0                                  ; Turn it off
        MVN     r1, #PortableControl_EconetEnable
        SWI     XPortable_Control
        Pull    "r0, r1, lr"
        |
        Push    "r1-r3, lr"                             ; On supervisor stack
        MOV     r1, #Service_Portable
        MOV     r2, #ServicePortable_PowerDown
        MOV     r3, #PortableControl_EconetEnable
        SWI     XOS_ServiceCall
        Pull    "r1-r3, lr"
        ]
        TEQP    psr, r5                                 ; Restore mode and interrupt state
        NOP
NoPowerDownYet
        ]
        [       ReceiveInBackground
        LD      r2, BridgeRxHandle
        TEQ     r2, #0
        BEQ     %90                                     ; Bridge handle already abandoned
        CMP     r6, #BridgeWaitTime
        BLS     %90                                     ; Not time to abandon yet, unsigned CMP
        TEQP    psr, #SVC_mode                          ; Goto SVC, needed to call AbandonAndReadReceive
        NOP
        Push    "r0, r1, r5, r10, r11, lr"
        MOV     r0, #0
        ST      r0, BridgeRxHandle
        ADDS    r0, r0, r2                              ; MOV r0, r2, clearing V: R2 is the handle to abandon
        BL      AbandonAndReadReceive                   ; Ignore errors returned
        [       DebugFindLocalNet
        BVS     %97
        TEQ     r0, #Status_Received
        LDRNE   r0, =Border_Grey
        LDREQ   r0, =Border_Brown
        ADR     r1, VIDC
        STR     r0, [ r1, #0 ]
97
        ]
        Pull    "r0, r1, r5, r10, r11, lr"
        TEQP    psr, r5                                 ; Restore mode and interrupt state
        NOP
90
        ]
ExitPacemaker
        Pull    "r2-r7, pc"

RestartRecord   ROUT                                    ; Called from StartTransmit and TickerV
        ;       R5 => Mode and flags to restore at the end
        ;       R6 => Time
        ;       R7 => Pointer to the record
        ;       SP => Has r2-r7, and the return address already pushed
        LD      r4, FIQStatus                           ; Test again because of being jumped to
        TEQ     r4, #FIQ_Owner                          ; Is it OK to do anything?
        BNE     ExitRestartRecord
        LDRB    r2, [ r7, #Offset_Station ]
        LD      r4, LocalStation                        ; Is it the same station number?
        TEQ     r2, r4                                  ; If it is then check the network number as well
        LDREQB  r2, [ r7, #Offset_Network ]
        TEQEQ   r2, #0                                  ; Is it this network?
        LDRNEB  r2, [ r7, #Offset_Broadcast ]
        TEQNE   r2, #0
        BNE     SendToWire                              ; Not for local loopback
        LDRB    r2, [ r7, #Offset_Port ]
        TEQ     r2, #0                                  ; Is this an immediate operation?
        LDRNEB  r2, [ r7, #Offset_Local ]               ; Have we already done this?
        TEQNE   r2, #0
        BEQ     SendToWire                              ; Yes, so "No way Hose!"
        LDR     r2, RxCBList                            ; Now compare the TxRecord with the RxList
ScanRxLoop
        TEQ     r2, #NIL
        BEQ     LocalNotListening
        LDRB    r3, [ r2, #Offset_Status ]
        TEQ     r3, #Status_RxReady
        BNE     SkipToNextRx                            ; Not ready, so it can't be this one
        LDRB    r3, [ r2, #Offset_RxPort ]
        TEQ     r3, #255
        LDRNEB  r4, [ r7, #Offset_Port ]                ; The transmission port
        TEQNE   r3, r4
        BNE     SkipToNextRx                            ; No port match or no wild reception port
        LDRB    r3, [ r2, #Offset_RxStation ]
        TEQ     r3, #255
        LD      r4, LocalStation, NE
        TEQNE   r3, r4
        BNE     SkipToNextRx                            ; No station match or no wild reception station
        LDRB    r3, [ r2, #Offset_RxNetwork ]
        TEQ     r3, #255
        TEQNE   r3, #0
        BNE     SkipToNextRx                            ; No network match or no wild reception network
        ; Now check that there is room for the transfer to take place
        LDR     r3, [ r2, #Offset_Size ]
        LDR     r4, [ r7, #Offset_Size ]
        CMP     r3, r4                                  ; Check the two buffer sizes
        MOVLT   r4, #Status_NetError
        BLT     LocalNetError                           ; No, not enough room
        Push    "r0, r1"
        [       DebugIRQ
        LDR     r0, =Border_Lime
        ADR     r1, VIDC
        STR     r0, [ r1, #0 ]
        ]
        LDR     r0, [ r2, #Offset_Start ]
        LDR     r1, [ r7, #Offset_Start ]
LocalCopyLoop
        LDRB    r3, [ r1 ], #1
        STRB    r3, [ r0 ], #1
        DECS    r4
        BNE     LocalCopyLoop
        Pull    "r0, r1"
        LDRB    r4, [ r7, #Offset_Station ]
        LDR     r4, [ r7, #Offset_Size ]
        STR     r4, [ r2, #Offset_RxSize ]
        LD      r4, LocalStation
        STRB    r4, [ r2, #Offset_Station ]
        MOV     r4, #0
        STRB    r4, [ r2, #Offset_Network ]
        LDRB    r4, [ r7, #Offset_Port ]
        STRB    r4, [ r2, #Offset_Port ]
        LDRB    r4, [ r7, #Offset_Control ]
        STRB    r4, [ r2, #Offset_Control ]
        MOV     r4, #Status_Received                    ; Mark the reception as completed
        STRB    r4, [ r2, #Offset_Status ]
        MOV     r4, psr                                 ; Save interrupt state
        TEQP    psr, #( FFlag + IFlag + SVC_mode )      ; Disable all interrupts
        NOP                                             ; Note; WP *IS* a mode dependent register
        LD      r3, EventSequenceNumber
        INC     r3                                      ; Get an event number
        ST      r3, EventSequenceNumber
        TEQP    psr, r4                                 ; Restore interrupts and mode
        NOP
        LDRB    r4, [ r7, #Offset_Broadcast ]
        TEQ     r4, #0                                  ; Is this a broadcast?
        MOVNE   r4, #Status_Transmitted                 ; Mark a normal transmit as completed
        STRNEB  r4, [ r7, #Offset_Status ]
        STRNE   r3, [ r7, #Offset_Event ]               ; Transmit event
        MOVNE   r7, r2                                  ; The RxCB
        BNE     DoEventAndExit                          ; And exit marking the RxCB for eventing
        STRB    r4, [ r7, #Offset_Local ]               ; Mark that we have done a local reception (0)
        STR     r3, [ r2, #Offset_Event ]               ; Receive event, will be triggered with the Tx
        B       SendToWire                              ; Now send the broadcast out on the wire as well

SkipToNextRx
        LDR     r2, [ r2, #Offset_Link ]
        B       ScanRxLoop                              ; Check the next RxRecord

LocalNotListening                                       ; No match on any RxCB
        MOV     r4, #Status_NotListening
LocalNetError
        LDRB    r2, [ r7, #Offset_Broadcast ]
        TEQ     r2, #0                                  ; If its a broadcast, send it out
        BEQ     SendToWire
        LDR     r2, [ r7, #Offset_Count ]
        DECS    r2
        STRLEB  r2, [ r7, #Offset_Status ]              ; Write the status if this was the last one
        BLE     DoEventAndExit                          ; Transmit is now complete
        STR     r2, [ r7, #Offset_Count ]
        LDR     r4, [ r7, #Offset_Delay ]
        LDR     r2, [ r7, #Offset_Time ]
        ADD     r2, r2, r4                              ; Compute next start time
        STR     r2, [ r7, #Offset_Time ]
        ;       Note that there is no need to adjust the ClaimTime
        B       ExitRestartRecord

SendToWire
    [   False    ;       ****************  Bodge  ****************
    !   0, " ****  Bodge code assembled in SendToWire ****"
        Push    r10
        [       PoduleCapable
        LDR     r10, HardwareAddress
        |
        LDR     r10, =EconetController
        ]
        LDRB    r10, SReg2
        ST      r10, Status2
        Pull    r10
    ]
        LD      r4, Status2
        TST     r4, #DCD
        MOVNE   r4, #Status_NoClock
        STRNEB  r4, [ r7, #Offset_Status ]
        BNE     DoEventAndExit                          ; No mode change yet
        TEQP    psr, #( FFlag + IFlag + FIQ_mode )      ; Goto FIQ mode, disable all interrupts
        NOP                                             ; Note; WP *IS* a mode dependent register
        LD      r4, FIQBusy                             ; Get the FIQBusy flag
        TEQ     r4, #0                                  ; Test it
        BNE     ExitRestartRecord
        ST      r7, Record                              ; Save the address of the transmit control block
      [ StrongARM
	MOV	r4, #3
        ST      r4, FIQBusy				; Can't STRB PC in ARMv4
      |
        ST      pc, FIQBusy                             ; Set the FIQ flag <> 0 (Mode = SVC)
      ]
        LDRB    r4, [ r7, #Offset_Station ]             ; Now set up the TxMode flags
        EORS    r4, r4, #255                            ; Z if it is 255 ==> broadcast
        ORREQ   r4, r4, #BroadcastBit
        BEQ     StoreModeWord
        LDRB    r9, [ r7, #Offset_Port ]
        TEQ     r9, #0
        BNE     StoreModeWord
        LDRB    r9, [ r7, #Offset_Control ]             ; This has bit seven set
        ADR     r13, ImmediateModeBits - ( BitSeven + Econet_Peek )
        LDRB    r9, [ r13, r9 ]
        ORR     r4, r4, r9, LSL #24
StoreModeWord
        ST      r4, TxMode
        LD      r13, SReg2                              ; Note R10 is always the address of the ADLC
        TST     r13, #RxIdle                            ; Now the line access stuff
        BEQ     NoLineAccess                            ; Line not idle
        TST     r13, #RxAbort
        BNE     NoLineAccess
        MOV     r13, #Status_Transmitting               ; Now mark the record as Transmitting
        STRB    r13, [ r7, #Offset_Status ]             ; Now we can start to prod the chip into action
        MOV     r13, #2_11100111                        ; RTS, CLRTxST, CLRRxST, FlagIdle, 2Byte, PSE
        ST      r13, CReg2
        MOV     r13, #2_01000100                        ; RxRS, TxIE
        ST      r13, CReg1
        [       Debug
        LDR     r8, =Border_Green                       ; Access to wire
        ADR     r9, VIDC
        STR     r8, [ r9, #0 ]
        ]
        SetFIQ  TxFromMe, r8, r9, Long, Init, r13
        SetJump TxControlAndPort, r8, r9, Long
ExitRestartRecord
        TEQP    psr, r5                                 ; Return to correct mode, and interrupt state
        NOP                                             ; Restores NZCVIF and the mode bits
        Pull    "r2-r7, pc"

ImmediateModeBits ; Stored as bytes to be put in the top bits
        DCB     2_00011010                              ; Peek
        DCB     2_00011000                              ; Poke
        DCB     2_00010000                              ; JSR
        DCB     2_00010000                              ; UserProcedureCall
        DCB     2_00010000                              ; OSProcedureCall
        DCB     2_00010101                              ; Halt
        DCB     2_00010101                              ; Continue
        DCB     2_00010010                              ; MachinePeek
        DCB     2_00010110                              ; GetRegisters
        ALIGN

NoLineAccess                                            ; Line jammed ??
        LDR     r8, [ r7, #Offset_ClaimTime ]
        CMP     r8, r6                                  ; Has the claim time expired ??
        ST      r13, Status2, MI                        ; Retain for later examination
        MOVPL   r6, #Status_TxReady                     ; Still keep trying
        MOVMI   r6, #Status_LineJammed                  ; Give up
        STRB    r6, [ r7, #Offset_Status ]
        MOV     r6, #0
        ST      r6, FIQBusy                             ; Must clear this since it is NOT busy no more
        BPL     ExitRestartRecord
        ;       Last time so must flag the event
DoEventAndExit
        ;       R7 <= Pointer to CB to event
        ;       Trashes R3 and R4
        MOV     r4, psr                                 ; Save interrupt state
        TEQP    psr, #( FFlag + IFlag + SVC_mode )      ; Disable all interrupts
        NOP                                             ; Note; WP *IS* a mode dependent register
        LD      r3, EventSequenceNumber
        INC     r3
        ST      r3, EventSequenceNumber
        TEQP    psr, r4                                 ; Restore interrupts and mode
        NOP
        STR     r3, [ r7, #Offset_Event ]
        ADR     r4, IOC
        LDRB    r3, [ r4, #IOCIRQMSKA ]                 ; IRQ Mask register
        ORR     r3, r3, #force_bit
        STRB    r3, [ r4, #IOCIRQMSKA ]                 ; IRQ Mask register
        B       ExitRestartRecord

        LTORG

        END