; Interrupt drivers for ASCI0 and ASCI1 global as0_dev,as1_dev extrn @ctbl,f_cpu extrn ff_empty,ff_get,ff_full,ff_put extrn ff_puth,ff_cnt,ff_gech extrn bufinit extrn isv_sw,ijphl,add_hla,div32_r extrn b_st_a,b_ld_a maclib z180reg.inc maclib config.inc maclib ioctl.inc maclib modebaud.inc m2b mbxon_bit,mb$xon$xoff ;----------------------------------------------------- dseg dw asci0_out dw asci0_osta dw asci0_inp dw asci0_ista dw asci_ioctl as0_dev: db 0 ;absolute device # db 0 ;relative device db 0 ;iflags db M_CREAD+M_CRTS_IFLOW+M_CCTS_OFLOW ;fflags db M_CS8 ;cflags o.absdev equ 0 o.reldev equ 1 o.iflags equ 2 o.fflags equ 3 o.cflags equ 4 db 0 db 0 oint.iflags equ as0_dev+o.iflags-s0.inbuf oint.fflags equ as0_dev+o.fflags-s0.inbuf mkbuf s0.rx_id, s0.inbuf, s0.rx_len mkbuf s0.tx_id, s0.outbuf,s0.tx_len dw asci1_out dw asci1_osta dw asci1_inp dw asci1_ista dw asci_ioctl as1_dev: db 0 ;absolute device # db 1 ;relative device db 0 ;iflags db M_CREAD ;fflags db M_CS8 ;cflags db 0 db 0 mkbuf s1.rx_id, s1.inbuf, s1.rx_len mkbuf s1.tx_id, s1.outbuf,s1.tx_len dseg ioctl_ftab: dw func_tcinit ;(00h) CP/M 3 DEVINI function dw func_tcgeta ;(01h) Get the current serial port settings. dw func_tcseta ;(02h) Set the current serial port settings. dw func_tcsetaw ;(03h) Allow the output buffer to drain dw func_tcsetaf ;(04h) Allow the output buffer to drain, discard pending input dw func_tcsbrk ;(05h) Sending a break (250ms .. 500ms) dw func_tcsbrkp ;(06h) arg is timeinterval in 0.1sec dw func_tiocsbrk ;(07h) Turn break on dw func_tioccbrk ;(08h) Turn break off dw func_tcxonc ;(09h) Software flow control (TCOOFF, TCOON, TCIOFF, TCION) dw func_tcflsh ;(0Ah) Flush input/output buffer (TCIFLUSH, TCOFLUSH, TCIOFLUSH) dw func_fionread ;(0Bh) Get the number of bytes in the input buffer. dw func_tiocoutq ;(0Ch) Get the number of bytes in the output buffer. dw func_tiocmget ;(0Dh) get the status of modem bits. dw func_tiocmbis ;(0Eh) set the indicated modem bits. dw func_tiocmbic ;(0Fh) clear the indicated modem bits. dw func_tiocmset ;(10h) set the status of modem bits. dw func_tiocgsoftcar ;(11h) Get the status of the CLOCAL flag in the c_cflag field dw func_tiocssoftcar ;(12h) Set the CLOCAL flag when *argp is nonzero, and clear it otherwise. IOCTL_MAX equ ($-ioctl_ftab)/2 dw nofunc ;-------------------------------------------------------------- ; ; b: device number ; c: command ; de: ioctl arg pointer ; hl: ptr to driver local data ; asci_ioctl: ld a,b cp 1 jr nz,asioc_1 ld a,(INIDONE) and 80h cp INIDONEVAL ret z asioc_1: push hl ex (sp),ix ld (ix+o.absdev),b ld hl,ioctl_ftab ld a,IOCTL_MAX cp c jr c,$+3 ld a,c add a,a call add_hla ld a,(hl) inc hl ld h,(hl) ld l,a call ijphl pop ix nofunc: or a ret ;-------------------------------------------------------------- ; CP/M 3 DEVINI function ; Init Serial I/O for input and output (ASCI 0/1) func_tcinit: call asci_stop init_st: ld c,asext0 ;Enable baud rate generator ld a,M_BRGMOD+M_DCD0DIS ; +M_CTS0DIS +M_BREAKEN bit CCTS_OFLOW,(ix+o.fflags) jr nz,$+4 or M_CTS0DIS call out_asci_reg ld b,(ix+o.absdev) ld c,8 ; mlt bc ; ld hl,@ctbl+7 ; add hl,bc ; ld a,(hl) ;get baudrate index call as_br_div ld c,astc0l call out_asci_reg_hl ld c,cntlb0 ld a,M_MPBT ;No MP Mode, X16 bit PARODD,(ix+o.iflags) jr z,$+4 or M_PEO call out_asci_reg ld c,cntla0 ld a,(ix+o.cflags) srlan CS8 ld hl,mod_tab call add_hla ld a,(hl) or a,M_RE+M_TE+M_RTS0+M_EFR ;Rx/Tx enable call out_asci_reg push ix bit 0,(ix+o.reldev) jr nz,init_1 ld hl,rtxisvjmp0 ;rx/tx int vector ld (ivtab + IV$ASCI0),hl ; ld ix,s0.outbuf call bufinit ld ix,s0.inbuf jr init_2 init_1: ld hl,rtxisvjmp1 ;rx/tx int vector ld (ivtab + IV$ASCI1),hl ; ld ix,s1.outbuf call bufinit ld ix,s1.inbuf init_2: call bufinit pop ix call asci_start ret ;-------------------------------------------------------------- mod_tab: db 000B ; 7N1 db 100B ; 8N1 db 001B ; 7N2 db 101B ; 8N2 db 010B ; 7P1 db 110B ; 8P1 db 011B ; 7P2 db 111B ; 8P2 ;-------------------------------------------------------------- ; Get the current serial port settings. func_tcgeta: call chk_ptr ld a,(ix+o.iflags) call b_st_a inc de ld a,(ix+o.fflags) call b_st_a inc de ld b,(ix+o.absdev) ld c,8 ; mlt bc ; ld hl,@ctbl+7 ; add hl,bc ; ld a,(hl) ;get baudrate index and M_CBAUD ld b,a ld a,(ix+o.cflags) and ~M_CBAUD or b call b_st_a dec de dec de xor a ret ;-------------------------------------------------------------- ; Set the current serial port settings. func_tcseta: call chk_ptr call asci_stop call b_ld_a ld (ix+o.iflags),a inc de call b_ld_a ld (ix+o.fflags),a inc de ld b,(ix+o.absdev) ld c,8 ; mlt bc ; ld hl,@ctbl+7 ; add hl,bc ; call b_ld_a ld (ix+o.cflags),a and M_CBAUD ld (hl),a ;set baudrate index dec de dec de push de call init_st pop de xor a ret ;-------------------------------------------------------------- ; Allow the output buffer to drain func_tcsetaw: ;-------------------------------------------------------------- ; Allow the output buffer to drain, discard pending input func_tcsetaf: ;-------------------------------------------------------------- ; Sending a break (250ms .. 500ms) func_tcsbrk: ;-------------------------------------------------------------- ; arg is timeinterval in 0.1sec func_tcsbrkp: ;-------------------------------------------------------------- ; Turn break on func_tiocsbrk: ;-------------------------------------------------------------- ; Turn break off func_tioccbrk: ;-------------------------------------------------------------- ; Software flow control (TCOOFF, TCOON, TCIOFF, TCION) func_tcxonc: ;-------------------------------------------------------------- ; Flush input/output buffer (TCIFLUSH, TCOFLUSH, TCIOFLUSH) func_tcflsh: ;-------------------------------------------------------------- ; Get the number of bytes in the input buffer. func_fionread: ;-------------------------------------------------------------- ; Get the number of bytes in the output buffer. func_tiocoutq: ;-------------------------------------------------------------- ; get the status of modem bits. func_tiocmget: ;-------------------------------------------------------------- ; set the indicated modem bits. func_tiocmbis: ;-------------------------------------------------------------- ; clear the indicated modem bits. func_tiocmbic: ;-------------------------------------------------------------- ; set the status of modem bits. func_tiocmset: ;-------------------------------------------------------------- ; Get the status of the CLOCAL flag in the c_cflag field func_tiocgsoftcar: ;-------------------------------------------------------------- ; Set the CLOCAL flag when *argp is nonzero, and clear it otherwise. func_tiocssoftcar: or 0ffh ret ;-------------------------------------------------------------- chk_ptr: ld a,e or d ret nz cpl pop hl ret ;-------------------------------------------------------------- asci_stop: ld c,stat0 ;Disable rx/tx interrupts xor a ; call out_asci_reg ld c,cntla0 ;Disable receiver and transmitter ld a,M_RTS0+M_EFR ;RTS/CKA1 jr out_asci_reg ;-------------------------------------------------------------- asci_start: ld c,stat0 ; ld a,M_RIE jr out_asci_reg ;-------------------------------------------------------------- ; output to asci0/1 register ; ; c: register address ; a: value ; out_asci_reg: push bc bit 0,(ix+o.reldev) jr z,$+3 inc c ld b,0 out (c),a pop bc ret ;-------------------------------------------------------------- ; output 16 bit value to asci0/1 register ; ; c: register address ; hl: value ; a destroyed out_asci_reg_hl: ld a,b ;save b bit 0,(ix+o.reldev) jr z,$+4 inc c inc c ld b,0 out (c),l inc c out (c),h ld b,a ret ;-------------------------------------------------------------- ; baud rate divider ; ; a: index ; return ; hl: divider as_br_div: push de push bc and 0fh add a,a ;get factor ld hl,bd150_tab call add_hla ld c,(hl) inc hl ld b,(hl) ld hl,(f_cpu) ld de,(f_cpu+2) call div32_r ld bc,32*150 call div32_r ld de,2 or a sbc hl,de pop bc pop de ret nc ld hl,0 ret bd150_tab: ; factor index baudrate orig. cp/m dw 19200/150 ; 0 19200 - dw 28800/150 ; 1 28800 50 dw 38400/150 ; 2 38400 75 dw 57600/150 ; 3 57600 110 dw 11520/15 ; 4 115200 134.5 dw 150/150 ; 5 150 dw 300/150 ; 6 300 dw 600/150 ; 7 600 dw 1200/150 ; 8 1200 dw 1800/150 ; 9 1800 dw 2400/150 ;10 2400 dw 3600/150 ;11 3600 dw 4800/150 ;12 4800 dw 7200/150 ;13 7200 dw 9600/150 ;14 9600 dw 19200/150 ;15 19200 ;-------------------------------------------------------------- if 0 initab0: db 1,stat0,0 ;Disable rx/tx interrupts ;Enable baud rate generator db 1,asext0,M_BRGMOD+M_DCD0DIS ; +M_CTS0DIS db 2,astc0l init_br_off equ $ - initab0 dw 28 db 1,cntlb0,M_MPBT ;No MP Mode, X16 db 1,cntla0,M_RE+M_TE+M_MOD2 ;Rx/Tx enable, 8N1 db 0 initab1: db 1,stat1,0 ;Disable rx/tx ints, disable CTS1 db 1,asext1,M_BRGMOD ;Enable baud rate generator db 2,astc1l,low 3, high 3 db 1,cntlb1,M_MPBT ;No MP Mode, X16 db 1,cntla1,M_RE+M_TE+M_MOD2 ;Rx/Tx enable, 8N1 db 0 endif ;-------------------------------------------------------------- dseg asci0_ista: push ix ld ix,s0.inbuf ; call ff_empty pop ix ret ;-------------------------------------------------------------- asci1_ista: push ix ld ix,s1.inbuf ; call ff_empty pop ix ret ;-------------------------------------------------------------- ; Get an input character asci0_inp: push ix ld ix,s0.inbuf ; call ff_gech ld a,b cp s0.rx_len/4 jr nc,a0i_1 bit CRTS_IFLOW,(ix+oint.fflags) jr z,a0i_1 di in0 a,(cntla0) and ~M_RTS0 ;assert RTS or M_EFR ;don't reset error flags ei out0 (cntla0),a a0i_1: ld a,c pop ix ret ;-------------------------------------------------------------- ; Get an input character asci1_inp: push ix ld ix,s1.inbuf ; call ff_gech pop ix ret ;-------------------------------------------------------------- ; Output status asci0_osta: push ix ld ix,s0.outbuf ; call ff_full pop ix ret ;-------------------------------------------------------------- ; Output status asci1_osta: push ix ld ix,s1.outbuf ; call ff_full pop ix ret ;-------------------------------------------------------------- ; put character in c in buffer ; destroys hl, bc ; returns output char in a asci0_out: push ix ; ld ix,s0.outbuf ; call ff_puth pop ix ; di ; in0 c,(stat0) ; set TIE,c ; out0 (stat0),c ; ei ; ret ;-------------------------------------------------------------- ; put character in c in buffer ; destroys hl, bc ; returns output char in a asci1_out: push ix ; ld ix,s1.outbuf ; call ff_puth pop ix ; di ; in0 c,(stat1) ; set TIE,c ; out0 (stat1),c ; ei ; ret ;-------------------------------------------------------------- cseg rtxisvjmp0: call isv_sw dw asci0_int rtxisvjmp1: call isv_sw dw asci1_int ;-------------------------------------------------------------- ; ASCI 0/1 Transmit/Receive interupt routines .lall asci_int macro dev local rxi_2,rxi_4 push ix rxtxi&dev&_lp0: ld ix,s&dev&.inbuf ; rxtxi&dev&_lp1: in0 a,(stat&dev) ;receive flag set? jp p,txi&dev ;RDRF == Bit 7 and M_OVRN+M_PERR+M_FE ld e,a in0 a,(asext&dev) and M_BREAK or e ld e,a in0 d,(cntla&dev) ; res EFR,d ; out0 (cntla&dev),d ld c,(ix+o.in_idx) ; ld b,0 ld hl,s&dev&.inbuf ; add hl,bc in0 a,(rdr&dev) ; ld (hl),a ;todo: break detection ;todo: parity, framing overrun error ld e,(ix+oint.fflags) bit IXON,e jr z,rxi_2 ;todo: test XON/XOFF rxi_2: ld a,c ;increment buffer in pointer inc a ; ld b,(ix+o.mask) ; and b ; ld c,a sub (ix+o.out_idx) ; jr z,rxtxi&dev&_lp1 ;skip if buffer is full ld (ix+o.in_idx),c ; jr nc,$+3 ; adc b ; cp s&dev&.tx_len*3/4 jr c,rxi&dev&_noflow if dev=0 bit CRTS_IFLOW,e jr z,rxi_4 set EFR,d set RTS0,d ;RTS inactive out0 (cntla&dev),d ; endif rxi_4: bit IXOFF,e jr z,rxtxi&dev&_lp1 ;todo: send XOFF rxi&dev&_noflow: jr rxtxi&dev&_lp1 txi&dev: ld e,a bit TDRE,e ;TX int? jr z,rxtxi&dev&_exit ;todo: xon/xoff ld hl,s&dev&.outbuf+o.in_idx ;[in] ld a,(hl) ; inc hl ;[out] ld c,(hl) ; cp c ; jr z,txi&dev&_empty ; inc hl ;fifo base ld b,0 ; add hl,bc ; ld a,(hl) ; out0 (tdr&dev),a ; inc c ; ld a,(s&dev&.outbuf+o.mask) ; and c ; ld (s&dev&.outbuf+o.out_idx),a ; jr rxtxi&dev&_lp0 txi&dev&_empty: res TIE,e ;disable tx-int out0 (stat&dev),e ; 5 rxtxi&dev&_exit: pop ix ret endm dseg ;-------------------------------------------------------------- ; ASCI 0 Transmit/Receive interupt routines asci0_int: asci_int 0 ;-------------------------------------------------------------- ; ASCI 1 Transmit/Receive interupt routines asci1_int: asci_int 1 end