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