]> cloudbase.mooo.com Git - z180-stamp-cpm3.git/blob - cbios/ascii.180
RX/TX int: Improve register allocation. TX int: Simplify/optimize flag handling.
[z180-stamp-cpm3.git] / cbios / ascii.180
1
2 ; Interrupt drivers for ASCI0 and ASCI1
3
4 global as0_dev,as1_dev
5
6 extrn @ctbl,f_cpu
7 extrn ff_empty,ff_get,ff_full,ff_put
8 extrn ff_puth,ff_cnt,ff_gech
9 extrn bufinit
10 extrn isv_sw,ijphl,add_hla,div32_r
11 extrn b_st_a,b_ld_a
12
13
14
15 maclib z180reg.inc
16 maclib config.inc
17 maclib ioctl.inc
18 maclib modebaud.inc
19
20
21 m2b mbxon_bit,mb$xon$xoff
22
23 ;-----------------------------------------------------
24
25 dseg
26
27 dw asci0_out
28 dw asci0_osta
29 dw asci0_inp
30 dw asci0_ista
31 dw asci_ioctl
32 as0_dev:
33 db 0 ;absolute device #
34 db 0 ;relative device
35 db 0 ;iflags
36 db M_CREAD+M_CRTS_IFLOW+M_CCTS_OFLOW ;fflags
37 db M_CS8 ;cflags
38 o.absdev equ 0
39 o.reldev equ 1
40 o.iflags equ 2
41 o.fflags equ 3
42 o.cflags equ 4
43
44 db 0
45 o.stat equ 5
46 b2m SXOFF,0
47 b2m TDC1,1
48 b2m TDC3,2
49 db 0
50 oint.iflags equ as0_dev+o.iflags-s0.inbuf
51 oint.fflags equ as0_dev+o.fflags-s0.inbuf
52 oint.stat equ as0_dev+o.stat-s0.inbuf
53 mkbuf s0.rx_id, s0.inbuf, s0.rx_len
54 mkbuf s0.tx_id, s0.outbuf,s0.tx_len
55
56
57 dw asci1_out
58 dw asci1_osta
59 dw asci1_inp
60 dw asci1_ista
61 dw asci_ioctl
62 as1_dev:
63 db 0 ;absolute device #
64 db 1 ;relative device
65 db 0 ;iflags
66 db M_CREAD+M_IXOFF ;fflags
67 db M_CS8 ;cflags
68
69 db 0
70 db 0
71 mkbuf s1.rx_id, s1.inbuf, s1.rx_len
72 mkbuf s1.tx_id, s1.outbuf,s1.tx_len
73
74
75
76 dseg
77
78
79 ioctl_ftab:
80 dw func_tcinit ;(00h) CP/M 3 DEVINI function
81 dw func_tcgeta ;(01h) Get the current serial port settings.
82 dw func_tcseta ;(02h) Set the current serial port settings.
83 dw func_tcsetaw ;(03h) Allow the output buffer to drain
84 dw func_tcsetaf ;(04h) Allow the output buffer to drain, discard pending input
85 dw func_tcsbrk ;(05h) Sending a break (250ms .. 500ms)
86 dw func_tcsbrkp ;(06h) arg is timeinterval in 0.1sec
87 dw func_tiocsbrk ;(07h) Turn break on
88 dw func_tioccbrk ;(08h) Turn break off
89 dw func_tcxonc ;(09h) Software flow control (TCOOFF, TCOON, TCIOFF, TCION)
90 dw func_tcflsh ;(0Ah) Flush input/output buffer (TCIFLUSH, TCOFLUSH, TCIOFLUSH)
91 dw func_fionread ;(0Bh) Get the number of bytes in the input buffer.
92 dw func_tiocoutq ;(0Ch) Get the number of bytes in the output buffer.
93 dw func_tiocmget ;(0Dh) get the status of modem bits.
94 dw func_tiocmbis ;(0Eh) set the indicated modem bits.
95 dw func_tiocmbic ;(0Fh) clear the indicated modem bits.
96 dw func_tiocmset ;(10h) set the status of modem bits.
97 dw func_tiocgsoftcar ;(11h) Get the status of the CLOCAL flag in the c_cflag field
98 dw func_tiocssoftcar ;(12h) Set the CLOCAL flag when *argp is nonzero, and clear it otherwise.
99
100 IOCTL_MAX equ ($-ioctl_ftab)/2
101 dw nofunc
102
103
104 ;--------------------------------------------------------------
105 ;
106 ; b: device number
107 ; c: command
108 ; de: ioctl arg pointer
109 ; hl: ptr to driver local data
110 ;
111
112 asci_ioctl:
113 ld a,b
114 cp 1
115 jr nz,asioc_1
116 ld a,(inidone)
117 cp inidoneval
118 ret z
119 asioc_1:
120 push hl
121 ex (sp),ix
122 ld (ix+o.absdev),b
123 ld hl,ioctl_ftab
124 ld a,IOCTL_MAX
125 cp c
126 jr c,$+3
127 ld a,c
128 add a,a
129 call add_hla
130 ld a,(hl)
131 inc hl
132 ld h,(hl)
133 ld l,a
134 call ijphl
135 pop ix
136 nofunc:
137 or a
138 ret
139
140 ;--------------------------------------------------------------
141 ; CP/M 3 DEVINI function
142 ; Init Serial I/O for input and output (ASCI 0/1)
143
144 func_tcinit:
145 call asci_stop
146
147 init_st:
148 ld c,asext0 ;Enable baud rate generator
149 ld a,M_BRGMOD+M_DCD0DIS ; +M_CTS0DIS +M_BREAKEN
150 bit CCTS_OFLOW,(ix+o.fflags)
151 jr nz,$+4
152 or M_CTS0DIS
153 call out_asci_reg
154
155 ld b,(ix+o.absdev)
156 ld c,8 ;
157 mlt bc ;
158 ld hl,@ctbl+7 ;
159 add hl,bc ;
160 ld a,(hl) ;get baudrate index
161 call as_br_div
162 ld c,astc0l
163 call out_asci_reg_hl
164
165 ld c,cntlb0
166 ld a,M_MPBT ;No MP Mode, X16
167 bit PARODD,(ix+o.iflags)
168 jr z,$+4
169 or M_PEO
170 call out_asci_reg
171
172 ld c,cntla0
173 ld a,(ix+o.cflags)
174 srlan CS8
175 ld hl,mod_tab
176 call add_hla
177 ld a,(hl)
178 or a,M_RE+M_TE+M_RTS0+M_EFR ;Rx/Tx enable
179 call out_asci_reg
180
181 bit 0,(ix+o.reldev)
182 push ix
183 jr nz,init_1
184 ld hl,rtxisvjmp0 ;rx/tx int vector
185 ld (ivtab + IV$ASCI0),hl ;
186 ld ix,s0.outbuf
187 call bufinit
188 ld ix,s0.inbuf
189 jr init_2
190 init_1:
191 ld hl,rtxisvjmp1 ;rx/tx int vector
192 ld (ivtab + IV$ASCI1),hl ;
193 ld ix,s1.outbuf
194 call bufinit
195 ld ix,s1.inbuf
196 init_2:
197 call bufinit
198 pop ix
199 call asci_start
200 ret
201
202 ;--------------------------------------------------------------
203
204 mod_tab:
205 db 000B ; 7N1
206 db 100B ; 8N1
207 db 001B ; 7N2
208 db 101B ; 8N2
209 db 010B ; 7P1
210 db 110B ; 8P1
211 db 011B ; 7P2
212 db 111B ; 8P2
213
214
215 ;--------------------------------------------------------------
216 ; Get the current serial port settings.
217
218 func_tcgeta:
219 call chk_ptr
220
221 ld a,(ix+o.iflags)
222 call b_st_a
223 inc de
224 ld a,(ix+o.fflags)
225 call b_st_a
226 inc de
227
228 ld b,(ix+o.absdev)
229 ld c,8 ;
230 mlt bc ;
231 ld hl,@ctbl+7 ;
232 add hl,bc ;
233 ld a,(hl) ;get baudrate index
234 and M_CBAUD
235 ld b,a
236 ld a,(ix+o.cflags)
237 and ~M_CBAUD
238 or b
239 call b_st_a
240 dec de
241 dec de
242 xor a
243 ret
244
245 ;--------------------------------------------------------------
246 ; Set the current serial port settings.
247
248 func_tcseta:
249 call chk_ptr
250
251 call asci_stop
252
253 call b_ld_a
254 ld (ix+o.iflags),a
255 inc de
256 call b_ld_a
257 ld (ix+o.fflags),a
258 inc de
259
260 ld b,(ix+o.absdev)
261 ld c,8 ;
262 mlt bc ;
263 ld hl,@ctbl+7 ;
264 add hl,bc ;
265 call b_ld_a
266 ld (ix+o.cflags),a
267 and M_CBAUD
268 ld (hl),a ;set baudrate index
269 dec de
270 dec de
271 push de
272 call init_st
273 pop de
274 xor a
275 ret
276
277 ;--------------------------------------------------------------
278 ; Allow the output buffer to drain
279
280 func_tcsetaw:
281
282 ;--------------------------------------------------------------
283 ; Allow the output buffer to drain, discard pending input
284
285 func_tcsetaf:
286
287 ;--------------------------------------------------------------
288 ; Sending a break (250ms .. 500ms)
289
290 func_tcsbrk:
291
292 ;--------------------------------------------------------------
293 ; arg is timeinterval in 0.1sec
294
295 func_tcsbrkp:
296
297 ;--------------------------------------------------------------
298 ; Turn break on
299
300 func_tiocsbrk:
301
302 ;--------------------------------------------------------------
303 ; Turn break off
304
305 func_tioccbrk:
306
307 ;--------------------------------------------------------------
308 ; Software flow control (TCOOFF, TCOON, TCIOFF, TCION)
309
310 func_tcxonc:
311
312 ;--------------------------------------------------------------
313 ; Flush input/output buffer (TCIFLUSH, TCOFLUSH, TCIOFLUSH)
314
315 func_tcflsh:
316
317 ;--------------------------------------------------------------
318 ; Get the number of bytes in the input buffer.
319
320 func_fionread:
321
322 ;--------------------------------------------------------------
323 ; Get the number of bytes in the output buffer.
324
325 func_tiocoutq:
326
327 ;--------------------------------------------------------------
328 ; get the status of modem bits.
329
330 func_tiocmget:
331
332 ;--------------------------------------------------------------
333 ; set the indicated modem bits.
334
335 func_tiocmbis:
336
337 ;--------------------------------------------------------------
338 ; clear the indicated modem bits.
339
340 func_tiocmbic:
341
342 ;--------------------------------------------------------------
343 ; set the status of modem bits.
344
345 func_tiocmset:
346
347 ;--------------------------------------------------------------
348 ; Get the status of the CLOCAL flag in the c_cflag field
349
350 func_tiocgsoftcar:
351
352 ;--------------------------------------------------------------
353 ; Set the CLOCAL flag when *argp is nonzero, and clear it otherwise.
354
355 func_tiocssoftcar:
356
357 or 0ffh
358 ret
359
360 ;--------------------------------------------------------------
361
362 chk_ptr:
363 ld a,e
364 or d
365 ret nz
366 cpl
367 pop hl
368 ret
369
370 ;--------------------------------------------------------------
371
372 asci_stop:
373 ld c,stat0 ;Disable rx/tx interrupts
374 xor a ;
375 call out_asci_reg
376
377 ld c,cntla0 ;Disable receiver and transmitter
378 ld a,M_RTS0+M_EFR ;RTS/CKA1
379 jr out_asci_reg
380
381 ;--------------------------------------------------------------
382
383 asci_start:
384 bit 0,(ix+o.reldev)
385 jr nz,asci_st1
386 in0 a,cntla0 ;asci0
387 and ~M_RTS0 ;Activate RTS
388 or M_EFR
389 out0 (cntla0),a
390 asci_st1:
391 ld c,stat0 ;
392 ld a,M_RIE
393 jr out_asci_reg
394
395 ;--------------------------------------------------------------
396 ; output to asci0/1 register
397 ;
398 ; c: register address
399 ; a: value
400 ;
401
402 out_asci_reg:
403 push bc
404 bit 0,(ix+o.reldev)
405 jr z,$+3
406 inc c
407 ld b,0
408 out (c),a
409 pop bc
410 ret
411
412 ;--------------------------------------------------------------
413 ; output 16 bit value to asci0/1 register
414 ;
415 ; c: register address
416 ; hl: value
417 ; a destroyed
418
419 out_asci_reg_hl:
420 ld a,b ;save b
421 bit 0,(ix+o.reldev)
422 jr z,$+4
423 inc c
424 inc c
425 ld b,0
426 out (c),l
427 inc c
428 out (c),h
429 ld b,a
430 ret
431
432 ;--------------------------------------------------------------
433 ; baud rate divider
434 ;
435 ; a: index
436 ; return
437 ; hl: divider
438
439 as_br_div:
440 push de
441 push bc
442 and 0fh
443 add a,a ;get factor
444 ld hl,bd150_tab
445 call add_hla
446 ld c,(hl)
447 inc hl
448 ld b,(hl)
449 ld hl,(f_cpu)
450 ld de,(f_cpu+2)
451 call div32_r
452 ld bc,32*150
453 call div32_r
454 ld de,2
455 or a
456 sbc hl,de
457 pop bc
458 pop de
459 ret nc
460 ld hl,0
461 ret
462
463 bd150_tab:
464 ; factor index baudrate orig. cp/m
465 dw 19200/150 ; 0 19200 -
466 dw 28800/150 ; 1 28800 50
467 dw 38400/150 ; 2 38400 75
468 dw 57600/150 ; 3 57600 110
469 dw 11520/15 ; 4 115200 134.5
470 dw 150/150 ; 5 150
471 dw 300/150 ; 6 300
472 dw 600/150 ; 7 600
473 dw 1200/150 ; 8 1200
474 dw 1800/150 ; 9 1800
475 dw 2400/150 ;10 2400
476 dw 3600/150 ;11 3600
477 dw 4800/150 ;12 4800
478 dw 7200/150 ;13 7200
479 dw 9600/150 ;14 9600
480 dw 19200/150 ;15 19200
481
482
483 ;--------------------------------------------------------------
484
485 if 0
486
487 initab0:
488 db 1,stat0,0 ;Disable rx/tx interrupts
489 ;Enable baud rate generator
490 db 1,asext0,M_BRGMOD+M_DCD0DIS ; +M_CTS0DIS
491 db 2,astc0l
492 init_br_off equ $ - initab0
493 dw 28
494 db 1,cntlb0,M_MPBT ;No MP Mode, X16
495 db 1,cntla0,M_RE+M_TE+M_MOD2 ;Rx/Tx enable, 8N1
496 db 0
497
498 initab1:
499 db 1,stat1,0 ;Disable rx/tx ints, disable CTS1
500 db 1,asext1,M_BRGMOD ;Enable baud rate generator
501 db 2,astc1l,low 3, high 3
502 db 1,cntlb1,M_MPBT ;No MP Mode, X16
503 db 1,cntla1,M_RE+M_TE+M_MOD2 ;Rx/Tx enable, 8N1
504 db 0
505 endif
506
507 ;--------------------------------------------------------------
508
509 dseg
510 asci0_ista:
511 push ix
512 ld ix,s0.inbuf ;
513 call ff_empty
514 pop ix
515 ret
516
517 ;--------------------------------------------------------------
518
519 asci1_ista:
520 push ix
521 ld ix,s1.inbuf ;
522 call ff_empty
523 pop ix
524 ret
525
526 ;--------------------------------------------------------------
527 ; Get an input character
528
529 if 0
530 asci0_inp:
531 push ix
532 ld ix,s0.inbuf ;
533 call ff_cnt
534 cp 32
535 jr nc,a0i_1
536 di
537 in0 a,(cntla0)
538 res RTS0,a
539 set EFR,a
540 out0 (cntla0),a
541 ei
542 a0i_1:
543 call ff_get
544 pop ix
545 ret
546 endif
547
548
549 asci0_inp:
550 push ix
551 ld ix,s0.inbuf ;
552 call ff_gech
553 ld a,b ;remaining chrs in buffer
554 cp s0.rx_len/4 ; < 32?
555 jr nc,a0i_2 ; no, just get char
556 ld b,(ix+oint.fflags) ; yes, enable RTS if needed
557 bit CRTS_IFLOW,b ; yes, enable RTS if needed
558 jr z,a0i_1 ; no needed
559 di ; needed, enable
560 in0 a,(cntla0)
561 and ~M_RTS0 ;assert RTS
562 or M_EFR ;don't reset error flags
563 ei
564 out0 (cntla0),a
565 a0i_1:
566 bit IXOFF,b ; XON/XOFF on input?
567 jr z,a0i_2 ; no
568 di
569 set TDC1,(ix+oint.stat) ;
570 in0 a,(stat0) ;
571 or M_TIE ;
572 ei
573 out0 (stat0),a ;
574 a0i_2:
575 ld a,c
576 pop ix
577 ret
578
579 ;--------------------------------------------------------------
580 ; Get an input character
581
582 asci1_inp:
583 push ix
584 ld ix,s1.inbuf ;
585 call ff_gech
586 ld a,b ; remaining chars in buffer
587 cp s0.rx_len/4 ; == 25% full?
588 jr nz,a1i_2 ; no, just get char
589 bit IXOFF,(ix+oint.fflags) ; XON/XOFF on input?
590 jr z,a1i_2 ; no
591 di
592 set TDC1,(ix+oint.stat) ;
593 in0 a,(stat1) ;
594 or M_TIE ;
595 out0 (stat1),a ;
596 ei
597 a1i_2:
598 ld a,c ; get back the char
599 pop ix
600 ret
601
602 ;--------------------------------------------------------------
603 ; Output status
604
605 asci0_osta:
606 push ix
607 ld ix,s0.outbuf ;
608 call ff_full
609 pop ix
610 ret
611
612 ;--------------------------------------------------------------
613 ; Output status
614
615 asci1_osta:
616 push ix
617 ld ix,s1.outbuf ;
618 call ff_full
619 pop ix
620 ret
621
622 ;--------------------------------------------------------------
623 ; put character in c in buffer
624 ; destroys hl, bc
625 ; returns output char in a
626
627 asci0_out:
628 push ix ;
629 ld ix,s0.outbuf ;
630 call ff_puth
631 pop ix ;
632 di ;
633 in0 c,(stat0) ;
634 set TIE,c ;
635 out0 (stat0),c ;
636 ei ;
637 ret
638
639 ;--------------------------------------------------------------
640 ; put character in c in buffer
641 ; destroys hl, bc
642 ; returns output char in a
643
644 asci1_out:
645 push ix ;
646 ld ix,s1.outbuf ;
647 call ff_puth
648 pop ix ;
649 di ;
650 in0 c,(stat1) ;
651 set TIE,c ;
652 out0 (stat1),c ;
653 ei ;
654 ret
655
656
657 ;--------------------------------------------------------------
658
659 cseg
660 rtxisvjmp0:
661 call isv_sw
662 dw asci0_int
663
664 rtxisvjmp1:
665 call isv_sw
666 dw asci1_int
667
668 ;--------------------------------------------------------------
669 ; ASCI 0/1 Transmit/Receive interupt routines
670
671 .lall
672 asci_int macro dev
673 local rxi_2,rxi_3
674
675 push ix
676 ld ix,s&dev&.inbuf ;
677 ld d,(ix+oint.fflags)
678 rxtxi&dev&_lp1:
679 in0 e,(stat&dev) ;get asci status
680 jp p,txi&dev ;RDRF == Bit 7
681
682 ; RX Interrupt
683
684 res BREAK,e
685 in0 a,(asext&dev) ;get break status
686 and M_BREAK
687 or e ;merge to other error flags
688 ld e,a
689
690 in0 a,(cntla&dev) ;reset all error flags
691 and ~M_EFR ;
692 out0 (cntla&dev),a ;
693
694 ld c,(ix+o.in_idx) ;input buffer pointer
695 ld b,0
696 ld hl,s&dev&.inbuf ;
697 add hl,bc
698
699 in0 b,(rdr&dev) ;get char
700 ;todo: break detection
701 ;todo: parity, framing, overrun error
702 ld (hl),b
703
704 ; bit IXON,d
705 ; jr z,rxi_2
706 ;todo: test XON/XOFF
707 rxi_2:
708
709 ld a,c ;increment buffer in pointer
710 inc a ;
711 ld b,(ix+o.mask) ;
712 and b ;
713 ld c,a
714
715 sub (ix+o.out_idx) ;
716 jr z,rxtxi&dev&_lp1 ;skip if buffer is full
717
718 ld (ix+o.in_idx),c ;input buffer pointer
719
720 jr nc,$+3 ;
721 adc b ;
722
723 cp s&dev&.tx_len*3/4
724 jr nz,rxtxi&dev&_lp1
725
726 if dev=0 ; only channel 0 has rts line
727 bit CRTS_IFLOW,d
728 jr z,rxi0_nocrts
729
730 in0 a,(cntla&dev) ;reset all error flags
731 or M_RTS0+M_EFR ;RTS inactive
732 out0 (cntla0),a ;
733 rxi0_nocrts:
734 endif
735
736 bit IXOFF,d
737 jr z,rxtxi&dev&_lp1
738 ;send XOFF
739 set TDC3,(ix+oint.stat)
740 set TIE,e ;
741 out0 (stat&dev),e ;
742 jr rxtxi&dev&_lp1
743
744 txi&dev:
745 bit TDRE,e ;TX int?
746 jr z,rxtxi&dev&_exit
747
748 ; TX Interrupt
749
750 ld a,(ix+oint.stat) ;check if xon/xoff should be sent
751 tst M_TDC1+M_TDC3 ;
752 jr z,txi&dev&_char ; no
753
754 ld l,DC3 ;prepare for xoff
755 bit TDC1,a ;request for xon (also) set?
756 jr z,txi&dev&_cch ;
757 ld l,DC1 ;
758 txi&dev&_cch:
759 out0 (tdr&dev),l ;
760 and ~(M_TDC1+M_TDC3) ;reset request flags
761 ld (ix+oint.stat),a ;
762 jp rxtxi&dev&_lp1 ;
763
764 txi&dev&_char:
765 ld hl,s&dev&.outbuf+o.in_idx ;[in]
766 ld a,(hl) ;
767 inc hl ;[out]
768 ld c,(hl) ;
769 cp c ;
770 jr z,txi&dev&_empty ;
771 inc hl ;fifo base
772 ld b,0 ;
773 add hl,bc ;
774 ld a,(hl) ;
775 out0 (tdr&dev),a ;
776 inc c ;
777 ld a,(s&dev&.outbuf+o.mask) ;
778 and c ;
779 ld (s&dev&.outbuf+o.out_idx),a ;
780
781 jp rxtxi&dev&_lp1
782
783 txi&dev&_empty:
784 res TIE,e ;disable tx-int
785 out0 (stat&dev),e ; 5
786
787 rxtxi&dev&_exit:
788 pop ix
789 ret
790 endm
791
792 dseg
793 ;--------------------------------------------------------------
794 ; ASCI 0 Transmit/Receive interupt routines
795
796 asci0_int:
797 asci_int 0
798
799 ;--------------------------------------------------------------
800 ; ASCI 1 Transmit/Receive interupt routines
801
802 asci1_int:
803 asci_int 1
804
805 end