comparison level1/modules/dw3mess.asm @ 2534:c92a6c65bbd9

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