; 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    Transmit routines. => &.Arthur.Econet.Transmit
        OPT     OptPage

        ALIGN   $Alignment
TxFromMe        ROUT                                    ; Send out the destination Address
        [       Debug
        LDR     r13, =Border_Cyan
        ADR     r11, VIDC
        STR     r13, [ r11, #0 ]
        ]
        LD      r13, SReg1
        TSTS    r13, #TxDRA                             ; TDRA OK ?
        MakeNetError1 EQ
        LD      r11, Record                             ; R11 points to the active record
        LDRB    r13, [ r11, #Offset_Station ]           ; Station number
        ST      r13, TxByte
        LDRB    r13, [ r11, #Offset_Network ]           ; Net number
        ST      r13, TxByte
        WaitForFIQ r11, r13
        LD      r13, SReg1
        TSTS    r13, #TxDRA                             ; TDRA OK ?
        MakeNetError1 EQ
        LD      r13, LocalStation
        ST      r13, TxByte
        MOV     r13, #0                                 ; Local network must be zero
        ST      r13, TxByte
        PutFIQ  r11, r13                                ; Go back to "calling" routine
        LD      r11, Record
        RTFIQ                                           ; Note the exit condition => r11 (txRec/rxRec) contains Pointer

        ALIGN   $Alignment
TxControlAndPort ROUT                                   ; Send out the flag and port bytes
        LD      r13, SReg1
        TSTS    r13, #TxDRA                             ; TDRA OK ?
        MakeNetError1 EQ
        LDRB    r13, [ r11, #Offset_Control ]
        ST      r13, TxByte
        LDRB    r13, [ r11, #Offset_Port ]
        ST      r13, TxByte
        LD      r13, TxMode
        TST     r13, #BroadcastBit
        BNE     BroadcastData                           ; It IS a broadcast so, now send out the data
        TST     r13, #ImmediateBit
        BEQ     FinishScout                             ; Ordinary case
ImmediateScout
        TST     r13, #ShortBit
        BNE     FinishScout
        WaitForFIQ r8, r9
        LD      r13, SReg1
        TSTS    r13, #TxDRA                             ; TDRA OK ?
        MakeNetError1 EQ
        LDR     r13, [ r11, #Offset_Destination ]
        ST      r13, TxByte                             ; Lo byte
        ASR     r13, 8
        ST      r13, TxByte                             ; MidLo byte
        WaitForFIQ r8, r9
        LD      r13, SReg1
        TSTS    r13, #TxDRA                             ; TDRA OK ?
        MakeNetError1 EQ
        LDR     r13, [ r11, #Offset_Destination ]
        ASR     r13, 16
        ST      r13, TxByte                             ; MidHi byte
        ASR     r13, 8
        ST      r13, TxByte                             ; Hi byte
        LD      r13, TxMode
        TST     r13, #LongBit
        BEQ     FinishScout
        WaitForFIQ r8, r9
        LD      r13, SReg1
        TSTS    r13, #TxDRA                             ; TDRA OK ?
        MakeNetError1 EQ
        LDR     r13, [ r11, #Offset_Destination ]
        LDR     r9, [ r11, #Offset_Size ]
        ADD     r13, r13, r9                            ; The end address
        ST      r13, TxByte                             ; Lo byte
        ASR     r13, 8
        ST      r13, TxByte                             ; MidLo byte
        WaitForFIQ r8, r9
        LD      r13, SReg1
        TSTS    r13, #TxDRA                             ; TDRA OK ?
        MakeNetError1 EQ
        LDR     r13, [ r11, #Offset_Destination ]
        LDR     r9, [ r11, #Offset_Size ]
        ADD     r13, r13, r9                            ; The end address
        ASR     r13, 16
        ST      r13, TxByte                             ; MidHi byte
        ASR     r13, 8
        ST      r13, TxByte                             ; Hi byte
FinishScout
        LDR     r13, =2_00111111                        ; -RTS, ClrRxST, TxLast, FC, FlagIdle, 2Byte, PSE
        ST      r13, CReg2
        LDR     r13, =2_00000100                        ; TxIE, Enable the receiver section
        ST      r13, CReg1
        WaitForFIQ r8, r9
        LD      r13, SReg1
        TSTS    r13, #FrameComplete
        MakeNetError1 EQ
        LDR     r13, =2_10000010                        ; TxRS, RxIE
        ST      r13, CReg1
        WaitForFIQ r8, r9
        LD      r13, SReg2
        ST      r13, Status2
        TSTS    r13, #AddressPresent                    ; This is the begining of the ScoutAck
        MOVEQ   r9, #Status_NotListening
        BEQ     DecrementCountAndWriteStatus            ; Every other failure is NetError except this one
        LD      r13, RxByte
        LD      r9, LocalStation
        TEQ     r13, r9                                 ; Is it well-formed?
        MakeNetError NE
        WaitForFIQ r8, r9                               ; Needed because Address Present forces single byte mode
        LD      r13, SReg2
        TSTS    r13, #RxDA
        MakeNetError2 EQ
        LD      r13, RxByte
        TEQ     r13, #0                                 ; Local network must be zero
        MakeNetError NE
        WaitForFIQ r8, r9
        LD      r13, SReg2
        TSTS    r13, #RxDA
        MakeNetError2 EQ
        LD      r13, RxByte
        LDRB    r9, [ r11, #Offset_Station ]
        TEQ     r13, r9                                 ; Is it from the right station?
        LDREQB  r13, RxByte
        LDREQB  r9, [ r11, #Offset_Network ]
        TEQEQ   r13, r9                                 ; On the right network?
        MakeNetError NE
        LD      r13, TxMode
        TST     r13, #PeekBit
        BNE     ReadyToPeekData                         ; Yes, it is a Peek
        TST     r13, #TwoWayBit
        BNE     EndOfFinalAck
        LD      r13, SReg2
        TSTS    r13, #FrameValid
        MakeNetError2 EQ
        LDR     r13, =2_11100111                        ; RTS, CLRTxST, CLRRxST, FlagIdle, 2Byte, PSE
        ST      r13, CReg2                              ; Turn the line around
        LDR     r13, =2_01000100                        ; RxRS, TxIE
        ST      r13, CReg1
        TurnAroundDelay r8, r9, r13
IgnoreCTS
        LD      r13, SReg1
        [       False                                   ; Fix2441   **************************************
        TSTS    r13, #CTS                               ; Is there a CTS status that we should ignore?
        BNE     IgnoreCTS
        ]
        TSTS    r13, #TxDRA                             ; TDRA OK ?
        MakeNetError1 EQ
        SetFIQ  TxFromMe, r8, r9
        SetJump TxStartData, r8, r9
        RTFIQ

BroadcastData   ROUT                                    ; Come here after sending out the Port and Control
        SetFIQ  TxStartData, r8, r9
        RTFIQ

        ALIGN   $Alignment
ReadyToPeekData
        SetFIQ  PeekData, r8, r9
        ADD     r9, r11, #Offset_Start
        LDMIA   r9, { r8, r9 }
        RTFIQ

        ALIGN   $Alignment
PeekData        ROUT
        LD      r13, SReg2
        TST     r13, #RxDA
        BEQ     WasThatTheEndOfPeek
        LD      r13, RxByte
        STRB    r13, [ r8 ], #1
        DECS    r9
        MakeNetError EQ
        LD      r13, SReg2
        TST     r13, #RxDA
        BNE     %01                                     ; Data is definately available
        TEQ     r13, #0
        BNE     WasThatTheEndOfPeek
01
        LD      r13, RxByte
        STRB    r13, [ r8 ], #1
        DECS    r9
        MakeNetError EQ
        RTFIQ                                           ; Will return to PeekData

WasThatTheEndOfPeek
        TSTS    r13, #FrameValid
        MakeNetError2 EQ
        LD      r13, RxByte
        STRB    r13, [ r8 ]
        MOV     r9, #Status_Transmitted
        B       WriteStatusAndReset

        ALIGN   $Alignment
TxStartData
        LD      r13, SReg1
        TSTS    r13, #TxDRA                             ; TDRA OK ?
        MakeNetError1 EQ
        SetFIQ  TxData, r8, r9                          ; Set up for the transfer routine

        ADD     r8, r11, #Offset_Start
        LDMIA   r8, { r8, r9 }                          ; Get the address and length of the data to send
        TEQ     r9, #0                                  ; Zero length transmit ??
        B       DoTxByte

        ALIGN   $Alignment
TxData                                                  ; The data transfer routine itself
        LD      r13, SReg1
        TSTS    r13, #TxDRA                             ; TDRA OK ?
        MakeNetError1 EQ
        LDRB    r13, [ r8 ], #1
        ST      r13, TxByte
        DECS    r9
DoTxByte
        BEQ     EndOfTx
        LDRB    r13, [ r8 ], #1
        ST      r13, TxByte
        DECS    r9
        BEQ     EndOfTx
        RTFIQ                                           ; Will return to TxData

EndOfTx
        LDRB    r13, =2_00111111                        ; -RTS, ClrRxST, TxLast, FC, FlagIdle, 2Byte, PSE
        STRB    r13, CReg2
        LDRB    r13, =2_00000100                        ; TxIE, Enable the receiver section
        STRB    r13, CReg1
WaitForFrameCompletion
        LD      r13, SReg1
        TSTS    r13, #INT
        BEQ     WaitForFrameCompletion
        TSTS    r13, #FrameComplete
        MakeNetError1 EQ
        LDR     r13, =2_10000010                        ; TxRS, RxIE
        STRB    r13, CReg1
        LD      r13, TxMode
        TST     r13, #BroadcastBit
        MOVNE   r9, #Status_Transmitted
        BNE     WriteStatusAndReset                     ; End of broadcast
        WaitForFIQ r8, r9
        LD      r13, SReg2
        TSTS    r13, #AddressPresent                    ; This should be the FinalAck
        BNE     %05                                     ; It may be the special case of a small idle from a BBC machine
        TSTS    r13, #RxIdle
        BEQ     %04                                     ; Anything but is an error
        MOV     r13, #2_01100111                        ; ClearRxStatus, ClearTxStatus, etc.
        STRB    r13, CReg2
        MOV     r9, #200                                ; Magic empirical number
03
        LD      r13, SReg2
        TSTS    r13, #AddressPresent
        BNE     %05                                     ; It may be the special case of a small idle from a BBC machine
        DECS    r9
        BNE     %03
04
        MakeNetError2
05
        LD      r13, RxByte
        LD      r9, LocalStation
        TEQ     r13, r9
        MakeNetError NE
        WaitForFIQ r8, r9                               ; Needed because AddressPresent forces single byte mode
        LD      r13, SReg2
        TSTS    r13, #RxDA
        MakeNetError2 EQ
        LD      r13, RxByte
        TEQ     r13, #0                                 ; Local network must be zero
        MakeNetError NE
        WaitForFIQ r8, r9
        LD      r13, SReg2
        TSTS    r13, #RxDA
        MakeNetError2 EQ
        LDR     r11, Record
        LD      r13, RxByte
        LDRB    r8, [ r11, #Offset_Station ]
        TEQ     r13, r8
        LDREQB  r13, RxByte
        LDREQB  r8, [ r11, #Offset_Network ]
        TEQEQ   r13, r8
        MakeNetError NE
EndOfFinalAck
        LD      r13, SReg2
        TSTS    r13, #FrameValid
        MakeNetError2 EQ
        MOV     r9, #Status_Transmitted
        B       WriteStatusAndReset

NetErrorWithSReg1                                       ; Status Register 1 in R13
        [       Debug
        LDR     r11, NetErrorListPointer
        STRB    r13, [ r11, #0 ]                        ; SReg 1 at offset 0
        ]
        TST     r13, #SReg2Req
        BEQ     NetError
        LD      r13, SReg2
NetErrorWithSReg2                                       ; Status Register 2 in R13
        [       Debug
        LDR     r11, NetErrorListPointer
        STRB    r13, [ r11, #1 ]                        ; SReg 2 at offset 1
        ]
        ST      r13, Status2
NetError                                                ; No status registers
        [       Debug
        LDR     r11, NetErrorListPointer
        STR     r8, [ r11, #4 ]                         ; The PC where it happened
        LD      r8, Time
        STR     r8, [ r11, #8 ]                         ; The time it happened
        ]
        LD      r8, Record
        TEQ     r8, #NIL                                ; Is there a valid record (ie is this an Immediate Op)?
        BEQ     Reset
        [       Debug
        LDR     r13, [ r8, #Offset_Handle ]
        STR     r13, [ r11, #12 ]                       ; To whom it happened
        LDRB    r13, [ r8, #Offset_Station ]
        STRB    r13, [ r11, #2 ]
        LDRB    r13, [ r8, #Offset_Network ]
        STRB    r13, [ r11, #3 ]
        MOV     r13, #-1                                ; Initialise the next record
        STR     r13, [ r11, #16 ] !
        STR     r13, [ r11, #12 ]
        STR     r11, NetErrorListPointer                ; Store the pointer for next time
        ]
        LDR     r11, [ r8, #Offset_Identifier ]
        LDR     r13, =RxCBIdentifier
        TEQ     r11, r13                                ; Check if it is an Rx record
        BEQ     TransmissionErrorDuringReceive          ; Yes, deal with it as an Rx record
        MOV     r9, #Status_NetError
DecrementCountAndWriteStatus                            ; R9 is the status
        LD      r8, Record
        LDR     r13, [ r8, #Offset_Count ]
        DECS    r13
        BLE     WriteStatusAndReset                     ; That was the last retry
        STR     r13, [ r8, #Offset_Count ]
        LDR     r13, [ r8, #Offset_Delay ]
        LDR     r11, [ r8, #Offset_Time ]
        ADD     r11, r11, r13                           ; Compute next start time
        STR     r11, [ r8, #Offset_Time ]
        ADD     r11, r11, #ClaimTime                    ; Compute next LineJammed time
        STR     r11, [ r8, #Offset_ClaimTime ] 
        MOV     r9, #Status_TxReady                     ; Ready to restart
WriteStatusAndReset
        LDR     r11, Record
        STRB    r9, [ r11, #Offset_Status ]
        MOV     r8, #NIL                                ; NIL the record pointer
        STR     r8, Record
        TEQ     r9, #Status_TxReady
        BEQ     Reset
        B       CauseEventAndReset                      ; Give an interrupt if it completes

        LTORG

FindLocalNetwork ROUT
        ;       Called in SVC mode and remains in SVC mode
        ;       Disables IRQs but preserves the IRQ state
        ;  In   None
        ;  Out  R0 will have the error pointer if V is set
        ;       All other registers preserved
        ;       Possible errors:
        ;         No Clock

        END