IF NOT lasm .printx * CPXSY2.ASM * ENDIF ;NOT lasm ; KERMIT - (Celtic for "FREE") ; ; This is the CP/M-80 implementation of the Columbia University ; KERMIT file transfer protocol. ; ; Version 4.0 ; ; Copyright June 1981,1982,1983,1984,1985 ; Columbia University ; ; Originally written by Bill Catchings of the Columbia University Center for ; Computing Activities, 612 W. 115th St., New York, NY 10025. ; ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many ; others. ; ; This file contains the system-dependent code and data for KERMIT. ; It will be probably be broken into independent files to generate ; overlays for the various systems, one or more overlay possible ; from each file. For now, we will leave it in one piece. ; ; revision history: ; ; ; This is the system-dependent command to change the baud rate. ; DE contains the two-byte value from the baud rate table; this ; value is also stored in 'speed'. sysspd: IF px8 ; [29] push d call rsclose ; baud rate can only be set on opening rs232 pop d mov a, e sta px8blk+4 ; set param block call rsopen ; to set rate ret ENDIF ; px8 [29] ; Set the speed for the Osborne I IF osbrn1 mvi a,osbin1 ;Reset the ACIA call osstst ;Write the control port osbs1: inr c ;Waiting loop jnz osbs1 mov a,e ; get the specified speed jmp osstst ;Write the control reg. ENDIF;osbrn1 ;[hh] set the speed for a lobo MAX-80 IF lobo mov a,e ;[hh] get the parsed value setbd: sta baudrt ;[hh] and send it to the baud rate port ret ;[hh] ENDIF;lobo ; Set the speed for bigboard I or the delphi or the CPT-85xx ; or Cromemco (TU-ART) IF delphi OR cpt85xx OR cmemco OR mmate ;[22] [29] mov a,e ; get the parsed value out baudrt ; Tell the baud rate generator. ret ENDIF;delphi OR cpt85xx OR cmemco OR mmate [22] [29] ;[22] Set the speed for Acorn BBC IF bbc mov l,e mvi a,7 ;Set receive baud rate call osbyte ;*FX7,?e mov l,e mvi a,8 ;Set transmit baud rate call osbyte ;*FX8,?e ret ENDIF;[22] bbc ;[22] Set speed for RM 380Z IF rm380z mvi a,4 ;device type (SI/O4) in A rst 6 ; EMT db 29h ; SETLST ret ENDIF;[22] rm380z ; Set the speed for MicroMikko. DE is baud rate multiplier IF mikko di lxi h,txclk mov m,d ;LSB first (swapped in memory) mov m,e ;MSB last lxi h,rxclk mov m,d mov m,e mvi b,0 ;"modifier" for 1 stop bit mvi a,2 ;Test MSB of speed >2 (110 bps or less) cmp e jp miksp1 mvi b,00001000B ;"modifier" for 2 stop bits miksp1: mvi a,4 ;Select SIO Reg 4 lxi h,sioac mov m,a mvi a,sion4 ;Get values ora b ;Add modifier mov m,a ;Set value (stop bits) ei ret ENDIF;mikko ; Set the speed for the Decision I IF mdI call selmdm ;Let's be absolutely sure, huh? mvi a,dlab+wls1+wls0+stb ;Set data latch access bit out lcr ;Out to Line Control Register lhld speed ;Load baudrate multiplier xchg mov a,d ;Get low order byte for baud rate out dlm ;Out to the MSB divisor port mov a,e ;...and the high order byte out dll ;Out to the LSB divisor port mvi a,wls1+wls0+stb ;Enable Divisor Access Latch out lcr ;Out to ACE Line Control Register xra a ;Clear A out ier ;Set no interrupts out lsr ;Clear status in msr ;Clear Modem Status Register in lsr ;Clear Line Status Register in rbr ;Clear Receiver Buffers in rbr ret ENDIF ;mdI [Toad Hall] IF teletek di mov a,e ; first speed byte out baudrt mov a,d ; second speed byte out baudrt ei ret ENDIF ;teletek IF access ;[29] mov a,e ;Get the parsed time constant ;The following code is derived from the Access initialization code sta savspd ;Save the time constant mvi a,14h ;Code for 'monitor' to set channel A baudrate call monitor lda savspd ;Get the time constant call monitor ; and send it to the CRT ret savspd: ds 1 monitor: ;Routine to do CRT functions out 90h ;Output the data to the CRT mvi a,1 ;Set DRDY true out 23h mon1: in 0a0h ;Wait for CACK* true rlc jc mon1 in 80h ;Read the input data latch push psw ;Save the input data xra a ;Set DRDY false out 23h mon2: in 0a0h ;Wait for CACK* false rlc jc mon2 pop psw sta 0ee02h ;Save the input data ret ENDIF;access [29] IF disc ;[29] ; Assuming that parsing of value from speed table puts low order ; byte of time constant in the e register and high byte in d. mvi a,12 ;Register 12 out mnprts mov a,e ;Low order byte of time constant out mnprts mvi a,13 ;Register 13 out mnprts mov a,d ;High order byte of time constant out mnprts mvi a,14 ;Register 14 out mnprts mvi a,3 ;Enable baud rate generator out mnprts mvi a,11 ;Register 11 out mnprts mvi a,52h ;no Xtal, tclk=rclk=/trxc out=br gen out mnprts ret ENDIF;disc [29] ; Speed tables ; (Note that speed tables MUST be in alphabetical order for later ; lookup procedures, and must begin with a value showing the total ; number of entries. The speed help tables are just for us poor ; humans. ; db string length,string,divisor (2 identical bytes or 1 word) ; [Toad Hall] IF delphi OR lobo ;[hh] spdtbl: db 10h ;16 entries db 03h,'110$', 02h,02h db 04h,'1200$', 07h,07h db 05h,'134.5$', 03h,03h db 03h,'150$', 04h,04h db 04h,'1800$', 08h,08h db 05h,'19200$', 0fh,0fh db 04h,'2000$', 09h,09h db 04h,'2400$', 0ah,0ah db 03h,'300$', 05h,05h db 04h,'3600$', 0bh,0bh db 04h,'4800$', 0ch,0ch db 02h,'50$', 00h,00h db 03h,'600$', 06h,06h db 04h,'7200$', 0dh,0dh db 02h,'75$', 01h,01h db 04h,'9600$', 0eh,0eh sphtbl: db cr,lf,' 50 75 110 134.5 150 300 600 1200' db cr,lf,' 1800 2000 2400 3600 4800 7200 9600 19200$' ENDIF;delphi OR lobo ;[hh] IF cpt85xx spdtbl: db 15 ; 15 entries db 03,'110$', 03h,03h db 04,'1200$', 09h,09h db 05,'134.5$', 04h,04h db 03,'150$', 05h,05h db 04,'1800$', 0Ah,0Ah db 04,'2400$', 0Bh,0Bh db 03,'300$', 06h,06h db 04,'3600$', 0Ch,0Ch db 04,'4800$', 0Dh,0Dh db 02,'50$', 01h,01h db 03,'600$', 07h,07h db 04,'7200$', 0Eh,0Eh db 02,'75$', 02h,02h db 03,'900$', 08h,08h db 04,'9600$', 0Fh,0Fh sphtbl: db cr,lf,' 50 75 110 134.5 150 300 600 900' db cr,lf,' 1200 1800 2400 3600 4800 7200 9600$' ENDIF;cpt85xx IF bbc ;[22] spdtbl: db 8 ; 8 entries db 04,'1200$', 04h,04h db 03,'150$', 02h,02h db 05,'19200$', 08h,08h db 04,'2400$', 05h,05h db 03,'300$', 03h,03h db 04,'4800$', 06h,06h db 02,'75$', 01h,01h db 04,'9600$', 07h,07h sphtbl: db cr,lf,' 75 150 300 1200 2400 4800 9600 19200$' ENDIF;[22] bbc IF rm380z ;[22] spdtbl: db 7 ; 7 entries db 03,'110$', 00h,00h db 04,'1200$', 03h,03h db 04,'2400$', 04h,04h db 03,'300$', 01h,01h db 04,'4800$', 05h,05h db 03,'600$', 02h,02h db 04,'9600$', 06h,06h sphtbl: db cr,lf,' 110 300 600 1200 2400 4800 9600$' ENDIF;[22] rm380z IF px8 ; [29] spdtbl: db 9 ; 9 entries db 03,'110$', 02h,02h db 04,'1200$', 0ah,0ah db 03,'150$', 04h,04h db 05,'19200$', 0fh,0fh db 04,'2400$', 0ch,0ch db 03,'300$', 06h,06h db 04,'4800$', 0dh,0dh db 03,'600$', 08h,08h db 04,'9600$', 0eh,0eh sphtbl: db cr, lf db ' 100 150 300 600 1200 2400 4800 9600 19200$' ENDIF ; px8 [29] IF mikko spdtbl: db 9h ;9 entries db 03h,'110$' dw 0369h db 04h,'1200$' dw 0050h db 03h,'150$' dw 0280h db 04h,'2400$' dw 0028h db 03h,'300$' dw 0140h db 04h,'4800$' dw 0014h db 03h,'600$' dw 00A0H db 02h,'75$' dw 0500h db 04h,'9600$' dw 000ah sphtbl: db cr,lf,' 75 110 150 300 600 1200 2400 4800 9600$' ENDIF;mikko IF osbrn1 spdtbl: db 02h ;2 entries db 04h,'1200$', OSBI12,OSBI12 db 03h,'300$', OSBI03,OSBI03 sphtbl: db cr,lf,' 300',cr,lf,' 1200$' ENDIF;osbrn1 IF mdI spdtbl: db 0dh ; 13 entries db 03h, '110$' dw 1047 db 04h, '1200$' dw 96 db 03h, '150$' dw 768 db 05h,'19200$' dw 6 db 04h, '2400$' dw 48 db 03h, '300$' dw 384 db 05h,'38400$' dw 3 db 03h, '450$' dw 288 db 04h, '4800$' dw 24 db 05h,'56000$' dw 2 db 03h, '600$' dw 192 db 02h, '75$' dw 1536 db 04h, '9600$' dw 12 sphtbl: db cr,lf,' 75 110 150 300 450 600 1200' db cr,lf,' 2400 4800 9600 19200 38400 56000$' ;(Lord knows what you'll be communicating with at 56000 baud, but the ;Multi-I/O board literature says it'll do it, so what the heck.... ;might as well throw it in here just to show off...sure hope the ;port don't melt...) ENDIF ;mdI [Toad Hall] IF cmemco ;[25] spdtbl: db 7 ; 7 entries db 3,'110$', 01H,01H db 4,'1200$', 88H,88H db 3,'150$', 82H,82H db 4,'2400$', 90H,90H db 3,'300$', 84H,84H db 4,'4800$', 0A0H,0A0H db 4,'9600$', 0C0H,0C0H sphtbl: db cr,lf db ' 110 150 300 1200 2400 4800 9600$' ENDIF;cmemco IF access ;Similar to bbI with different values [29] spdtbl: db 6h ;6 entries db 04h,'1200$', 28h,28h db 04h,'2400$', 14h,14h db 03h,'300$', 0a0h,0a0h db 04h,'4800$', 0ah,0ah db 03h,'600$', 50h,50h db 04h,'9600$', 5,5 sphtbl: db cr,lf,' 300 600 1200 2400 4800 9600$' ENDIF;access [29] IF mmate ;[29] spdtbl: db 10h ;16 entries db 03h,'110$', 0e2h,0e2h db 04h,'1200$', 0e7h,0e7h db 05h,'134.5$', 0e3h,0e3h db 03h,'150$', 0e4h,0e4h db 04h,'1800$', 0e8h,0e8h db 05h,'19200$', 0efh,0efh db 04h,'2000$', 0e9h,0e9h db 04h,'2400$', 0eah,0eah db 03h,'300$', 0e5h,0e5h db 04h,'3600$', 0ebh,0ebh db 04h,'4800$', 0ech,0ech db 02h,'50$', 0e0h,0e0h db 03h,'600$', 0e6h,0e6h db 04h,'7200$', 0edh,0edh db 02h,'75$', 0e1h,0e1h db 04h,'9600$', 0eeh,0eeh sphtbl: db cr,lf,' 50 75 110 134.5 150 300 600 1200' db cr,lf,' 1800 2000 2400 3600 4800 7200 9600 19200$' ENDIF;mmate [29] IF disc ;[29] ; Similar to mikko table but with different time constant values spdtbl: db 9h ;9 entries db 03h,'110$' dw 1134 db 04h,'1200$' dw 102h db 03h,'150$' dw 831 db 04h,'2400$' dw 50 db 03h,'300$' dw 415 db 04h,'4800$' dw 24 db 03h,'600$' dw 206 db 02h,'75$' dw 1665 db 04h,'9600$' dw 11 sphtbl: db cr,lf,' 75 110 150 300 600 1200 2400 4800 9600$' ENDIF;disc [29] IF teletek spdtbl: db 7 ; 7 entries db 4, '1200$', 47h,40h db 5,'19200$', 47h,04h db 4, '2400$', 47h,20h db 3, '300$', 47h,00h db 4, '4800$', 47h,10h db 3, '600$', 47h,80h db 4, '9600$', 47h,08h sphtbl: db cr,lf db ' 300 600 1200 2400 4800 9600 19200$' ENDIF ;teletk ; The following conditionals were once a huge if not statement. There ; wasn't enough room to add the lobo to the list, so it had to be broken ; into 2, which you can't do with an if not. I redid it as two ifs and ; applied them to those that wouldn't set baud. [Hal Hostetler] IF robin OR gener OR dmII OR vector OR trs80;[32] spdtbl equ 0 ; SET BAUD not supported. sphtbl equ 0 ENDIF;robin OR gener OR dmII OR vector OR trs80 ; IF mmdI OR osi OR cpm3 OR S1008 ; [29] spdtbl EQU 0 ;[hh] SET BAUD not supported. sphtbl EQU 0 ;[hh] ran out of room above... ENDIF;mmdI OR osi OR cpm3 OR S1008 [29] ; IF hp125 ;[MF] spdtbl equ 0 ; SET BAUD not supported. sphtbl equ 0 ENDIF;hp125 [MF] ; ; This is the system-dependent SET PORT command. ; HL contains the argument from the command table. sysprt: IF lobo ;[hh] mov a,l ;[hh] get the data port value and store at sta outmd3+1 ;[hh] the two places we use... sta inpmd2+1 ;[hh] MNPORT in the overlay sta port ;[hh] inform program of the change in ports inr a ;[hh] status port = data port + 1 in the Lobo sta outmd1+1 ;[hh] store it at the three places... sta inpmd1+1 ;[hh] we use MNPRTS... sta outctl+1 ;[hh] in the overlay mov a,h ;[hh] now get the baud rate port value sta getbd+1 ;[hh] store it in the two places we use... sta setbd+1 ;[hh] BAUDRT in the overlay sta port+1 ;[hh] don't need to, but keeps it consistant getbd: lda baudrt ;[hh] get baud rate value from port sta speed ;[hh] tell STAT. baud rate for each port ;[hh] is independant of the other ENDIF ;lobo IF iobyt mov a,m ;Get the I/O byte sta prtiob ;Save the desired IO byte for this port inx h ;Point at next entry mov a,m ;Get the output function sta prtfun ;Save it ENDIF;iobyt IF iobyt AND robin inx h ;Point at next entry mov a,m ;Get the hardware address for the port sta prtadr ;Store it ENDIF;iobyt AND robin ; IF hp125 ;[MF] push psw push b push d push h xchg ;Put port connect sequence address in DE call prtstr ;Connect proper port pop h pop d pop b pop psw ENDIF;hp125 [MF] ; ret ; ; Port tables for Lobo MAX-80 IF lobo ;[hh] ; help text prhtbl: db cr,lf,'RS-232 port A or B$' ; ; command table prttbl: db 02H ;[hh] two entries db 01H,'A$',0E4H,0D0H db 01H,'B$',0E6H,0D4H ENDIF ;lobo ; ; Port tables for GENERIC CPM 2.2 IF gener ; help text prhtbl: db cr,lf,'CRT device' db cr,lf,'PTR device' db cr,lf,'TTY device' db cr,lf,'UC1 device' db cr,lf,'UR1 device' db cr,lf,'UR2 device$' ; command table prttbl: db 06H ;Six devices to choose from db 03H,'CRT$' dw crtptb db 03H,'PTR$' dw ptrptb db 03H,'TTY$' dw ttyptb db 03H,'UC1$' dw uc1ptb db 03H,'UR1$' dw ur1ptb db 03H,'UR2$' dw ur2ptb ; port entry table ; table entries are: ; db iobyte-value, BDOS output function, reserved crtptb: db crtio,conout,0 ptrptb: db ptrio,punout,0 ttyptb: db ttyio,conout,0 uc1ptb: db uc1io,conout,0 ur1ptb: db ur1io,punout,0 ur2ptb: db ur2io,punout,0 ENDIF;gener ; ; Port tables for DECmate II or MicroMikko or Acorn BBC ; IF dmII OR mikko OR bbc ;[22] ; help text prhtbl: db cr,lf,'COMMUNICATIONS port$' ; command table prttbl: db 01H ;Only one port known at this point db 0EH,'COMMUNICATIONS$' dw comptb ;address of info ; port entry table ; table entries are: ; db iobyte-value, BDOS output function, reserved comptb: db batio,punout,0 ENDIF;[22] dmII OR mikko OR bbc ; ; Port tables for Robin ; IF robin ; help text prhtbl: db cr,lf,'COMMUNICATIONS port' db cr,lf,'GENERAL purpose port' db cr,lf,'PRINTER port$' ; command table prttbl: db 03H ;Three entries db 0EH,'COMMUNICATIONS$' dw comptb db 07H,'GENERAL$' dw gppptb db 07H,'PRINTER$' dw prnptb ; port entry table ; table entries are: ; db iobyte-value, BDOS output function, hardware port address ; (control/status) ; ;At present, the hardware port address is only used for sending a break. comptb: db batio,punout,comtst gppptb: db gppio,conout,gentst prnptb: db lptio,conout,prntst prtadr: db comtst ;space for current hardware port address ENDIF;robin IF iobyt prtfun: db punout ;Function to use for output to comm port prtiob: db batio ;I/O byte to use for communicating coniob: db defio ;I/O byte to use for console ENDIF;iobyt ; IF hp125 ;[MF] ; Help table prhtbl: db cr,lf,'Communications port' db cr,lf,'Printer port$' ; command table prttbl: db 02H ;2 entries db 0eH,'COMMUNICATIONS$' dw mapon1 db 07H,'PRINTER$' dw mapon2 ;Port table entries are the addresses of the escape sequences to connect ;the ports. ; ENDIF;hp125 [MF] IF NOT (iobyt OR lobo OR hp125) ;[hh] [MF] prttbl equ 0 ; SET PORT is not supported prhtbl equ 0 ENDIF;NOT iobyt OR lobo OR hp125 [MF] ; ; selmdm - select modem port ; selcon - select console port ; selmdm is called before using inpmdm or outmdm; ; selcon is called before using inpcon or outcon. ; For iobyt systems, diddle the I/O byte to select console or comm port; ; For Decision I, switches Multi I/O board to console or modem serial ; port. [Toad Hall] ; For the rest, does nothing. ; preserves bc, de, hl. selmdm: IF iobyt lda prtiob ;Set up for output to go to the comm port sta iobyte ;Switch byte directly ENDIF;iobyt IF mdI lda group ori mdmgrp ;Mask modem serial port out grpsel ENDIF;mdI [Toad Hall] ret selcon: IF iobyt lda coniob ;Set up for output to go to the console port sta iobyte ;Switch directly ENDIF;iobyt IF mdI lda group ori congrp ;Mask console serial port (1) out grpsel ENDIF;mdI [Toad Hall] ret ; Get character from console, or return zero. ; result is returned in A. destroys bc, de, hl. ; inpcon: IF NOT iobyt mvi c,dconio ;Direct console I/O BDOS call. mvi e,0FFH ;Input. call BDOS ENDIF;NOT iobyt IF iobyt call bconst ;Get the status ora a ;Anything there? rz ;No, forget it call bconin ;Yes, get the character ENDIF;iobyt ret ; ; Output character in E to the console. ; destroys bc, de, hl ; outcon: IF rm380z ;[22] mov a,e cpi cr ;cr produces cr + lf jnz outcn1 mvi e,'N'-100O ;Control-N produces cr only outcn1: ;continue ENDIF;[22] rm380z IF NOT iobyt mvi c,dconio ;Console output bdos call. call bdos ;Output the char to the console. ENDIF;NOT iobyt IF iobyt mov c,e ;Character call bcnout ;to Console ENDIF;iobyt ret ; ; outmdm - output a char from E to the modem. ; the parity bit has been set as necessary. ; returns nonskip; bc, de, hl preserved. outmdm: IF osi OR lobo ;[hh] push h outmd1: lxi h,mnprts ;address of the port status register outmd2: mov a,m ; get port status in A ani output ;Loop till ready. jz outmd2 outmd3: lxi h,mnport ;address of port data register mov m,e ; write the character pop h ret ENDIF;osi OR lobo IF osbrn1 call osldst ;Read the status port ani output ;Loop till ready. jz outmdm mov a,e jmp osstda ;Write to the data port ENDIF;osbrn1 IF px8 ; [29] push h push b push d outmd1: call rsoutst ; get the output status ora a jz outmd1 ; check if output enabled pop d mov c, e ; char in C push d call rsput pop d pop b pop h ret ENDIF; px8 [29] IF inout in mnprts ;Get the output done flag. ani output ;Is it set? jz outmdm ;If not, loop until it is. mov a,e out mnport ;Output it. ret ENDIF;inout IF iobyt ;**** Note that we enter from outpkt with the I/O byte already set up for ; output to go to the comm port push h push b lda prtfun ;Get the output function mov c,a ;Into C call bdos ;And output the character pop b pop h ret ENDIF;iobyt IF cpm3 OR hp125 ;[MF] push h push b mvi c,auxout ;Output to the aux output device call bdos pop b pop h ret ENDIF;cpm3 OR hp125 [MF] ;org $+100h AND 0FF00h ; get rid of phase error ; ; get character from modem; return zero if none available. ; for IOBYT systems, the modem port has already been selected. ; destroys bc, de, hl. inpmdm: IF iobyt call bconst ;Is Char at COMM-Port? ora a ;something there? rz ; return if nothing there call bconin ; data present. read data. ENDIF;iobyt IF cpm3 mvi c,auxist call bdos ;is char at auxin? ora a ;something there? rz ;no mvi c,auxin call bdos ;read char from auxin ENDIF;cpm3 ; IF hp125 ;[MF] lxi b,70ffh ;SEt subfunction to get RDR (auxin) status call bdos ;is char at RDR? ora a ;something there? rz ;no mvi c,auxin call bdos ;read char from RDR ENDIF;hp125 [MF] IF osi OR lobo ;[hh] inpmd1: lda mnprts ;Get the port status into A. ani input ;See if the input ready bit is on. rz ;If not then return. inpmd2: lda mnport ;If so, get the char. ENDIF;osi OR lobo IF osbrn1 call osldst ;Read the status port ani input ;Something there? rz ;Nope call osldda ;Read the data port ENDIF;osbrn1 IF inout ;Note: modem port should already be selected for mdI. [Toad Hall] in mnprts ;Get the port status into A. ani input ;See if the input ready bit is on. rz ;If not then return. in mnport ;If so, get the char. ENDIF;inout IF px8 ; [29] call rserst ; check error status ani 64h ; this assumes 'not open' cannot occur jnz inpmd1 ; error has occurred! call rsinst ; any chars outstanding? ora a rz ; exit if none call rsget ; get char in A ret ; return the 'no char outstanding' indication on error inpmd1: mvi a, 0 ENDIF; px8 [29] ret ; return with character in A ; ; flsmdm - flush comm line. ; Modem is selected. ; Currently, just gets characters until none are available. flsmdm: call inpmdm ; Try to get a character ora a ; Got one? jnz flsmdm ; If so, try for another ret ; Receiver is drained. Return. ; ; lptstat - get the printer status. Return a=0ffh if ok, or 0 if not. lptstat: IF iobyt ;[33] call bprtst ; call bprtst ; get status ENDIF ;iobyt[33] IF NOT iobyt ;[33] xra a ; assume it is ok.. this may not be necessary ENDIF ;iobyt [33] ret ; ; outlpt - output character in E to printer ; console is selected. ; preserves de. outlpt: push d ; save DE in either case call prtflt ; go through printer filter [30] ana a ; if A = 0 do nothing, jz outlp1 ; [30] if a=0 do nothing IF NOT iobyt mvi c,lstout call bdos ;Char to printer ENDIF;NOT iobyt IF iobyt mov c,e call blsout ENDIF;iobyt outlp1: pop d ; restore saved register pair ret ; ; Screen manipulation routines ; csrpos - move to row B, column C ; ; csrpos for terminals that use a leadin sequence followed ; by (row + 31.) and (column + 31.) ; IF NOT (robin OR dmII OR osi OR vector OR termin OR hp125) ;[MF] Terminals code in CPXVDU csrpos: push b ; save coordinates lxi d,curldn ; get cursor leadin sequence call prtstr ; print it pop h ; restore coordinates mov a,h ; get row adi (' '-1) ; space is row one mov e,a push h call outcon ; output row pop h mov a,l ; get column adi (' '-1) ; space is column one mov e,a jmp outcon ; output it and return ENDIF;NOT (robin OR dmII OR osi OR vector OR termin OR hp125)[MF] ; ; ; ; csrpos for ANSI terminals ; IF robin OR dmII csrpos: push b ; save coordinates lxi d,curldn ; get cursor leadin sequence call prtstr ; print it pop h ; peek at coordinates push h ; then save away again mov l,h ; l = row mvi h,0 ; hl = row call nout ; output in decimal mvi e,';' ; follow with semicolon call outcon ; print it pop h ; restore column mvi h,0 ; hl = column call nout mvi e,'H' ; terminate with 'move cursor' command jmp outcon ; output it and return ENDIF;robin OR dmII ; ; csrpos for the HP-125 [MF] ; IF hp125 ;[MF] csrpos: dcr b ;HP-125 uses zero-based addressing dcr c ;... push b ; save coordinates lxi d,curldn ; get cursor leadin sequence call prtstr ; print it pop h ; peek at coordinates push h ; then save away again mov l,h ; l = row mvi h,0 ; hl = row call nout ; output in decimal mvi e,'R'+20h ;Say it was a row call outcon ; print it pop h ; restore column mvi h,0 ; hl = column call nout mvi e,'C' ; terminate with 'move cursor' command jmp outcon ; output it and return ENDIF;hp125 [MF] ; ; csrpos for the Vector General. It's weird. ; IF vector csrpos: dcr b ; vector uses zero-based addressing? dcr c push b ; save coordinates mvi e,esc ; print an escape call outcon pop d ; peek at coordinates push d call outcon ; output column pop d mov e,d ; get row jmp outcon ; output and return ENDIF;vector IF osi ; systems without cursor positioning csrpos: ret ; dummy routine referenced by linkage section ENDIF;osi ; ; delchr - make delete look like a backspace. Unless delete is a printing ; character, we just need to print a backspace. (we'll output clrspc ; afterwards) ; For Kaypro and Vector General, delete puts a blotch on the screen. ; For Apple and Osborne 1, delete moves but doesn't print. delchr: IF vector OR osbrn1 OR lobo lxi d,delstr jmp prtstr ENDIF ;vector OR osbrn1 OR lobo IF bbc OR rm380z ;[22] ret ENDIF;bbc OR rm380z IF NOT (vector OR osbrn1 OR bbc OR rm380z);[22] mvi e,bs ;get a backspace jmp outcon ENDIF;NOT (vector OR osbrn1 OR bbc OR rm380z [22] ; erase the character at the current cursor position clrspc: mvi e,' ' call outcon mvi e,bs ;get a backspace jmp outcon ; erase the current line clrlin: lxi d,eralin jmp prtstr ; erase the whole screen, and go home. preserves b (but not c) clrtop: lxi d,erascr jmp prtstr IF robin sysver: db 'VT180 Robin$' ENDIF;robin IF dmII sysver: db 'DECmate II CP/M-80$' ENDIF;dmII IF delphi ; [7] new system sysver: db 'Digicomp Delphi 100$' endif;delphi IF access sysver: db 'Actrix CP/M$' endif; IF teletek sysver: db 'Teletek SYSTEMASTER CP/M-80$' ENDIF ;teletek IF cpt85xx sysver: db 'CPT-85xx under CompuPak CP/M$' ENDIF;cpt85xx IF mdI sysver: db 'Morrow Decision I$' ENDIF;mdI [Toad Hall] IF mmdI sysver: db 'MicroDecision I$' ENDIF;mmdI IF osi sysver: db 'Ohio Scientific$' ENDIF;osi IF mmate ;[29] sysver: db 'PMC Micromate using port I/O$' ENDIF;mmate [29] IF disc ;[29] sysver: db 'Discovery using 83U board port B$' ENDIF ;disc [29] IF s1008 ;[29] sysver: db 'U. S. MicroSales using printer port$' ENDIF ;s1008 [29] IF cmemco ;[25] sysver: db 'Cromemco (TU-ART)$' ENDIF;cmemco ; IF robin OR dmII ; Note that we cannot support Graphics Mode or the H19 erase-screen command ; (<esc>E), because the sequences are more than three bytes. defesc EQU '\'-100O ;Still Control-\ (just ran out of room...) vtval EQU 0 ; we probably don't want VT52 emulation outlin: db esc,3CH,esc,'[H',esc,'[J',cr,lf,tab,tab,'$' erascr: db esc,'[H',esc,'[J$' ;Clear screen and go home. eralin: db cr,esc,'[K$' ;Clear line. curldn: db esc,'[$' ; Cursor leadin ttab: ta: db esc,'[A$' ; Cursor up. tb: db esc,'[B$' ; Cursor down. tc: db esc,'[C$' ; Cursor right. td: db esc,'[D$' ; Cursor left te: db '$',0,0,0 ; (can't) Clear display tf: db '$',0,0,0 ; (don't) Enter Graphics Mode tg: db '$',0,0,0 ; (don't) Exit Graphics mode th: db esc,'[H$' ; Cursor home. ti: db esc,'M$',0 ; Reverse linefeed. tj: db esc,'[J$' ; Clear to end of screen. tk: db esc,'[K$' ; Clear to end of line. ENDIF;robin OR dmII IF mikko sysver: db 'MikroMikko$' outlin: db subt,cr,lf,tab,'$' erascr: db subt,'$' ;Clear screen and go home. eralin: db cr,1CH,'$' ;Clear line. curldn: db esc,'=$' ;cursor leadin ttab: ;Table start location. ta: db 0BH,'$',0,0 ;Cursor up. tb: db 0AH,'$',0,0 ;Cursor down. tc: db 0CH,'$',0,0 ;Cursor right. td: db bs,'$',0,0 ;Cursor left te: db subt,'$',0,0 ;Clear display tf: db '$',0,0,0 ;(can't) Enter Graphics Mode tg: db '$',0,0,0 ;(can't) Exit Graphics mode th: db 1EH,'$',0,0 ;Cursor home. ti: db '$',0,0,0 ;(can't) Reverse linefeed. tj: db 1cH,'$',0,0 ;Clear to end of screen. tk: db 1cH,'$',0,0 ;Clear to end of line. ENDIF;mikko ; IF bbc ;[22] sysver: db 'BBC (Z80)$' outlin: db 0CH,esc,'=',21H,30H,'$' erascr: db 0CH,'$' ;Clear screen and go home. eralin: db cr,esc,'@$' ;Clear line. curldn: db esc,'=$' ;cursor leadin ttab: ;Table start location. ta: db 0BH,'$',0,0 ;Cursor up. tb: db 0AH,'$',0,0 ;Cursor down. tc: db tab,'$',0,0 ;Cursor right. td: db bs,'$',0,0 ;Cursor left te: db 0CH,'$',0,0 ;Clear display tf: db '$',0,0,0 ;(can't) Enter Graphics Mode tg: db '$',0,0,0 ;(can't) Exit Graphics mode th: db 1EH,'$',0,0 ;Cursor home. ti: db '$',0,0,0 ;(can't) Reverse linefeed. tj: db esc,'?$',0,0 ;Clear to end of screen. tk: db esc,'@$',0,0 ;Clear to end of line. ENDIF;[22] bbc ; IF rm380z ;[22] sysver: db 'Research Machines 380Z$' outlin: db 1FH,cr,tab,'$' erascr: db 1FH,'$' ;Clear screen and go home. eralin: db 0EH,19H,'$' ;Clear line. curldn: db 16H,'$' ;cursor leadin ttab: ;Table start location. ta: db 0BH,'$',0,0 ;Cursor up. tb: db 0AH,'$',0,0 ;Cursor down. tc: db 18H,'$',0,0 ;Cursor right. td: db bs,'$',0,0 ;Cursor left te: db 1FH,'$',0,0 ;Clear display tf: db '$',0,0,0 ;(can't) Enter Graphics Mode tg: db '$',0,0,0 ;(can't) Exit Graphics mode th: db 1DH,'$',0,0 ;Cursor home. ti: db '$',0,0,0 ;(can't) Reverse linefeed. tj: db 1EH,'$',0,0 ;Clear to end of screen. tk: db 19H,'$',0,0 ;Clear to end of line. ENDIF;[22] rm380z IF lobo ;[hh] sysver: db 'Lobo MAX-80$' outlin: db esc,'*',cr,lf,tab,tab,'$' erascr: db esc,'*$' ;[hh] clear screen and home cursor eralin: db cr,esc,'R$' ;[hh] clear line curldn: db esc,'=$' ;[hh] cursor lead-in string delstr: db bs,' ',bs,bs,'$' ;[hh] ??adjust for echoing delete ttab: ;[hh] table start location ta: db 0BH,'$',0,0 ;[hh] cursor up tb: db 0AH,'$',0,0 ;[hh] cursor down tc: db 0CH,'$',0,0 ;[hh] cursor right td: db 08H,'$',0,0 ;[hh] cursor left te: db esc,'*$',0 ;[hh] clear display (homes cursor) tf: db '$',0,0,0 ;[hh] (can't) enter graphics mode tg: db '$',0,0,0 ;[hh] (can't) exit graphics mode th: db 01EH,'$',0,0 ;[hh] home cursor ti: db esc,'E$',0 ;[hh] reverse linefeed (insert line) tj: db esc,'Y$',0 ;[hh] clear to end of screen tk: db esc,'T$',0 ;[hh] clear to end of line ENDIF ;lobo IF px8 ; [29] sysver: db 'Epson PX-8$' outlin: db esc,'*$' erascr: db esc,'*$' ; clear screen and home eralin: db cr,esc,'T$' ; clear line curldn: db esc,'=$' ; cursor lead in ttab: ; table start location ta: db 30,'$',0,0 ; cursor up tb: db 31,'$',0,0 ; cursor down tc: db 28,'$',0,0 ; cursor right td: db 29,'$',0,0 ; cursor left te: db esc,'*$',0 ; clear display tf: db '$',0,0,0 ; can't enter graphics graphics mode tg: db '$',0,0,0 ; can't exit graphics mode th: db 11,'$',0,0 ; home cursor ti: db 30,'$',0,0 ; reverse linefeed tj: db esc,'Y$',0 ; erase to end of screen tk: db esc,'T$',0 ; erase to end of line ENDIF ; px8 [29] ; IF osbrn1 sysver: db 'Osborne 1$' outlin: db 1AH,cr,lf,tab,'$' ;(Clear screen, home cursor) erascr: db 1AH,'$' ;Clear screen and go home. eralin: db cr,esc,'T$' ;Clear line. delstr: db bs,bs,'$' ; Adjust for delete curldn: db esc,'=$' ;Cursor lead-in ttab: ;Table start location. ta: db ('K'-100O),'$',0,0 ;Cursor up. tb: db 12O,'$',0,0 ;Cursor down. tc: db ('L'-100O),'$',0,0 ;Cursor right. td: db bs,'$',0,0 ;Cursor left. te: db subt,'$',0,0 ;Clear screen. tf: db '$',0,0,0 ;(can't) Enter graphics mode tg: db '$',0,0,0 ;(can't) Exit graphics mode th: db ('^'-100O),'$',0,0 ;Cursor home. ti: db ('K'-100O),'$',0,0 ;Reverse linefeed. tj: db esc,'T$',0 ;(can't) Clear to end of screen. tk: db esc,'T$',0 ;Clear to end of line. ENDIF;osbrn1 ; IF vector sysver: db 'Vector Graphics$' outlin: db ('D'-100O),cr,lf,tab,tab,'$' erascr: db ('D'-100O),'$' ;Clear screen and go home. eralin: db cr,('Q'-100O),'$' ;Clear line. delstr: db bs,' ',bs,bs,'$' ; adjust for echoing delete character ttab: ;Table start location. ta: db ('U'-100O),'$',0,0 ;Cursor up. tb: db 12O,'$',0,0 ;Cursor down. tc: db ('Z'-100O),'$',0,0 ;Cursor right. td: db '$',0,0,0 ;(can't) Cursor left te: db '$',0,0,0 ;(can't) Clear display tf: db '$',0,0,0 ;(can't) Enter graphics mode tg: db '$',0,0,0 ;(can't) Exit graphics mode th: db ('B'-100O),'$',0,0 ;Cursor home. ti: db ('U'-100O),'$',0,0 ;Reverse linefeed. tj: db ('P'-100O),'$',0,0 ;Clear to end of screen. tk: db ('Q'-100O),'$',0,0 ;Clear to end of line. ENDIF;vector IF trs80lb sysver: db 'TRS-80 II Lifeboat CP/M$' outlin: db esc,':',cr,lf,tab,tab,'$' erascr: db esc,':$' ;Clear screen and go home. eralin: db cr,esc,'T$' ;Clear line. curldn: db esc,'=$' ;Cursor lead-in ttab: ;Table start location. ta: db 0BH,'$',0,0 ;Cursor up. tb: db 0AH,'$',0,0 ;Cursor down. tc: db 0CH,'$',0,0 ;Cursor right. td: db bs,'$',0,0 ;Cursor left te: db esc,':$',0 ;Clear display tf: db '$',0,0,0 ;(can't) Enter Graphics Mode tg: db '$',0,0,0 ;(can't) Exit Graphics mode th: db 1EH,'$',0,0 ;Cursor home. ti: db 0BH,'$',0,0 ;Reverse linefeed. tj: db esc,'Y$',0 ;Clear to end of screen. tk: db esc,'T$',0 ;Clear to end of line. ENDIF;trs80lb ; IF trs80pt sysver: db 'TRS-80 II P+T CP/M$' outlin: db 0CH,cr,lf,tab,tab,'$' erascr: db 0CH,'$' ;Clear screen and go home. eralin: db cr,01H,'$' ;Clear line. curldn: db esc,'Y$' ;Cursor lead-in ttab: ;Table start location ;Must be 4 bytes each ta: db 1EH,'$',0,0 ;Cursor up. tb: db 1FH,'$',0,0 ;Cursor down. tc: db 1DH,'$',0,0 ;Cursor right. td: db 1CH,'$',0,0 ;Cursor left te: db 0CH,'$',0,0 ;Clear display tf: db 11H,'$',0,0 ;Enter Graphics Mode tg: db 14H,'$',0,0 ;Exit Graphics mode th: db 06H,'$',0,0 ;Cursor home. ti: db 1EH,'$',0,0 ;Reverse linefeed. tj: db 02H,'$',0,0 ;Clear to end of screen. tk: db 01H,'$',0,0 ;Clear to end of line. ENDIF;trs80pt IF osi outlin: db cr,lf,'Starting ...$' erascr equ crlf ;"Home & clear" (best we can do). eralin: db '^U',cr,lf,'$' ;Clear line. prpack: db cr,lf,'RPack: $' pspack: db cr,lf,'SPack: $' ttab equ 0 ; no VT52 table ENDIF;osi ; IF hp125 ;[MF] defesc EQU '\'-100O ;Still Control-\ (just ran out of room...) vtval EQU 0 ; we probably don't want VT52 emulation ; sysver: db 'HP-125 Series 100$' ; outlin: db esc,'H',esc,'J',cr,lf,tab,tab,'$' erascr: db esc,'H',esc,'J$' ;Clear screen and go home. eralin: db cr,esc,'K$' ;Clear line. curldn: db esc,'&a$' ;Cursor leadin ttab: ;Table start location. ta: db esc,'A$',0 ;Cursor up. tb: db esc,'B$',0 ;Cursor down. tc: db esc,'C$',0 ;Cursor right. td: db esc,'D$',0 ;Cursor left te: db esc,'J$',0 ;Clear display tf: db '$',0,0,0 ;[hh] (can't) enter graphics mode tg: db '$',0,0,0 ;[hh] (can't) exit graphics mode th: db esc,'H$',0 ;Cursor home. ti: db esc,'M$',0 ;Reverse linefeed. tj: db esc,'J$',0 ;Clear to end of screen. tk: db esc,'K$',0 ;Clear to end of line. ; ; ; Escape sequences to map CP/M Reader/Punch to Data Comm input/output, ; respectively and to turn off these mappings ; mapon1: db esc,'&i10s18d9M' db esc,'&i2s25d9M' db esc,'&i10s16d2M' db esc,'&i0s25d2M$';Esc. sequences to turn off DAtacomm2/turn ;on Data Comm 1 mapon2: db esc,'&i10s16d9M' db esc,'&i0s25d9M' db esc,'&i10s18d2M' db esc,'&i2s25d2M$';Esc. sequences to turn off Datacomm1/turn ;on Datacomm 2 mapoff: db esc,'&i0s25d9M' db esc,'&i10s16d9M' db esc,'&i2s25d9M' db esc,'&i10s18d9M$' ; readin: call $-$ ;Read character into b mov a,b ;Get 8-bit character ret ;and return ; jbuf: db 7 ;bios dispatch table vector argument block db 0 ;to read RDR routine address db 0c3h ;... dw 0 ;... ; ENDIF;hp125 ;[MF] IF lasm and termin ; if no terminal, no need to link LINK CPXVDU.ASM ENDIF ; lasm and termin ovlend EQU $ IF lasm END ; If m80 then this ignored ENDIF ; lasm