2534
|
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
|