-
Notifications
You must be signed in to change notification settings - Fork 15
/
hw_seriala.a
257 lines (210 loc) · 8.56 KB
/
hw_seriala.a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
-- File: hw_seriala.a
-- Subsystem: ARM Helios executive
-- Author: JGSmith
-- Date: 930311
--
-- Description: Low-level VL16C551 serial interface link I/O functions.
--
-- Copyright (c) 1993, VLSI Technology Inc.
-- All Rights Reserved.
--
-- ----------------------------------------------------------------------------
include ../gexec.m -- Executive manifests
include link.m
include root.m
include module.m
include cpustate.m
include ARM/vy86pid.m
-- ----------------------------------------------------------------------------
_if _not _defp '__VY86PID [
error "This source file should only be used for VY86PID systems"
]
-- ----------------------------------------------------------------------------
-- LinkIntrHandler
--
-- Link Comms Interrupt handler.
--
-- This is branched to directly from the main system interrupt handler
-- routine.
--
-- NOTE: This code is currently setup to only deal with a single
-- serial interrupt source. It assumes that the serial device is Link
-- logical ID 0.
--
-- On Entry:
-- tmp/ip = hw_INTC
-- r14_irq = current threads return address and PSR (DO NOT CORRUPT)
-- r13_irq = current threads SaveState.CPUcontext (DO NOT CORRUPT)
-- Registers {r0-r12} have already been saved to the
-- SaveState.CPUcontext.
Function LinkIntrHandler
import ExternContinueThread,
ExternCheckIRQDispatch
GetExecRoot a1 -- a1 = execroot address
ldr a2,hw_SERIAL_holder -- a2 = VL16C551 serial device address
mov a4,0 -- a4 = 0 (used as a thread Dispatched flag)
mov v1,0 -- v1 = 0 (easy to use constant for later code)
mov v2,THREAD_RUNNABLE -- v2 = handy constant
-- Since we may have been called spuriously (and possibly not
-- even from the main system interrupt handler), we check that
-- we do have an out-standing serial interrupt.
ldrb a3,(a2,hw_serial.IIR) -- get interrupt state
tst a3,hw_serial_IIR_IPENDN -- check if interrupt is pending
bne ExternContinueThread -- no interrupt, so quick exit
-- check for Rx interrupt
and a3,a3,hw_serial_IIR_IID_mask -- type of interrupt pending
cmp a3,hw_serial_IIR_IID_RDA -- check for Rx DAta interrupt
bne checkTx
-- ----------------------------------------------------------------------------
-- Rx data interrupt
-- a1 = ExecRoot address
-- a2 = hw_SERIAL address
-- a4 = last SaveState dispatched
-- v1 = 0
-- v2 = THREAD_RUNNABLE
add v4,a1,ExecRoot.LinkInStat0 -- v4 = (LinkReq *)&xroot->LinkInStat[0]
ldmia v4,{v3,v5}
-- v3 = count
-- v5 = buffer
-- FIXME : We could improve this code by checking if more
-- bytes can be polled across
ldrb tmp,(a2,hw_serial.RBR) -- tmp = current byte
strb tmp,(v5),1 -- store byte (incrementing buffer address)
subs v3,v3,1 -- v3 = number of bytes remaining
stmneia v4,{v3,v5} -- save updated count and buffer values
bne ExternContinueThread -- continue the current thread
-- no bytes remaining, so fall through to unblockRxThread
-- ----------------------------------------------------------------------------
unblockRxThread:
-- Unblock the LinkRx thread.
-- a1 = ExecRoot address
-- a2 = hw_SERIAL
-- a4 = last SaveState dispatched
-- v1 = 0
-- v2 = THREAD_RUNNABLE
ldr tmp,(a1,ExecRoot.KernelRoot) -- get KernelRoot structure address
ldr tmp,(tmp,Root.Links) -- get Links structure address
ldr tmp,(tmp,0) -- index into link table (logical id 0)
add a4,tmp,Link.RxThread -- a4 = address of RxThread
-- a4 = SaveState **ssp = thread to be re-started
ldr v5,(a4) -- v5 = "SaveState *" of blocked thread
ldr tmp,(v5,SaveState.priority) -- tmp = SaveState.priority
add v3,a1,ExecRoot.Queue0.tail -- v3 = (ThreadQ *)&xroot->Queues0.tail
-- NOTE: At the moment we are in IRQ mode, with IRQs disabled.
-- This means that no other handlers will be activated, and we
-- can modify the run Q's atomically.
-- Add thread to its pri's run Q.
-- tq->tail = tq->tail->next = ss;
-- (index into RunQ .tails with 'tmp lsl 3' = pri * sizeof ThreadQ)
ldr v4,(v3,tmp lsl 3) -- v4 = tq->tail
str v5,(v4,SaveState.next) -- tq->tail->next = ss
str v5,(v3,tmp lsl 3) -- tq->tail = ss
str v1,(v5,SaveState.next) -- ss->next = NULL
-- Keep exec hint up to date.
-- if (pri < xroot->HighestAvailPri)
-- xroot->HighestAvailPri = pri;
ldr v4,(a1,ExecRoot.HighestAvailPri)
cmp v4,tmp
strgt tmp,(a1,ExecRoot.HighestAvailPri)
-- Clear thread so an AbortRx cannot re-schedule it.
str v1,(a4) -- *ssp = NULL
str v2,(v5,SaveState.status) -- ss->status = THREAD_RUNNABLE
-- Stop any further link input interrupts occuring
ldr a3,(a1,ExecRoot.Serial1_IER_softcopy)
bic a3,a3,hw_serial_IER_ERBFI
strb a3,(a2,hw_serial.IER) -- linka->IER &= ~IER_ERBFI
str a3,(a1,ExecRoot.Serial1_IER_softcopy)
B ExternCheckIRQDispatch -- so see if we need to slice to it
hw_SERIAL_holder:
word hw_SERIAL -- 32bit constant
-- ----------------------------------------------------------------------------
checkTx:
-- check for Tx interrupt
-- a1 = ExecRoot address
-- a2 = hw_SERIAL
-- a3 = type of interrupt pending
-- a4 = last SaveState dispatched
-- v1 = 0
-- v2 = THREAD_RUNNABLE
cmp a3,hw_serial_IIR_IID_THRE -- Tx Holding Register Empty interrupt
bne unknownIRQ
-- Tx data interrupt
-- a1 = ExecRoot address
-- a2 = hw_SERIAL address
add v4,a1,ExecRoot.LinkOutStat0 -- v4 = (LinkReq *)&xroot->LinkOutStat[0]
ldmia v4,{v3,v5}
-- v3 = count
-- v5 = buffer
-- FIXME : We could improve this code by checking if more
-- bytes can be polled across
ldrb tmp,(v5),1 -- load byte (incrementing buffer address)
strb tmp,(a2,hw_serial.THR) -- store byte to the serial device
subs v3,v3,1 -- v3 = number of bytes remaining
stmneia v4,{v3,v5} -- save updated count and buffer values
bne ExternContinueThread -- continue the current thread
-- no bytes remaining, so fall through to unblockTxThread
-- ----------------------------------------------------------------------------
unblockTxThread:
-- Unblock the LinkTx thread.
-- a1 = ExecRoot address
-- a2 = hw_SERIAL
-- a4 = last SaveState dispatched
-- v1 = 0
-- v2 = THREAD_RUNNABLE
ldr tmp,(a1,ExecRoot.KernelRoot) -- get KernelRoot structure address
ldr tmp,(tmp,Root.Links) -- get Links structure address
ldr tmp,(tmp,0) -- index into link table (logical id 0)
add a4,tmp,Link.TxThread -- a4 = address of TxThread
-- a4 = SaveState **ssp = thread to be re-started
ldr v5,(a4) -- v5 = "SaveState *" of blocked thread
ldr tmp,(v5,SaveState.priority) -- tmp = SaveState.priority
add v3, a1, ExecRoot.Queue0.tail -- v3 = (ThreadQ *)&xroot->Queues0.tail
-- See the comments about allowing other IRQs in the unblockRxThread code.
-- Add thread to its pri's run Q.
-- tq->tail = tq->tail->next = ss;
-- (index into RunQ .tails with 'tmp lsl 3' = pri * sizeof ThreadQ)
ldr v4,(v3,tmp lsl 3) -- v4 = tq->tail
str v5,(v4,SaveState.next) -- tq->tail->next = ss
str v5,(v3,tmp lsl 3) -- tq->tail = ss
str v1,(v5,SaveState.next) -- ss->next = NULL
-- Keep exec hint up to date.
-- if (pri < xroot->HighestAvailPri)
-- xroot->HighestAvailPri = pri;
ldr v4,(a1,ExecRoot.HighestAvailPri)
cmp v4,tmp
strgt tmp,(a1,ExecRoot.HighestAvailPri)
-- Clear thread so an AbortTx cannot re-schedule it.
str v1,(a4) -- *ssp = NULL
str v2,(v5,SaveState.status) -- ss->status = THREAD_RUNNABLE
-- Stop any further link output interrupts occuring.
ldr a3,(a1,ExecRoot.Serial1_IER_softcopy)
bic a3,a3,hw_serial_IER_ETBEI
strb a3,(a2,hw_serial.IER) -- linka->IER &= ~IER_ETBEI
str a3,(a1,ExecRoot.Serial1_IER_softcopy)
B ExternCheckIRQDispatch -- so see if we need to slice to it
-- ----------------------------------------------------------------------------
unknownIRQ:
-- FIXME : At the moment we ignore the modem status and line
-- status interrupts. However, we still need to clear
-- them to ensure we can leave the IRQ handler.
-- a1 = ExecRoot address
-- a2 = hw_SERIAL
-- a3 = type of interrupt pending
-- a4 = last SaveState dispatched
-- v1 = 0
-- v2 = THREAD_RUNNABLE
cmp a3,hw_serial_IIR_IID_MS -- Modem Status
bne unknownIRQcheckRLS
ldrb tmp,(a2,hw_serial.MSR) -- read MSR to clear source
b ExternContinueThread -- continue the current thread
-- ----------------------------------------------------------------------------
unknownIRQcheckRLS:
cmp a3,hw_serial_IIR_IID_RLS -- Rx Line Status
-- FIXME: If this is NE then we have failed to match a source
-- against the interrupt
bne ExternContinueThread -- continue the current thread
ldrb tmp,(a2,hw_serial.LSR) -- read LSR to clear source
b ExternContinueThread -- continue the current thread
-- and fall through to the handlerExit routine
-- ----------------------------------------------------------------------------
-- EOF hw_seriala.a