title 'XUTIL.ASM' ;************************************************ ;* * ;* XUTIL.ASM * ;* * ;* General purpose utility routines for X.25 * ;* protocol interface program * ;* * ;* rev 0.16 08/21/84 E. Elizondo * ;* * ;* (c) 1984 E. Elizondo - all rights reserved. * ;* * ;* This program may be used freely for non- * ;* commercial applications. It may not be sold * ;* or used for commercial applications without * ;* written permission of the author. * ;* * ;************************************************ ; maclib Z80 ;DR Z80 macro library ; subroutine entry points public ilprt ;in-line print routine public ctype ;output char to console and printer public cview ;output char to console only public move ;move block of data public decbin ;convert decimal ASCII to binary public hexbin ;convert hex ASCII digit to binary public pdec ;print binary number in ASCII decimal public pbin ;print byte in binary public phex ;print byte in hex public phex1 ;print nibble in hex public disptch ;dispatch routine public instr ;input string from console public poll ;poll console & printer public delay ;wait a bit ; address hooks public inbuf ;console input buffer public prnflg ;printer ena/dis flag ; external subroutines extrn putbuf ;put byte into a fifo buffer extrn getbuf ;get byte from a fifo buffer ; external addresses extrn cibcb ;A(console input buffer) extrn cobcb ;A(console output buffer) extrn pobcb ;A(printer buffer) ; standard ASCII equates bell equ 07h tab equ 09h cr equ 0dh lf equ 0ah esc equ 1bh ; CP/M BDOS function equates conotf equ 2 ;console output function listf equ 5 ;list output function diriof equ 6 ;direct console I/O frcbuf equ 10 ;read edited input line ; CP/M address equates: fcb equ 005ch ;default file control block bdos equ 0005h ;BDOS entry address cseg ;code section ; in-line print routine ; on entry: text to be printed follows call ; to this routine, and is ; terminated by a 0 ; on exit: , flags clobbered ; all other registers unchanged ; routine returns to instruction ; immediately following message ; ilprt: xthl ;point to first byte of msg ilplp: mov a,m ;get byte ora a ;terminator? jz ilpret ;yes, exit ; call ctype ;else output character inx h ;bump pointer jmp ilplp ;and go back for more ; ilpret: inx h ;bump past terminator xthl ;put next address on stack ret ;and go there ; output character in to console buffer ; and to printer buffer if printer enabled ; on entry: = character ; on exit: all flags, regs unchanged ; ctype: push psw ;save regs push h ; / push d ; / push b ; / mov b,a ;save char in lxi h,cobcb ;point to console output buffer call putbuf ;and write it there lda prnflg ;get print flag ora a ;printer enabled? jz ctyexi ;no, exit ; mov a,b ;get back byte lxi h,pobcb ;point to printer output buffer call putbuf ;write char there ; ; common exit ctyexi: call copol ;poll crt output pop b ;restore regs pop d ; / pop h ; / pop psw ; / ret ; output character in to console buffer (only) ; (used for clearing crt screen, end of line, etc) ; on entry: = character ; on exit: all flags, regs unchanged ; cview: push psw ;save regs push h ; / push d ; / push b ; / lxi h,cobcb ;point to console output buffer call putbuf ;and write it there call copol ;poll crt output pop b ;restore regs pop d ; / pop h ; / pop psw ; / ret ; general purpose move routine ; (internally and externally called) ; on entry: =source address ; =destination address ; =number of bytes to move ; on exit: =last source address+1 ; =last dest address+1 ; =0 move: ldir ret ; dispatch routine ; on entry: =offset into table (0-127) ; table of addresses follows calling routine ; on exit: ,flags clobbered ; all other regs unchanged ; disptch: rlc ;double the offset bits xthl ;save hl, get adress of table push d ;save de mov e,a ;put doubled code in e mvi d,0 ;and clear d dad d ;offset into table mov a,m ;get low byte of destination inx h ;and now high byte mov h,m ;high byte into h mov l,a ;and low byte into l pop d ;restore de xthl ;put dest address on stack, restore hl ret ;dispatch to destination ; get edited console string ; on entry: no parameters ; on exit: all regs unchanged ; console string is in inbuf instr: push b push d push h mvi c,frcbuf lxi d,inbuf call bdos pop h pop d pop b ret ; convert ASCII decimal number in input buffer to binary ; on entry: no parameters ; on exit: =binary number ; carry set if conversion error ; decbin: push h ;save regs push b ; / lxi d,0 ;clear binary number lxi h,inbuf+1 ;=A(# of input characters) mov b,m ;,=# of input characters mov a,b ; / ora a ;no input? jz addexi ;yes, return with =0 ; dbloop: inx h ;get a digit mov a,m ; / sui '0' ;convert to binary jc addexi ;return with carry if <0 ; cpi 10 ;or if >9 cmc ; / jc addexi ; / ; ora a ;=0? jz nxtdig ;yes, get next digit ; adddig: inx d ;else add digit in to dcr a ; / jnz adddig ; / ; nxtdig: dcr b ;last digit? jz addexi ;yes, normal exit ; push h ;else save lxi h,0 ;clear mvi c,10 ;and multiply by 10 mult10: dad d ; / dcr c ; / jnz mult10 ; / ; xchg ;restore number to pop h ;restore jmp dbloop ;and get next digit ; addexi: pop b ;restore regs pop h ; / ret ; convert ASCII hex digit to binary ; (externally called) ; on entry: = hex digit ; on exit: = binary equivalent ; carry set if conversion error ; other flags clobbered ; all other regs unchanged hexbin: sui '0' ;subtract ASCII bias rc ;error if <0 ; cpi 10 ;is it <10? cmc ;yes, return with value rnc ; / ; ani 0101$1111b ;convert to upper case cpi 'G'-'0' ;is it >F? cmc ;yes, return with carry rc ; / ; sui 'A'-'9'-1 ;else adjust A-F cpi 10 ;set carry if not >10 ret ; print binary number in ASCII ; on entry: =binary number ; on exit: ,flags clobbered ; all other regs unchanged pdec: push h ;save regs push d ; / push b ; / lxi d,numbuf ;point to number buffer call bindec ;convert # to ASCII lxi h,numbuf ;point to number buffer mvi b,4 ;max # of leading zeros mvi a,'0' ;blank leading zeros blnklp: cmp m ;is char a zero? jnz pdec1 ;no, all finished ; mvi m,' ' ;yes, blank it inx h ;bump pointer dcr b ;last leading zero? jnz blnklp ;no, keep going ; pdec1: call ilprt ;print it numbuf: db '00000',0 pop b ;restore regs pop d ; / pop h ; / ret ; convert binary number 0-65535 to decimal ASCII ; (internally called) ; on entry: =binary number ; =address of buffer to put ASCII digits ; on exit: buffer contains ASCII number ; terminated by binary 0 ; regs, flags clobbered bindec: lxi b,-10000 ;digit value call cdigit ;convert first digit lxi b,-1000 ;convert next digit call cdigit ; / lxi b,-100 ;convert next digit call cdigit ; / lxi b,-10 ;convert next digit call cdigit ; / lxi b,-1 ;convert last digit call cdigit ; / mvi a,0 ;put terminator in buffer stax d ; / ret ; convert a digit cdigit: mvi a,'0'-1 ;initialize ASCII value push d ;save buffer pointer cdloop: mov e,l ;save last iteration mov d,h ; / inr a ;increment ASCII digit dad b ;subtract value jc cdloop ;repeat till underflow ; mov l,e ;get previous iteration mov h,d ; / pop d ;restore buffer pointer stax d ;store byte in buffer inx d ;bump pointer ret ; print byte in binary '1''s and '0''s ; (clever routine adapted from TDL) ; on entry: =byte ; on exit: ,flags clobbered ; all other regs unchanged pbin: push b ;save mvi b,8 ;# of bits to output pbit: ral ;move msb to carry push psw ;sabe byte mvi a,'0'/2 ;make '0' or '1' adc a ; / call ctype ;output char pop psw ;restore byte dcr b ;last bit? jnz pbit ;no, keep going ; pop b ;else restore ret ; print byte in ASCII hex format (phex) ; print nibble in ASCII hex format (phex1) ; (externally and internally called) ; on entry: =byte ; on exit: ,flags clobbered ; all other regs unchanged phex: push psw ;save byte rrc ;move upper nibble down rrc ; / rrc ; / rrc ; / call phex1 ;output it pop psw ;restore byte phex1: ani 0fh ;strip lower nibble adi 90h ;convert to ASCII character daa ; / aci 40h ; / daa ; / call ctype ;output hex digit ret ; poll console and printer ; (externally and internally called) ; on entry: no parameters ; on exit: all registers unchanged poll: push psw ;save all registers & flags push b ; / push d ; / push h ; / call cipol ;poll console input call copol ;poll console output call popol ;poll printer output pop h ;restore registers & flags pop d ; / pop b ; / pop psw ; / ret ;--> poll console input cipol: mvi c,diriof ;direct I/O function mvi e,0ffh ;console request call bdos ;do it ora a ;console input ready? rz ;no, return ; lxi h,cibcb ;else put byte in queue buffer call putbuf ; / rnc ;return if all ok ; call ilprt ;else display error message db cr,lf,'L4: console input buffer overflow',cr,lf,bell,0 ret ;--> output byte to console if available copol: lxi h,cobcb ;get byte from queue buffer call getbuf ; / rc ;return if no byte available ; mvi c,diriof ;direct I/O function mov e,a ;else, output byte call bdos ret ;--> poll printer output popol: lhld 0001h ;get start of bios vector table lxi d,2dh-3h ;offset to list status entry point dad d ; / call go ;get list device status ora a ;ready? rz ;no, return ; lxi h,pobcb ;get byte from queue buffer call getbuf ; / rc ;return if no byte available ; mov e,a ;else, output byte mvi c,listf ;list output function call bdos ;and do it ret go: pchl ;dispatch to ; wait a little bit ; on entry: no parameters ; on exit: all regs, flags unchanged delay: push psw ;save regs push h ; / push d ; / push b ; / lxi d,0 ;= outer loop lxi h,0 ;= inner loop dloop: dcx d ;bump dloop1: dcx h ;bump mov a,h ;all counted out? cmp l ; / jnz dloop1 ;no, keep counting ; mov a,d ;outer loop counted out? cmp e ; / jnz dloop ;no, keep counting ; pop b ;restore regs pop d ; / pop h ; / pop psw ; / ret ; ***************** ; * data area * ; ***************** dseg ;data segment prnflg db 0 ;print on/off flag inbuf: db 128,0,0 ;initialized console input buffer ds 127 ;console input buffer area