; 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 Receive routines. => &.Arthur.Econet.Receive
OPT OptPage
ALIGN $Alignment
StartReception ROUT
LD r13, SReg1
TST r13, #SReg2Req
BEQ FrameDiscontinue
LD r13, SReg2
ST r13, Status2
TST r13, #AddressPresent
BEQ Reset ; No, so give up and start again
LD r9, RxByte ; Get the first byte, keep in R9 for later
LD r13, LocalStation ; Get our station number
TEQ r9, r13
BNE %30 ; It might be a broadcast
SetFIQ CheckNetOfScout, r11, r13
B %40
30
TEQ r9, #255 ; Is it a broadcast?
BNE FrameDiscontinue
SetFIQ CheckNetOfScoutForBroadcast, r11, r13
40
[ StrongARM
MOV r13, #1
ST r13, FIQBusy ; Can't STRB PC in ARMv4
|
ST pc, FIQBusy ; Set the Busy flag, since this is not executed in UserMode
]
RTFIQ
ALIGN $Alignment
CheckNetOfScout
LD r13, SReg2
TST r13, #RxDA
MakeReceptionError2 EQ
LD r13, RxByte
TEQ r13, #0 ; Local net of zero
BNE FrameDiscontinue
B %60
ALIGN $Alignment
CheckNetOfScoutForBroadcast
LD r13, SReg2
TST r13, #RxDA
BEQ FrameDiscontinue
LD r13, RxByte
TEQ r13, #0 ; Local short broadcast?
BEQ %50 ; Yes, so get on with the reception
CMP r13, #&FC ; Global short (FF), Global long (FE), Local long (FD), or Reserved (FC)?
BLT FrameDiscontinue ; No
50
ORR r13, r13, #( BroadcastBit :SHR: 8 )
60
ORR r13, r9, r13, ASL #8 ; Bottom 16 bits are the destination Address
ST r13, RxMode
SetFIQ BufferData, r8, r9
SetJump CheckScoutBuffer, r11, r13
ADRL r8, ScoutBuffer
MOV r9, #?ScoutBuffer
RTFIQ
ReceptionErrorWithSReg2
[ Debug
LDR r11, NetErrorListPointer
STRB r13, [ r11, #1 ] ; SReg 2 at offset 1
]
ReceptionError
[ 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 NoRxRecordToUpdate
[ 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
]
LDRB r9, [ r8, #Offset_Status ]
LDR r11, [ r8, #Offset_Identifier ]
LDR r13, =TxCBIdentifier
TEQ r11, r13 ; Check if it is a Tx record
MOVEQ r9, #Status_NetError
BEQ DecrementCountAndWriteStatus ; Yes, deal with it as a Tx record
TransmissionErrorDuringReceive
MOV r9, #Status_RxReady
STRB r9, [ r8, #Offset_Status ]
MOV r8, #NIL ; NIL the record pointer
STR r8, Record
NoRxRecordToUpdate
LD r13, SReg2
ST r13, Status2
TST r13, #(RxDA :OR: AddressPresent)
BEQ Reset
B ReInit
FrameDiscontinue
MOV r13, #2_10100010 ; TxRS, Frame discontinue, RxIE
ST r13, CReg1
B Ready
ALIGN $Alignment
BufferData ROUT
LD r13, SReg2
TST r13, #RxDA
BEQ WasThatTheEnd
LD r13, RxByte
STRB r13, [ r8 ], #1
DECS r9
BEQ FrameDiscontinue
LD r13, SReg2
TST r13, #RxDA
BNE %20
TEQ r13, #0
BNE WasThatTheEnd
20
LD r13, RxByte
STRB r13, [ r8 ], #1
DECS r9
BEQ FrameDiscontinue
RTFIQ
WasThatTheEnd
LD r13, RxMode ; Turn the line around if not a broadcast
TST r13, #BroadcastBit
MOVEQ r13, #2_10000100 ; RTS, Flag idle, 1 byte mode, NO PSE
MOVNE r13, #2_00000100 ; Flag idle, 1 byte mode, NO PSE
ST r13, CReg2 ; So we can see an RxDA if there is one
MOV r13, #2_00000000 ; Disable interupts
ST r13, CReg1
LD r13, SReg2
TST r13, #FrameValid
MakeReceptionError2 EQ
TST r13, #RxDA
BEQ %10
LD r13, RxByte
STRB r13, [ r8 ], #1
DECS r9
10
TurnAroundDelay r8, r11, r13
ADR r13, NextJump ; The data fitted in the buffer and all is well
LDR pc, [ r13 ]
ALIGN $Alignment
CheckScoutBuffer ROUT
[ DebugFIQ
LDRNE r11, =Border_Green
ADR r13, VIDC
STR r11, [ r13, #0 ]
]
RSB r9, r9, #?ScoutBuffer ; The number of bytes now in the scout buffer
SUBS r9, r9, #4 ; Now the actual number of data bytes received
BLT Reset ; FrameDiscontinue ; ReceptionError
LDR r11, RxCBList
LDRB r13, ScoutBuffer + 3 ; Destination port
TEQ r13, #0 ; Is this an immediate operation ??
BEQ RxImmediate
CheckRxCB
TEQ r11, #NIL ; Scan RxCBs for a match
BEQ Reset ; FrameDiscontinue ; ReceptionError
LDRB r13, [ r11, #Offset_RxStation ] ; Check the station number first
TEQ r13, #255 ; Wild, skip to check network
BEQ %05
LDRB r10, ScoutBuffer + 0 ; Source station
TEQ r10, r13
BNE TryNextRxCB
05
LDRB r13, [ r11, #Offset_RxNetwork ] ; Now check net number
TEQ r13, #255 ; Wild, skip to check port
BEQ %10
LDRB r10, ScoutBuffer + 1 ; Source network
TEQ r10, r13
BNE TryNextRxCB
10
LDRB r13, [ r11, #Offset_RxPort ] ; Now check port
TEQ r13, #255 ; Wild, skip to check status
BEQ %20
LDRB r10, ScoutBuffer + 3 ; Destination port
TEQ r10, r13
BNE TryNextRxCB
20
LDRB r13, [ r11, #Offset_Status ] ; Now check status
TEQ r13, #Status_RxReady
TryNextRxCB
[ PoduleCapable
LDR r10, HardwareAddress
|
LDR r10, =EconetController ; Always branched to with BNE, because something didn't match
]
BEQ ScoutMatch ; This branch taken on the TEQ above
LDR r11, [ r11, #Offset_Link ]
B CheckRxCB
ScoutMatch
LD r13, RxMode
TST r13, #BroadcastBit
BNE RxBroadcast
MOV r13, #Status_Receiving
STRB r13, [ r11, #Offset_Status ]
LDR r13, ScoutBuffer + 0 ; Source Station, Network, Control, Port
STRB r13, [ r11, #Offset_Station ]
ASR r13, 8
STRB r13, [ r11, #Offset_Network ]
ASR r13, 8
STRB r13, [ r11, #Offset_Control ]
ASR r13, 8
STRB r13, [ r11, #Offset_Port ]
ST r11, Record
SetFIQ TxFromMe, r8, r13, Long
SetJump WaitForData, r8, r13
MOV r13, #2_11100111 ; RTS, CLRTxST, CLRRxST, FlagIdle, 2Byte, PSE
ST r13, CReg2
MOV r13, #2_01000100 ; RxRS, TxIE
ST r13, CReg1
RTFIQ
ALIGN $Alignment
WaitForData ; Shared with reception of Poke
[ False ; DebugFIQ
ADR r8, DebugSpacePointer
LDR r9, [ r8, #0 ]
TEQ r9, #0
LDRNEB r13, SReg1
STRNEB r13, [ r9 ], #1
LDRNEB r13, SReg2
STRNEB r13, [ r9 ], #1
CMP r9, #DebugSpaceEnd
MOVGE r9, #0
STR r9, [ r8, #0 ]
]
SetJump EndOfData, r8, r13
MOV r13, #2_00111111 ; -RTS, ClrRxST, TxLast, FC, FlagIdle, 2Byte, PSE
ST r13, CReg2
WaitForFIQ r8, r9
[ DebugFIQ
LDR r8, =Border_Red
ADR r9, VIDC
STR r8, [ r9, #0 ]
]
LD r13, SReg1
TST r13, #FrameComplete
MakeReceptionError EQ
MOV r13, #2_10000010 ; TxRS, RxIE
ST r13, CReg1
WaitForFIQ r8, r9
LD r13, SReg2
[ DebugFIQ
ADR r8, DebugSpacePointer
LDR r9, [ r8, #0 ]
TEQ r9, #0
STRNEB r13, [ r9 ], #1
CMP r9, #DebugSpaceEnd
MOVGE r9, #0
STR r9, [ r8, #0 ]
]
TST r13, #AddressPresent
[ DebugFIQ
LDRNE r8, =Border_Green
LDREQ r8, =Border_Pink
ADR r9, VIDC
STR r8, [ r9, #0 ]
]
MakeReceptionError2 EQ
LD r13, RxByte
LD r8, LocalStation
TEQ r13, r8
MakeReceptionError NE
WaitForFIQ r8, r9
[ DebugFIQ
LDR r8, =Border_Yellow
ADR r9, VIDC
STR r8, [ r9, #0 ]
]
LD r13, SReg2
TST r13, #RxDA
MakeReceptionError2 EQ
LD r13, RxByte
TEQ r13, #0 ; Local network must be zero
MakeReceptionError NE
WaitForFIQ r8, r9
LD r13, SReg2
TST r13, #RxDA
MakeReceptionError2 EQ
LD r13, RxByte
LDRB r8, [ r11, #Offset_Station ]
TEQ r13, r8
MakeReceptionError NE
LD r13, RxByte
LDRB r8, [ r11, #Offset_Network ]
TEQ r13, r8
MakeReceptionError NE
SetFIQ BufferData, r8, r13, Long
ADD r11, r11, #Offset_Start
LDMIA r11, { r8, r9 } ; Start & Length
RTFIQ
ALIGN $Alignment
EndOfData
LD r11, Record
LDR r8, [ r11, #Offset_Size ] ; The original size
SUB r9, r8, r9 ; The number of bytes received
STR r9, [ r11, #Offset_RxSize ] ; Mark reception so client can find out
SetFIQ TxFromMe, r8, r9, Long
SetJump EndOfData2, r8, r9
MOV r13, #2_11100111 ; RTS, CLRTxST, CLRRxST, FlagIdle, 2Byte, PSE
ST r13, CReg2
[ Analyser
MOV r13, #2_01000101 ; RxRS, TxIE, AC=1
ST r13, CReg1
MOV r13, #2_10000000 ; +DTR, NONLOOP
ST r13, CReg3
[ DebugFIQ
LDR r8, =Border_Magenta
ADR r9, VIDC
STR r8, [ r9, #0 ]
]
]
MOV r13, #2_01000100 ; RxRS, TxIE, AC=0
ST r13, CReg1
RTFIQ
ALIGN $Alignment
EndOfData2
MOV r13, #2_00111111 ; -RTS, ClrRxST, TxLast, FC, FlagIdle, 2Byte, PSE
ST r13, CReg2
WaitForFIQ r8, r13
LD r13, SReg1
TST r13, #FrameComplete
MakeReceptionError EQ
CompleteReception
MOV r13, #Status_Received
STRB r13, [ r11, #Offset_Status ]
CauseEventAndReset
LD r13, EventSequenceNumber
INC r13
ST r13, EventSequenceNumber
STR r13, [ r11, #Offset_Event ]
CauseInterruptAndReset
ADR r11, IOC
LDRB r13, [ r11, #IOCIRQMSKA ] ; IRQ Mask register
ORR r13, r13, #force_bit ; FIQ to IRQ down-grade
STRB r13, [ r11, #IOCIRQMSKA ] ; IRQ Mask register
B Reset
RxBroadcast
LDR r13, [ r11, #Offset_Size ] ; Check that the user's buffer is big enough
CMP r9, r13 ; Actual size of reception
MakeReceptionError GT
MOV r13, #Status_Receiving
STRB r13, [ r11, #Offset_Status ]
STR r9, [ r11, #Offset_RxSize ]
ADR r12, ScoutBuffer
LDR r13, [ r12 ], #4 ; Source station, net, control and port
; R12 now pointing at the actual data
STRB r13, [ r11, #Offset_Station ]
ASR r13, 8
STRB r13, [ r11, #Offset_Network ]
ASR r13, 8
BIC r13, r13, #BitSeven
STRB r13, [ r11, #Offset_Control ]
ASR r13, 8
STRB r13, [ r11, #Offset_Port ]
LDR r8, [ r11, #Offset_Start ]
; At this point the register useage is as follows;
; R8 is the destination address, doesn't need to be preserved
; R9 is the length, in bytes, of the copy required
; R10 is free, it is set to its usual value by "CauseInterruptAndReset"
; R11 is a pointer to the receive record, not stored in "Record"
; R12 is the source address, known to be word aligned, see R10
; R13 is free
TEQ r9, #0
BEQ CompleteReception
LDR r10, [ r12 ], #4 ; Get the first byte(s)
TST r8, #3 ; Check for alignment
BEQ CopyAlignmentZero
STRB r10, [ r8 ], #1 ; Copy the first byte
DECS r9
BEQ CompleteReception ; There was only one byte
LSR r10, 8
TST r8, #3 ; Check for alignment
BEQ CopyAlignmentOne
STRB r10, [ r8 ], #1 ; Copy the second byte
DECS r9
BEQ CompleteReception ; There were only two bytes
LSR r10, 8
TST r8, #3 ; Check for alignment
BEQ CopyAlignmentTwo
STRB r10, [ r8 ], #1 ; Copy the third byte
DECS r9
BEQ CompleteReception ; There were only three bytes
LSR r10, 8
CopyAlignmentThree ; There is one byte left in R10
LDR r13, [ r12 ], #4
ADD r10, r10, r13, LSL #8 ; Add in the next three bytes
CMP r9, #3
BLT CompleteCopy
STR r10, [ r8 ], #4
DEC r9, 4
MOV r10, r13, LSR #24
B CopyAlignmentThree
CopyAlignmentTwo ; There are two bytes left in R10
LDR r13, [ r12 ], #4
ADD r10, r10, r13, LSL #16 ; Add in the next two bytes
CMP r9, #3
BLT CompleteCopy
STR r10, [ r8 ], #4
DEC r9, 4
MOV r10, r13, LSR #16
B CopyAlignmentTwo
CopyAlignmentOne ; There are three bytes left in R10
LDR r13, [ r12 ], #4
ADD r10, r10, r13, LSL #24 ; Add in the next byte
CMP r9, #3
BLT CompleteCopy
STR r10, [ r8 ], #4
DEC r9, 4
MOV r10, r13, LSR #8
B CopyAlignmentOne
CopyAlignmentZero ; There are four bytes left in R10
CMP r9, #3
BLT CompleteCopy
AlignmentZeroLoop
STR r10, [ r8 ], #4
LDR r10, [ r12 ], #4
DEC r9, 4
CMP r9, #3
BGE AlignmentZeroLoop
CompleteCopy ; There are 0, 1, 2, or 3 bytes left to go, data is in R10
TEQ r9, #0 ; No bytes left?
STRNEB r10, [ r8 ], #1 ; No, so store one
SUBNES r9, r9, #1 ; Was that the last one?
MOVNE r10, r10, LSR #8 ; No get the next byte
STRNEB r10, [ r8 ], #1 ; And store it
SUBNES r9, r9, #1
MOVNE r10, r10, LSR #8
STRNEB r10, [ r8 ], #1
B CompleteReception
RxImmediate
[ DebugFIQ
LDR r8, =Border_Pink
ADR r11, VIDC
STR r8, [ r11, #0 ]
]
ADRL r11, ImmediateRecord
ST r11, Record
MOV r8, #Status_Receiving
STRB r8, [ r11, #Offset_Status ]
LDR r8, ScoutBuffer + 0 ; Station
STRB r8, [ r11, #Offset_Station ]
ASR r8, 8 ; Network
STRB r8, [ r11, #Offset_Network ]
ASR r8, 8 ; Control, Port is always zero
STRB r8, [ r11, #Offset_Control ]
DEC r8 ; Make base of Immediates &80 not &81
AND r8, r8, #2_00011111 ; Clear the top bits [ 0..31 ]
LD r9, LockOut
LD r13, Protection
ORR r13, r13, r9 ; Add in the lock out state
MOV r13, r13, ASR r8 ; Put relevant protection bit in bit zero
TST r13, #BitZero
MakeReceptionError NE ; That operation was protected
CMP r8, #( ( ImmediateEnd - ImmediateJumpTable ) / 4 )
ADDLT pc, pc, r8, ASL #2
B Reset ; That operation we have no implementation for yet
ImmediateJumpTable
B RxPeekData ; &81
B RxPokeData ; &82
B RxJSR ; &83
B RxUserRPC ; &84
B RxSystemRPC ; &85
B RxHalt ; &86
B RxContinue ; &87
B RxMachinePeek ; &88
B RxGetRegisters ; &89
ImmediateEnd
RxPeekData ; &81
SetJump TxStartData, r9, r13, Long
B ValidatePeekPokeAddress
RxPokeData ; &82
SetJump WaitForData, r9, r13 ; Share with normal reception
ValidatePeekPokeAddress
ADR r8, ScoutBuffer + 4 ; Start, End
LDMIA r8, { r8, r9 }
STR r8, [ r11, #Offset_Start ]
SUB r9, r9, r8 ; Size = End - Start
STR r9, [ r11, #Offset_Size ]
[ StrongARM
MOV r8, #1
ST r8, PeekPokeFlag ; Can't STRB PC in ARMv4
|
ST pc, PeekPokeFlag ; Non zero because of the mode
]
ADR r8, IOC
LDRB r13, [ r8, #IOCIRQMSKA ] ; IRQ Mask register
ORR r13, r13, #force_bit ; FIQ to IRQ down-grade
STRB r13, [ r8, #IOCIRQMSKA ] ; IRQ Mask register
SetFIQ TxFromMe, r9, r13, Long
RTFIQ
RxJSR ; &83
RxUserRPC ; &84
RxSystemRPC ; &85
SetFIQ TxFromMe, r8, r9
SetJump WaitForArguments, r8, r9
MOV r13, #2_11100111 ; RTS, CLRTxST, CLRRxST, FlagIdle, 2Byte, PSE
ST r13, CReg2
MOV r13, #2_01000100 ; RxRS, TxIE
ST r13, CReg1
RTFIQ ; Goes off to TxFromMe, then goes to WaitForArguments
ALIGN $Alignment
WaitForArguments
MOV r13, #2_00111111 ; -RTS, ClrRxST, TxLast, FC, FlagIdle, 2Byte, PSE
ST r13, CReg2
WaitForFIQ r8, r9
LD r13, SReg1
TST r13, #FrameComplete
MakeReceptionError EQ
MOV r13, #2_10000010 ; TxRS, RxIE
ST r13, CReg1
SetJump EndOfArguments, r8, r9 ; Do this early
WaitForFIQ r8, r9
LD r13, SReg2
TST r13, #AddressPresent
MakeReceptionError2 EQ
LD r13, RxByte
LD r9, LocalStation
TEQ r13, r9
MakeReceptionError NE ; Station number is wrong
LDR r13, ScoutBuffer + 4 ; The JSR address or Procedure number
ST r13, ArgumentsAddressOrNumber
WaitForFIQ r8, r9
LD r13, SReg2
TST r13, #RxDA
MakeReceptionError2 EQ ; What?
LD r13, RxByte
TEQ r13, #0 ; Local network must be zero
MakeReceptionError NE ; Network number is wrong
WaitForFIQ r8, r9
LD r13, SReg2
TST r13, #RxDA
MakeReceptionError2 EQ ; What?
LD r13, RxByte
LDRB r9, ImmediateRecord + Offset_Station
TEQ r13, r9
MakeReceptionError NE
LD r13, RxByte
LDRB r9, ImmediateRecord + Offset_Network
TEQ r13, r9
MakeReceptionError NE
SetFIQ BufferData, r9, r13, Long
ADRL r8, ArgumentsBuffer
MOV r9, #?ArgumentsBuffer
RTFIQ
ALIGN $Alignment
EndOfArguments
RSB r9, r9, #?ArgumentsBuffer ; Size of transmission
STR r9, ArgumentsSize
MOV r13, #2_11100111 ; RTS, CLRTxST, CLRRxST, FlagIdle, 2Byte, PSE
ST r13, CReg2
MOV r13, #2_01000100 ; RxRS, TxIE
ST r13, CReg1
SetFIQ TxFromMe, r9, r13
SetJump EndOfArguments2, r9, r13
RTFIQ
ALIGN $Alignment
EndOfArguments2
MOV r13, #2_00111111 ; -RTS, ClrRxST, TxLast, FC, FlagIdle, 2Byte, PSE
ST r13, CReg2
WaitForFIQ r9, r13
LD r13, SReg1
TST r13, #FrameComplete
MakeReceptionError EQ
MOV r9, #2_000011100 ; Protect against another immediate op of this class
ST r9, LockOut ; Set the lock out state
B CauseInterruptAndReset
RxHalt ; &86
RxContinue ; &87
B Reset
RxMachinePeek ; &88
[ DebugFIQ
LDR r8, =Border_Red
ADR r9, VIDC
STR r8, [ r9, #0 ]
]
[ OldOs
ADRL r8, MachineVersionNumber
MOV r9, #4 - 1
|
ADR r8, MachinePeekData
MOV r9, #?MachinePeekData - 1
]
B CommonPeek
RxGetRegisters ; &89
ADR r9, Registers
STMIA r9!, { r0-r14 } ^ ; Put down user R0 to R14, R9 now has address of R15
SUB r8, lr, #4 ; Correct PC
STR r8, [ r9 ], #4 ; Store R15 (PC+PSR)
TEQP psr, #FFlag + IFlag + IRQ_mode ; Go to IRQ Mode
NOP
STMIA r9!, { r13, r14 }
TEQP psr, #FFlag + IFlag + SVC_mode ; Go to SVC Mode
NOP
STMIA r9, { r13, r14 }
TEQP psr, #FFlag + IFlag + FIQ_mode ; Go back to FIQ Mode
NOP
ADR r8, Registers
MOV r9, #?Registers - 1
CommonPeek
SetFIQ TxFromMe, r11, r13
SetJump TxCommonPeekData, r11, r13
MOV r13, #2_11100111 ; RTS, CLRTxST, CLRRxST, FlagIdle, 2Byte, PSE
ST r13, CReg2
MOV r13, #2_01000100 ; RxRS, TxIE
ST r13, CReg1
RTFIQ
TxCommonPeekData ROUT
LD r13, SReg1
20
TSTS r13, #TxDRA ; TDRA OK ?
MakeNetError EQ
LDRB r13, [ r8 ], #1
ST r13, TxByte
SetFIQ TxData, r11, r13, Long
RTFIQ
LTORG
END