Mercurial > hg > Members > kono > nitros9-code
annotate level1/modules/dw3.asm @ 2387:8476556e5f0c
dynamic ISR/poll frequency
author | aaronwolfe |
---|---|
date | Sun, 24 Jan 2010 01:51:34 +0000 |
parents | b399116a3b5f |
children | 61778d4bb634 |
rev | line source |
---|---|
2180 | 1 ******************************************************************** |
2 * DW3 - DriveWire 3 Low Level Subroutine Module | |
3 * | |
4 * $Id$ | |
5 * | |
6 * Edt/Rev YYYY/MM/DD Modified by | |
7 * Comment | |
8 * ------------------------------------------------------------------ | |
9 * 1 2008/01/26 Boisy G. Pitre | |
10 * Started as a segregated subroutine module. | |
2374 | 11 * |
12 * 2 2010/01/20 Boisy G. Pitre | |
13 * Added support for DWNet | |
2387 | 14 * |
15 * 3 2010/01/23 Aaron A. Wolfe | |
16 * Added dynamic polling frequency | |
17 * | |
2374 | 18 nam DW3 |
19 ttl DriveWire 3 Low Level Subroutine Module | |
2180 | 20 |
2374 | 21 ifp1 |
22 use defsfile | |
23 use dwdefs.d | |
24 endc | |
2180 | 25 |
2374 | 26 tylg set Sbrtn+Objct |
27 atrv set ReEnt+rev | |
28 rev set $01 | |
2308 | 29 |
2374 | 30 mod eom,name,tylg,atrv,start,0 |
2180 | 31 |
2308 | 32 * irq |
2374 | 33 IRQPckt fcb $00,$01,$0A ;IRQ packet Flip(1),Mask(1),Priority(1) bytes |
2308 | 34 * Default time packet |
2374 | 35 DefTime fcb 109,12,31,23,59,59 |
2180 | 36 |
2387 | 37 * for dynamic poll frequency, number of ticks between firing poller |
38 * speed 1 = interactive (typing) | |
39 PollSpd1 fcb 3 | |
40 * speed 2 = bulk transfer | |
41 PollSpd2 fcb 6 | |
42 * speed 3 = idle | |
43 PollSpd3 fcb 40 | |
44 * X pollidle -> drop to next slower rate | |
45 PollIdle fcb 60 | |
46 | |
47 | |
2374 | 48 name fcs /dw3/ |
2180 | 49 |
50 * DriveWire subroutine entry table | |
2374 | 51 start lbra Init |
52 bra Read | |
53 nop | |
54 lbra Write | |
2180 | 55 |
56 * Term | |
57 * | |
58 * Entry: | |
59 * U = address of device memory area | |
60 * | |
61 * Exit: | |
62 * CC = carry set on error | |
63 * B = error code | |
64 * | |
2374 | 65 Term |
66 clrb clear Carry | |
67 rts | |
2180 | 68 |
69 * Read | |
70 * | |
71 * ON ENTRY: | |
72 * X = ADDRESS OF THE RECEIVE BUFFER | |
73 * A = TIMEOUT VALUE (182 = APPROX ONE SECOND @ 0.89 MHz) | |
74 * | |
75 * ON EXIT: | |
76 * Y = DATA CHECKSUM | |
77 * D = ACTUAL NUMBER OF BYTES RECEIVED | |
78 * X AND U ARE PRESERVED | |
79 * CC.CARRY IS SET IF A FRAMING ERROR WAS DETECTED | |
80 * | |
2374 | 81 Read |
82 use dwread.asm | |
83 | |
2180 | 84 * Write |
85 * | |
86 * Entry: | |
2374 | 87 Write |
88 use dwwrite.asm | |
2308 | 89 |
90 * Init | |
91 * | |
92 * Entry: | |
93 * Y = address of device descriptor | |
94 * U = address of device memory area | |
95 * | |
96 * Exit: | |
97 * CC = carry set on error | |
98 * B = error code | |
99 * | |
100 * Initialize the serial device | |
2374 | 101 Init |
102 clrb clear Carry | |
103 pshs y,x,cc then push CC on stack | |
104 orcc #IntMasks | |
105 ldx #PIA1Base $FF20 | |
106 clr 1,x clear CD | |
107 lda #%11111110 | |
108 sta ,x | |
109 lda #%00110100 | |
110 sta 1,x | |
111 lda ,x | |
2308 | 112 |
113 ; allocate DW statics page | |
2374 | 114 pshs u |
115 ldd #$0100 | |
116 os9 F$SRqMem | |
117 tfr u,x | |
118 puls u | |
119 lbcs InitEx | |
120 ifgt Level-1 | |
121 stx <D.DWStat | |
122 else | |
123 stx >D.DWStat | |
124 endc | |
2308 | 125 ; clear out 256 byte page at X |
2374 | 126 clrb |
127 loop@ clr ,x+ | |
128 decb | |
129 bne loop@ | |
2308 | 130 |
2321
6a5ada3e2666
added DWINIT op code, dw3 now sends on init just before installing VIRQ
aaronwolfe
parents:
2316
diff
changeset
|
131 * send OP_DWINIT |
6a5ada3e2666
added DWINIT op code, dw3 now sends on init just before installing VIRQ
aaronwolfe
parents:
2316
diff
changeset
|
132 ; setup DWsub command |
2374 | 133 pshs u |
134 lda #OP_DWINIT ; load command | |
135 pshs a ; command store on stack | |
136 leax ,s ; point X to stack | |
137 ldy #1 ; 1 byte to send | |
138 ifgt Level-1 | |
139 ldu <D.DWSubAddr | |
140 else | |
141 ldu >D.DWSubAddr | |
142 endc | |
143 jsr 6,u ; call DWrite | |
144 leas 1,s ; clean 1 DWsub arg from stack | |
145 puls u | |
146 | |
2308 | 147 * install ISR |
2374 | 148 InstIRQ |
149 ifgt Level-1 | |
150 ldx <D.DWStat | |
151 else | |
152 ldx >D.DWStat | |
153 endc | |
154 leax DW.VIRQPkt,x | |
155 pshs u | |
156 tfr x,u | |
157 leax Vi.Stat,x ;fake VIRQ status register | |
158 lda #$80 ;VIRQ flag clear, repeated VIRQs | |
159 sta ,x ;set it while we're here... | |
160 tfr x,d ;copy fake VIRQ status register address | |
161 leax IRQPckt,pcr ;IRQ polling packet | |
162 leay IRQSvc,pcr ;IRQ service entry | |
163 os9 F$IRQ ;install | |
164 puls u | |
165 bcs InitEx ;exit with error | |
2387 | 166 clra |
167 ldb PollSpd3,pcr ; start at idle | |
2374 | 168 ifgt Level-1 |
169 ldx <D.DWStat | |
170 else | |
171 ldx >D.DWStat | |
172 endc | |
173 leax DW.VIRQPkt,x | |
174 std Vi.Rst,x ; reset count | |
175 tfr x,y ; move VIRQ software packet to Y | |
176 tryagain | |
177 ldx #$0001 ; code to install new VIRQ | |
178 os9 F$VIRQ ; install | |
179 bcc IRQok ; no error, continue | |
180 cmpb #E$UnkSvc | |
181 bne InitEx | |
2308 | 182 ; if we get an E$UnkSvc error, then clock has not been initialized, so do it here |
2374 | 183 leax DefTime,pcr |
184 os9 F$STime | |
185 bra tryagain ; note: this has the slim potential of looping forever | |
186 IRQok | |
187 ifgt Level-1 | |
188 ldx <D.DWStat | |
189 else | |
190 ldx >D.DWStat | |
191 endc | |
2308 | 192 ; cheat: we know DW.StatTbl is at offset $00 from D.DWStat, do not bother with leax |
2374 | 193 leax DW.StatTbl,x |
194 tfr u,d | |
195 ldb <V.PORT+1,u ; get our port # | |
196 sta b,x ; store in table | |
2308 | 197 |
2374 | 198 InitEx |
199 puls cc,x,y,pc | |
2308 | 200 |
201 | |
202 ; *********************************************************************** | |
203 ; Interrupt handler - Much help from Darren Atkinson | |
2374 | 204 |
205 IRQMulti3 anda #$0F ; mask first 4 bits, a is now port #+1 | |
206 deca ; we pass +1 to use 0 for no data | |
207 pshs a ; save port # | |
208 cmpb RxGrab,u ; compare room in buffer to server's byte | |
209 bhs IRQM06 ; room left >= server's bytes, no problem | |
210 | |
211 stb RxGrab,u ; else replace with room left in our buffer | |
2308 | 212 |
213 ; also limit to end of buffer | |
2374 | 214 IRQM06 ldd RxBufEnd,u ; end addr of buffer |
215 subd RxBufPut,u ; subtract current write pointer, result is # bytes left going forward in buff. | |
216 | |
217 IRQM05 cmpb RxGrab,u ; compare b (room left) to grab bytes | |
218 bhs IRQM03 ; branch if we have room for grab bytes | |
2308 | 219 |
2374 | 220 stb RxGrab,u ; else set grab to room left |
221 | |
2308 | 222 ; send multiread req |
2374 | 223 IRQM03 puls a ; port # is on stack |
224 ldb RxGrab,u | |
2308 | 225 |
2374 | 226 pshs u |
227 | |
2308 | 228 ; setup DWsub command |
2374 | 229 pshs d ; (a port, b bytes) |
230 lda #OP_SERREADM ; load command | |
231 pshs a ; command store on stack | |
232 leax ,s ; point X to stack | |
233 ldy #3 ; 3 bytes to send | |
2308 | 234 |
2374 | 235 ifgt Level-1 |
236 ldu <D.DWSubAddr | |
237 else | |
238 ldu >D.DWSubAddr | |
239 endc | |
240 jsr 6,u ; call DWrite | |
2308 | 241 |
2374 | 242 leas 3,s ; clean 3 DWsub args from stack |
2308 | 243 |
2374 | 244 ldx ,s ; pointer to this port's area (from U prior), leave it on stack |
245 ldb RxGrab,x ; set B to grab bytes | |
246 clra ; 0 in high byte | |
247 tfr d,y ; set # bytes for DW | |
2308 | 248 |
2374 | 249 ldx RxBufPut,x ; point X to insert position in this port's buffer |
2308 | 250 ; receive response |
2374 | 251 jsr 3,u ; call DWRead |
2308 | 252 ; handle errors? |
253 | |
254 | |
2374 | 255 puls u |
256 ldb RxGrab,u ; our grab bytes | |
2308 | 257 |
258 ; set new RxBufPut | |
2374 | 259 ldx RxBufPut,u ; current write pointer |
260 abx ; add b (# bytes) to RxBufPut | |
261 cmpx RxBufEnd,u ; end of Rx buffer? | |
262 blo IRQM04 ; no, go keep laydown pointer | |
263 ldx RxBufPtr,u ; get Rx buffer start address | |
264 IRQM04 stx RxBufPut,u ; set new Rx data laydown pointer | |
2308 | 265 |
266 ; set new RxDatLen | |
2374 | 267 ldb RxDatLen,u |
268 addb RxGrab,u | |
269 stb RxDatLen,u ; store new value | |
270 | |
271 lbra CkSSig ; had to lbra | |
272 | |
273 IRQMulti | |
2387 | 274 ; set IRQ freq for bulk |
275 pshs a | |
276 lda PollSpd2,pcr | |
277 lbsr IRQsetFRQ | |
278 puls a | |
279 | |
2308 | 280 ; initial grab bytes |
2374 | 281 stb RxGrab,u |
282 | |
2308 | 283 ; limit server bytes to bufsize - datlen |
2374 | 284 ldb RxBufSiz,u ; size of buffer |
285 subb RxDatLen,u ; current bytes in buffer | |
286 bne IRQMulti3 ; continue, we have some space in buffer | |
2308 | 287 ; no room in buffer |
2374 | 288 tstb |
289 lbne CkSSig ;had to lbra | |
290 lbra IRQExit ;had to lbra | |
291 | |
2308 | 292 |
293 ; **** IRQ ENTRY POINT | |
2374 | 294 IRQSvc equ * |
295 pshs cc,dp ; save system cc,DP | |
296 orcc #IntMasks ; mask interrupts | |
2308 | 297 |
298 ; mark VIRQ handled (note U is pointer to our VIRQ packet in DP) | |
2374 | 299 lda Vi.Stat,u ; VIRQ status register |
300 anda #^Vi.IFlag ; clear flag in VIRQ status register | |
301 sta Vi.Stat,u ; save it... | |
2308 | 302 |
303 ; poll server for incoming serial data | |
304 | |
305 ; send request | |
2374 | 306 lda #OP_SERREAD ; load command |
307 pshs a ; command store on stack | |
308 leax ,s ; point X to stack | |
309 ldy #1 ; 1 byte to send | |
2308 | 310 |
2374 | 311 ifgt Level-1 |
312 ldu <D.DWSubAddr | |
313 else | |
314 ldu >D.DWSubAddr | |
315 endc | |
316 jsr 6,u ; call DWrite | |
2308 | 317 |
318 ; receive response | |
2374 | 319 leas -1,s ; one more byte to fit response |
320 leax ,s ; point X to stack head | |
321 ldy #2 ; 2 bytes to retrieve | |
322 jsr 3,u ; call DWRead | |
323 beq IRQSvc2 ; branch if no error | |
324 leas 2,s ; error, cleanup stack 2 | |
325 lbra IRQExit2 ; don't reset error count on the way out | |
2308 | 326 |
327 ; process response | |
2374 | 328 IRQSvc2 |
329 ldd ,s++ ; pull returned status byte into A,data into B (set Z if zero, N if multiread) | |
2387 | 330 bne IRQGotOp ; branch if D != 0 (something to do) |
331 * this is a NOP response.. do we need to reschedule | |
332 ifgt Level-1 | |
333 ldx <D.DWStat | |
334 else | |
335 ldx >D.DWStat | |
336 endc | |
337 lda DW.VIRQFRQ,x | |
338 cmpa PollSpd3,pcr | |
339 lbeq IRQExit ;we are already at idle speed | |
2308 | 340 |
2387 | 341 lda DW.VIRQNOP,x |
342 inca | |
343 cmpa PollIdle,pcr | |
344 beq FRQdown | |
345 | |
346 sta DW.VIRQNOP,x ;inc NOP count, exit | |
347 lbra IRQExit | |
348 | |
349 FRQdown lda DW.VIRQFRQ,x | |
350 cmpa PollSpd1,pcr | |
351 beq FRQd1 | |
352 lda PollSpd3,pcr | |
353 FRQd2 | |
354 sta DW.VIRQFRQ,x | |
355 clr DW.VIRQNOP,x | |
356 lbra IRQExit | |
357 FRQd1 lda PollSpd2,pcr | |
358 bra FRQd2 | |
2374 | 359 |
2308 | 360 ; save back D on stack and build our U |
2387 | 361 IRQGotOp pshs d |
2311 | 362 * mode switch on bits 7+6 of A: 00 = vserial, 01 = system, 10 = wirebug?, 11 = ? |
2374 | 363 anda #$C0 ; mask last 6 bits |
364 beq mode00 ; virtual serial mode | |
2311 | 365 ; future - handle other modes |
2374 | 366 lbra IRQExit ; for now, bail |
367 | |
368 mode00 lda ,s ; restore A | |
369 anda #$0F ; mask first 4 bits, a is now port #+1 | |
370 beq IRQCont ; if we're here with 0 in the port, its not really a port # (can we jump straight to status?) | |
371 deca ; we pass +1 to use 0 for no data | |
2308 | 372 ; here we set U to the static storage area of the device we are working with |
2374 | 373 ifgt Level-1 |
374 ldx <D.DWStat | |
375 else | |
376 ldx >D.DWStat | |
377 endc | |
2308 | 378 ; cheat: we know DW.StatTbl is at offset $00 from D.DWStat, do not bother with leax |
379 ; leax DW.StatTbl,x | |
2374 | 380 lda a,x |
381 bne IRQCont ; if A is 0, then this device is not active, so exit | |
382 puls d | |
383 lbra IRQExit | |
384 IRQCont | |
385 clrb | |
386 tfr d,u | |
387 | |
388 puls d | |
2308 | 389 |
2311 | 390 * multiread/status flag is in bit 4 of A |
2374 | 391 bita #$10 |
2387 | 392 beq IRQPutch ; branch for read1 if multiread not set |
2374 | 393 |
2311 | 394 * all 0s in port means status, anything else is multiread |
2374 | 395 |
396 bita #$0F ;mask bit 7-4 | |
397 beq dostat ;port # all 0, this is a status response | |
2387 | 398 lbra IRQMulti ;its not all 0, this is a multiread |
2308 | 399 |
2314
5f76d1a611f6
term signal sending for serread port status responses
aaronwolfe
parents:
2313
diff
changeset
|
400 |
5f76d1a611f6
term signal sending for serread port status responses
aaronwolfe
parents:
2313
diff
changeset
|
401 * in status events, databyte is split, 4bits status, 4bits port # |
2374 | 402 dostat bitb #$F0 ;mask low bits |
403 lbne IRQExit ;we only implement code 0000, term | |
2314
5f76d1a611f6
term signal sending for serread port status responses
aaronwolfe
parents:
2313
diff
changeset
|
404 * set u to port # |
2374 | 405 ifgt Level-1 |
406 ldx <D.DWStat | |
407 else | |
408 ldx >D.DWStat | |
409 endc | |
410 lda b,x | |
411 bne statcont ; if A is 0, then this device is not active, so exit | |
412 lbra IRQExit | |
2372 | 413 |
2387 | 414 * IRQ set freq routine |
415 * sets freq and clears NOP counter | |
416 * a = desired IRQ freq | |
417 IRQsetFRQ pshs x ; preserve | |
418 ifgt Level-1 | |
419 ldx <D.DWStat | |
420 else | |
421 ldx >D.DWStat | |
422 endc | |
423 sta DW.VIRQFRQ,x | |
424 clr DW.VIRQNOP,x | |
425 puls x | |
426 rts | |
427 | |
428 | |
2372 | 429 * This routine roots through process descriptors in a queue and |
430 * checks to see if the process has a path that is open to the device | |
431 * represented by the static storage pointer in U. if so, the S$HUP | |
432 * signal is sent to that process | |
433 * | |
434 * Entry: X = process descriptor to evaluate | |
435 * U = static storage of device we want to check against | |
2374 | 436 RootThrough |
437 ldb #NumPaths | |
438 leay P$Path,x | |
439 pshs x | |
440 loop decb | |
441 bmi out | |
442 lda ,y+ | |
443 beq loop | |
444 pshs y | |
445 ifgt Level-1 | |
446 ldx <D.PthDBT | |
447 else | |
448 ldx >D.PthDBT | |
449 endc | |
450 os9 F$Find64 | |
451 ldx PD.DEV,y | |
452 leax V$STAT,x | |
453 puls y | |
454 bcs out | |
2372 | 455 |
2374 | 456 cmpu ,x |
457 bne loop | |
458 | |
459 ldx ,s | |
460 lda P$ID,x | |
461 ldb #S$HUP | |
462 os9 F$Send | |
2372 | 463 |
2374 | 464 out puls x |
465 ldx P$Queue,x | |
466 bne RootThrough | |
467 rts | |
468 | |
469 statcont clrb | |
470 tfr d,u | |
2372 | 471 * NEW: root through all process descriptors. if any has a path open to this |
472 * device, send then S$HUP | |
2374 | 473 ldx <D.AProcQ |
2383
b399116a3b5f
Now we have a /N descriptor... and the code in scdwn.asm to handle it.
boisy
parents:
2375
diff
changeset
|
474 beq dowaitq |
2374 | 475 bsr RootThrough |
2383
b399116a3b5f
Now we have a /N descriptor... and the code in scdwn.asm to handle it.
boisy
parents:
2375
diff
changeset
|
476 dowaitq ldx <D.WProcQ |
b399116a3b5f
Now we have a /N descriptor... and the code in scdwn.asm to handle it.
boisy
parents:
2375
diff
changeset
|
477 beq dosleepq |
2374 | 478 bsr RootThrough |
2383
b399116a3b5f
Now we have a /N descriptor... and the code in scdwn.asm to handle it.
boisy
parents:
2375
diff
changeset
|
479 dosleepq ldx <D.SProcQ |
2375 | 480 beq CkLPRC |
2374 | 481 bsr RootThrough |
2372 | 482 |
2387 | 483 CkLPRC |
2374 | 484 lda <V.LPRC,u |
485 beq IRQExit ; no last process, bail | |
486 ldb #S$HUP | |
487 os9 F$Send ; send signal, don't think we can do anything about an error result anyway.. so | |
488 bra CkSuspnd ; do we need to go check suspend? | |
2314
5f76d1a611f6
term signal sending for serread port status responses
aaronwolfe
parents:
2313
diff
changeset
|
489 |
2308 | 490 ; put byte B in port As buffer - optimization help from Darren Atkinson |
2387 | 491 IRQPutCh |
492 ; set IRQ freq for bulk | |
493 lbsr IRQsetFRQ | |
494 ldx RxBufPut,u ; point X to the data buffer | |
2374 | 495 |
2308 | 496 ; process interrupt/quit characters here |
497 ; note we will have to do this in the multiread (ugh) | |
2374 | 498 tfr b,a ; put byte in A |
499 ldb #S$Intrpt | |
500 cmpa V.INTR,u | |
501 beq send@ | |
502 ldb #S$Abort | |
503 cmpa V.QUIT,u | |
504 bne store | |
505 send@ lda V.LPRC,u | |
506 beq IRQExit | |
507 os9 F$Send | |
508 bra IRQExit | |
2308 | 509 |
2374 | 510 store |
2308 | 511 ; store our data byte |
2374 | 512 sta ,x+ ; store and increment buffer pointer |
513 | |
2308 | 514 ; adjust RxBufPut |
2374 | 515 cmpx RxBufEnd,u ; end of Rx buffer? |
516 blo IRQSkip1 ; no, go keep laydown pointer | |
517 ldx RxBufPtr,u ; get Rx buffer start address | |
518 IRQSkip1 stx RxBufPut,u ; set new Rx data laydown pointer | |
2308 | 519 |
520 ; increment RxDatLen | |
2374 | 521 inc RxDatLen,u |
2308 | 522 |
2374 | 523 CkSSig |
524 lda <SSigID,u ; send signal on data ready? | |
525 beq CkSuspnd | |
526 ldb <SSigSg,u ; else get signal code | |
527 os9 F$Send | |
528 clr <SSigID,u | |
529 bra IRQExit | |
2308 | 530 |
531 ; check if we have a process waiting for data | |
2374 | 532 CkSuspnd |
533 lda <V.WAKE,u ; V.WAKE? | |
534 beq IRQExit ; no | |
535 clr <V.WAKE,u ; clear V.WAKE | |
536 | |
2308 | 537 ; wake up waiter for read |
2374 | 538 ifeq Level-1 |
539 ldb #S$Wake | |
540 os9 F$Send | |
541 else | |
542 clrb | |
543 tfr d,x ; copy process descriptor pointer | |
544 lda P$State,x ; get state flags | |
545 anda #^Suspend ; clear suspend state | |
546 sta P$State,x ; save state flags | |
547 endc | |
2308 | 548 |
2374 | 549 IRQExit |
550 IRQExit2 puls cc,dp,pc ; restore interrupts cc,dp, return | |
2180 | 551 |
2374 | 552 emod |
553 eom equ * | |
554 end |