-
Notifications
You must be signed in to change notification settings - Fork 0
/
interrupt.asm
310 lines (235 loc) · 4.49 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
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
org $0800
cli
cld
xor ax,ax
mov si,ax
out $80,al
mov ss,ax
mov ax,#$0800
mov sp,ax
mov ax,#intvec
mov word [4],ax
mov ax,cs
mov word [6],ax
jmp init_continue
intvec:
iret
init_continue:
; skip over interrupt vector
jmp skip_over_interrupt_vector
progress:
dw $0
interrupt_triggered:
db $00
send_eoi:
db $01
nop
nop
kb_int_vector:
push ax
; retrieve character from keybboard
in al,#$60
; store
mov interrupt_triggered,al
;
cmp byte send_eoi,#$01
jnz skip_eoi
;
mov al,#$20 ; EOI code
out $20,al ; send 'end of interrupt'
;
skip_eoi:
pop ax
iret
unmask_keyboard:
; * PUT OCW1
push AX
; 8259 port 21
mov al,#$fd
; IMR, interrupt mask register
; only allow irq 1
out $21,al
pop AX
ret
mask_keyboard:
; * PUT OCW1
push AX
; 8259 port 21
mov al,#$ff
; IMR, interrupt mask register
; allow no interrupts
out $21,al
pop AX
ret
clear_interrupt_flag:
push ax
xor ax,ax
mov interrupt_triggered,al
pop ax
ret
wait_interrupt_success:
push cx
mov cx,#0000
loop_02:
cmp byte interrupt_triggered,#$aa
jz int_received
loop loop_02
cli
hlt
int_received:
pop cx
ret
wait_interrupt_none:
push cx
mov cx,#0000
loop_win:
cmp byte interrupt_triggered,#$aa
jz win_int_received2
loop loop_win
jp loop_win_ok
win_int_received2:
cli
hlt ; error!
loop_win_ok:
pop cx
ret
reset_keyboard:
; trigger keyboard reset
; set kbd clk line low
mov al,#$08
out $61,al
; this is 20ms on a 4.77MHz PC
mov cx,#10582
loop_01:
loop loop_01
; set clk, enable lines high
mov al,#$c8
out $61,al
; set clk high, enable low
mov al,#$48
out $61,al
ret
; *** MAIN ***
skip_over_interrupt_vector:
; set pointer to vector routine
mov ax,#kb_int_vector
mov [9 * 4 + 0],ax
; set segment register to this code
mov ax,cs
mov [9 * 4 + 2],ax
; * PUT ICW1
; 8259 port 20
mov al,#$13
; 00010011 -> ICW1, edge triggered, 8 byte int vector, single 8259, with ICW4
out $20,al
; * PUT ICW2?
; 8259 port 21
mov al,#$08
; interrupt vector starting at 8
out $21,al
; NO ICW3 because the system has no slaves
; * PUT ICW4
; 00001101 -> sequential, buffered master, normal EOI, 80x86 mode
mov al,#$0d
out $21,al
; ******** check if interrupts come when doing STI/CLI ********
mov progress,#$0001
call unmask_keyboard
; just to be sure, redundant at this step
call clear_interrupt_flag
call reset_keyboard
; enable interrupts
sti
; wait a while for an interrupt
call wait_interrupt_success
; disable interrupts
cli
call clear_interrupt_flag
call reset_keyboard
mov progress,#$0002
; wait a while and make sure no interrupt comes in
call wait_interrupt_none
; * flush interrupt
sti ; enable interrupts
wait_for_int:
cmp byte interrupt_triggered,#$aa
jne wait_for_int
; disable interrupts
cli
; ******** check if no interrupt comes in when doing STI and 8259 mask ********
mov progress,#$100
call mask_keyboard
mov progress,#$101
call clear_interrupt_flag
mov progress,#$102
sti
mov progress,#$103
call reset_keyboard
mov progress,#$104
; wait a while and make sure no interrupt comes in
call wait_interrupt_none
; ******** check if no interrupt comes in when the previous is not EOId ********
mov progress,#$200
call unmask_keyboard
; make sure no EOI is send to the 8259
mov byte send_eoi,#$00
call clear_interrupt_flag
; generate an interrupt
call reset_keyboard
; wait for the generated interrupt
call wait_interrupt_success
mov progress,#$201
call clear_interrupt_flag
; generate another interrupt
call reset_keyboard
call wait_interrupt_none
; ********* check if offset is taken care of ********
jmp skip_over_new_vector
hlt_vector:
hlt
skip_over_new_vector:
cli
; error vector
mov ax,#hlt_vector
mov [9 * 4 + 0],ax
mov ax,cs
mov [9 * 4 + 2],ax
; all fine vector
mov ax,#kb_int_vector
mov [17 * 4 + 0],ax
mov ax,cs
mov [17 * 4 + 2],ax
; * PUT ICW1
; 8259 port 20
mov al,#$13
; 00010011 -> ICW1, edge triggered, 8 byte int vector, single 8259, with ICW4
out $20,al
; * PUT ICW2?
; 8259 port 21
mov al,#$10
; interrupt vector starting at 16
out $21,al
; NO ICW3 because the system has no slaves
; * PUT ICW4
; 00001101 -> sequential, buffered master, normal EOI, 80x86 mode
mov al,#$0d
out $21,al
; go!
mov progress,#$300
mov byte send_eoi,#$01
call unmask_keyboard
mov progress,#$301
call clear_interrupt_flag
sti
mov progress,#$302
call reset_keyboard
mov progress,#$303
call wait_interrupt_success
mov progress,#$304
; ***
mov ax,#$a5ee
mov si,ax
mov al,#$ff
out $80,al
cli
hlt