/
interrupt.asm
260 lines (241 loc) · 4.8 KB
/
interrupt.asm
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
258
259
260
;; contextSwitch [System]
;; Triggers a context switch early. This will transfer control from your thread to
;; another and eventaully return to yours with interrupts enabled.
contextSwitch:
di
push af
push bc
push de
push hl
push ix
push iy
exx
ex af, af'
push af
push bc
push de
push hl
jr doContextSwitch
sysInterrupt:
di
push af
push bc
push de
push hl
push ix
push iy
exx
ex af, af'
push af
push bc
push de
push hl
#ifdef USB
jp usbInterrupt
interruptResume:
#endif
#ifdef LINK_ASSIST
in a, (PORT_LINK_ASSIST_STATUS)
and 0b00000111 ; LA_INT_* bits
jp nz, la_handleInterrupt
#endif
#ifdef LINK_ASSIST_RO
; TODO
#endif
in a, (PORT_INT_TRIG)
bit BIT_INT_TRIG_ON, a
jp nz, intHandleON
bit BIT_INT_TRIG_TIMER1, a
jp nz, intHandleTimer1
bit BIT_INT_TRIG_TIMER2, a
jp nz, intHandleTimer2
bit BIT_INT_TRIG_LINK, a
jp nz, intHandleLink
jr contextSwitch
intHandleON:
in a, (PORT_INT_MASK)
res BIT_INT_ON, a
out (PORT_INT_MASK), a
set BIT_INT_ON, a
out (PORT_INT_MASK), a
; Check for special keycodes
jp handleKeyboard
intHandleTimer1:
in a, (PORT_INT_MASK)
res BIT_INT_TIMER1, a
out (PORT_INT_MASK), a
set BIT_INT_TIMER1, a
out (PORT_INT_MASK), a
; Timer 1 interrupt
ld hl, (kernel_current_time)
inc hl
ld (kernel_current_time), hl
doContextSwitch:
ld a, (currentThreadIndex)
cp -1
jr z, contextSwitch_manual
add a, a
add a, a
add a, a
ld hl, threadTable + 3
add a, l
ld l, a
ex de, hl
ld hl, 0
add hl, sp
ex de, hl
; Save stack pointer
ld (hl), e
inc hl
ld (hl), d
contextSwitch_manual:
ld a, (activeThreads)
or a \ jr z, noThreads ; Error out when there are no active threads
ld c, a \ inc c
contextSwitch_search:
dec c
xor a
cp c
jr z, noActiveThreads
ld a, (currentThreadIndex)
inc a \ ld (currentThreadIndex), a
ld b, a
ld a, (activeThreads)
dec a \ cp b
jr nc, _
xor a
ld b, a
ld (currentThreadIndex), a
_: ld a, b
add a, a
add a, a
add a, a
ld hl, threadTable + 5
add a, l
ld l, a
ld a, (hl)
bit 1, a ; May be suspended
jr nz, _
bit 2, a
jr nz, contextSwitch_search ; Suspended
_: dec hl
ld d, (hl)
dec hl
ld e, (hl)
ex de, hl
ld sp, hl
jr sysInterruptDone
noThreads:
jr sysInterruptDone
ld a, panic_no_threads
jp panic
noActiveThreads:
ld a, -1
ld (currentThreadIndex), a
ld hl, idlethread_stack
ld de, userMemory - (idlethread_stack_end - idlethread_stack)
ld bc, idlethread_stack_end - idlethread_stack
ldir
ld sp, userMemory - (idlethread_stack_end - idlethread_stack)
jr sysInterruptDone
intHandleTimer2:
in a, (PORT_INT_MASK)
res BIT_INT_TIMER2, a
out (PORT_INT_MASK), a
set BIT_INT_TIMER2, a
out (PORT_INT_MASK), a
; Timer 2 interrupt
jr sysInterruptDone
intHandleLink:
in a, (PORT_INT_MASK)
res BIT_INT_LINK, a
out (PORT_INT_MASK), a
set BIT_INT_LINK, a
out (PORT_INT_MASK), a
; Link interrupt
sysInterruptDone:
pop hl
pop de
pop bc
pop af
exx
ex af, af'
pop iy
pop ix
pop hl
pop de
pop bc
pop af
ei
ret
; Sits and spins if all other threads are suspended
idlethread:
halt
jr idlethread
idlethread_stack:
.dw 0
.dw 0
.dw 0
.dw 0
.dw 0
.dw 0
.dw 0
.dw 0
.dw 0
.dw 0
.dw idlethread
idlethread_stack_end:
handleKeyboard:
call getKey_skipCheck
call flushKeys_skipCheck
cp kK
jr z, handleOnK
cp kR
jp z, reboot
cp kMODE
jr z, handleOnMODE
#ifdef DEBUG
cp kPRGM
jr z, handleOnPRGM
#endif
jr sysInterruptDone
handleOnMODE:
ld de, init
call launchProgram
ld h, 1
call setInitialA
jr sysInterruptDone
handleOnK:
ld a, (hwLockLCD)
call killThread
jp contextSwitch_manual
#ifdef DEBUG
handleOnPRGM:
rst 0x30
jp sysInterruptDone
#endif
#ifdef USB
usbInterrupt:
in a, (0x55) ; USB Interrupt status
bit BIT_USB_INT_BUS, a
jr z, usbUnknownEvent
bit BIT_USB_INT_LINE, a
jr z, usbLineEvent
bit BIT_USB_INT_PROTOCOL, a
jr z, usbProtocolEvent
jp interruptResume
usbUnknownEvent:
jp interruptResume
usbLineEvent:
in a, (PORT_USB_LINE) ; USB Line Events
xor 0xFF
out (PORT_USB_LINE_MASK), a ; Acknowledge interrupt and disable further interrupts
jp interruptResume
usbProtocolEvent:
in a, (PORT_USB_WRPIPE1)
in a, (PORT_USB_WRPIPE2)
in a, (PORT_USB_RDPIPE1)
in a, (PORT_USB_RDPIPE2)
in a, (PORT_USB_MISC_EVENTS) ; Merely reading from these will acknowledge the interrupt
jp interruptResume
#endif