PAGESIZE 71 TITLE 'BYE86' ; This program was given to Bill Spoolhoff by the author, Ed Bertness, ; SYSOP of the San Antonio HUG. It was origionally written to run under ; CP/M-86 on the HEATH ZENITH Z-100. It was modified for use with a ; COMPUPRO S-100 CP/M 8-16 system. Do not delete the authors' copyright ; notice in the welcome message note in further editions or versions. ; ; Use of this program in commercial enterprise for monetary gain is ; strictly forbidden under the U.S. copyright laws. Please send any re- ; visions of this program to Atlas Micro Associates "MCI" BBS-RCP/M. We ; will serve as a collection point for forwarding to the author for fur- ; ther distribution. ; ; *** system equates *** ; BDOS EQU 0E0H ;bdos interrupt BDOSBP EQU 24A0H ;bdos data page base \ MONTH EQU 24C0H ;month location in bdos \ DAYS EQU 24C3H ;days location in bdos \ using the proper system YEARS EQU 24C6H ;years location in bdos > call will eliminaea all HOURS EQU 24C9H ;hours location in bdos / this - do a syscall 31h MINS EQU 24CBH ;minutes location in bdos / SECS EQU 24CDH ;seconds location in bdos / NXTAVL EQU 1 ;offset into memtable for available memory BCONST EQU 2806H ;bios console status jmp location BCONIN EQU 2809H ; " " input " " BCONOUT EQU 280CH ; " " output " " JUMP EQU 0E9H ;intra-segment direct jump instruction JUMPF EQU 0EAH ;inter-segment direct jump instruction CALLN EQU 0E8H ;intra-segment call instruction CALLF EQU 09AH ;inter-segment call instruction COMDRIV EQU 0 ;drive for cmd (com) files (0 = drive a:) BBSUSR EQU 0EH ;user area for bbs file (user #14) SYSUSR EQU 0 ;user area for system files DFTDRV EQU 0736H ;location in bdos for default drive # DFTUSR EQU 0737H ;location in bdos for default user # ; cpm system calls SRESET EQU 0 ;reset SCONIN EQU 1 ;console input SCONOUT EQU 2 ;console output SDCIO EQU 6 ;direct console i/o SGIOB EQU 7 ;get i/o byte SSIOB EQU 8 ;set i/o byte SPRTSTR EQU 9 ;print string SRDBUF EQU 0AH ;read console buffer SCONST EQU 0BH ;get console status SRSTDSK EQU 0DH ;reset disk system SSELDSK EQU 0EH ;select disk drive SGETDRV EQU 19H ;get current drive SUSER EQU 20H ;set/get user # SCHAIN EQU 2FH ;chain program SSYSDAT EQU 31H ;get system data address SBIOS EQU 32H ;direct bios call SGETDMA EQU 34H ;get dma base ; bios call # for direct bios call system call CBOOT EQU 0 ;cold boot initialize WBOOT EQU 1 ;warm boot CONST EQU 2 ;get console status CONIN EQU 3 ;input console character CONOUT EQU 4 ;output console character PRNTR EQU 5 ;write character to printer PUNCH EQU 6 ;write punch character READER EQU 7 ;read reader character HOME EQU 8 ;move to track 00 SELDSK EQU 9 ;select disk drive SETTRK EQU 10 ;set track number SETSEC EQU 11 ;set sector number SETDMA EQU 12 ;set dma offset address READ EQU 13 ;read selected sector WRITE EQU 14 ;write selected sector LISTST EQU 15 ;return list status SECTRAN EQU 16 ;sector translate SETDMAB EQU 17 ;set dma segment address GETSEGB EQU 18 ;get mem desc table offset GETIOB EQU 19 ;get i/o byte SETIOB EQU 20 ;set i/o byte ; ascii constants CR EQU 0DH ;carriage return LF EQU 0AH ;line feed ESC EQU 1BH ;escape character CTRLC EQU 'C'-40H ;control c CPMEOM EQU '$' ;end of message ; flag values for i/o routines CHRRDY EQU 00000001B ;character ready at modem XCHRRDY EQU 11111110B ;mask to turn off chrrdy ONLINE EQU 00000010B ;phone answered, system on line XONLINE EQU 11111101B ;mask to turn off xonline UPCON EQU 00000100B ;upper case only UPCOFF EQU 00000000B ;lower case ok UPCMSK EQU 11111011B ;upper case mask ANYNULL EQU 11110000B ;mask to test for nulls ; ***!!! the following equates are all hardware dependent !!!*** ; *** serial port equates *** DATPORT EQU 0E1H ;modem data port STPORT EQU 0E0H ;modem status port RPORT EQU 0E2H ;modem mode port CPORT EQU 0E3H ;modem command port ; switch hook & modem commands out to stport BYE EQU 0 ;hangup ANSW EQU 2 ;off hook answer mode BIT8 EQU 0CH ;eight data bits NOPY EQU 10H ;no parity TSB EQU 40H ;2 stop bits NORM EQU BIT8+NOPY ;normal 8 bits no parity P110 EQU BIT8+NOPY+TSB ;same w/2 stop bits ; modem status input on rport DTD EQU 1 ;dial tone detect RDET EQU 2 ;ring detect CTS EQU 4 ;carrier detect CONN EQU 10H ;connected 0=yes 1=no ; control port filter masks LE300 EQU 7FH ;less than or equal to 300 baud GT300 EQU 5FH ;greater than 300 baud ; baudrate divisors B300 EQU 52 ;300 baud B600 EQU 26 ;600 baud ; pmmi status masks TRDY EQU 1 DAV EQU 2 OE EQU 10H FE EQU 20H ANYERR EQU FE OR OE ; miscellaneous equates MHZ EQU 8 CWAIT EQU 20 ; ***keyboard equates*** KEYST EQU 055H ;keyboard status port KEYRDY EQU 1 ;keyboard has data available ;======================================================================= ; ; program starts here ; ;======================================================================= CSEG ORG 100H ; entry point START: CALL GETOSEG ;go get operating system base address CALL CHKUSR ;q - are we set to user 0? JE USROK ;yes - don'T BOTHER TO SET IT CALL SETDU ; else set user 0 USROK: CALL CHKDRV ;q - are we set to drive 0? JE DRVOK ;yes - don'T SET IT CALL SETDU ; else set drive 0 DRVOK: CALL GETMSEG ;get first segment of free memory CALL CHECK ;q? have we been loaded once? JZ NOFIX ;yes - forget this stuff CALL SETSEG ; else compute new segment for mem pointers CALL MEMFIX ; move memory and adjust jumps, calls, etc. CALL SIGNON ; sign on system NOFIX: CALL CARDET ;q - did remote type "bye"? JNZ BYPASS ;yes- say goodbye and hangup CALL HANGUP2 ; else don'T SAY GOOD-BYE AND HANG UP BYPASS: CALL HANGUP ;say good bye,turn off modem CALL ANSLOOP ;and wait for call WAITCAR:CALL CARDET ;q - detect carrier? JNZ CAROK PUSH CX MOV CX,CWAIT*10 ;wait for the carrier DEL1: CALL CARDET JNZ CAROK CALL DELAY ;delay loop LOOP DEL1 POP CX JMP BYPASS ;no carrier go back and hangup CAROK: CALL SETBD ;do speed detection CALL SETFLG ;let i/o system know we'RE ON LINE CALL HELLO ;send greeting & version # CALL GETNUL ;get # of nulls CALL GETUPC ;check lower case capability EXIT: CALL PRLDMSG ;say we are loading RBBS MOV AX,SYSSEG ;\ MOV ES,AX ; \ set user # of MOV BX,DFTUSR ; / com file - rbbs MOV ES:BYTE PTR [BX],BBSUSR ;/ in this instance ; move the command line into the dma area and do a program chain sys call MOV CL,SGETDMA INT BDOS MOV SI,OFFSET CMDLINE MOV CX,(OFFSET ENDCMD) - (OFFSET CMDLINE) + 1 MOV DI,BX REP MOVSB MOV CL,SCHAIN INT BDOS ; get segment in which operating system resides GETOSEG:MOV CL,SSYSDAT INT BDOS MOV AX,ES MOV SYSSEG,AX RET ; check that we'RE IN USER AREA 0 CHKUSR: MOV CL,SUSER MOV DL,0FFH INT BDOS CMP AL,0 RET ; check that we'RE LOGGED ONTO DRIVE 0 CHKDRV: MOV CL,SGETDRV INT BDOS CMP AL,0 RET ; set drive and user to 0 SETDU: MOV AX,SYSSEG MOV ES,AX MOV BX,DFTDRV MOV ES:BYTE PTR [BX],0 INC BX MOV ES:BYTE PTR [BX],0 RET ; move essential stuff to reside just above bios and patch memory ; pointers in the 'BIOS' to keep this code resident at all times. ; ; enter: none ; exit: es: = operating system segment ; ax = segment # of next available memory ; bx = offset in segment 40 to read/write lower memory bound GETMSEG:MOV BCALL1,GETSEGB ;get offset to bios memory area MOV CL,SBIOS MOV DX,OFFSET BCALL1 INT BDOS ADD BX,NXTAVL ;pointer is offset 1 into table MOV AX,SYSSEG MOV ES,AX MOV AX,ES:[BX] ;ax contains seg of next available mem RET ; check to see if bye has already been loaded once ; ; enter: es: = operating system segment ; ax = segment # of next available memory (lower bound) ; bx = offset in segment 40 to read/write lower memory bound ; exit: ax = segment # of next available memory (lower bound) ; bx = offset in segment 40 to read/write lower memory bound ; dx = length of moved portion in paragraphs ; es: = segment of fix - if there CHECK: PUSH AX MOV DX,(PGMLEN+15)/16 ;get length of pgm in paragraphs SUB AX,DX MOV ES,AX MOV SI,CS:OFFSET IDMSG MOV DI,(OFFSET IDMSG) - (OFFSET CONSTE) MOV CX,(OFFSET ENDMSG) - (OFFSET IDMSG) REPE CMPSB JNZ SEGOK MOV NEWSEG,AX POP AX RET SEGOK: POP AX MOV NEWSEG,AX RET ; set new segment for lower memory bound ; enter: ax = segment # of next available memory (lower bound) ; bx = offset in segment 40 to read/write lower memory bound ; dx = length of moved portion in paragraphs ; es: = segment of fix, if there ; exit: ax = length of available memory ; bx = offset in segment 40 to avail mem length ; cx = segment # of next available memory (lower bound) ; dx = length of moved portion in paragraphs ; es: = operating system segment SETSEG: PUSH DX MOV CX,AX MOV AX,SYSSEG MOV ES,AX ADD DX,CX MOV ES:[BX],DX POP DX ADD BX,2 MOV AX,ES:[BX] SUB AX,DX MOV ES:[BX],AX RET ; memfix - move the necessary portions of bye86 and patch required jumps ; in 'BIOS' ; ; enter: ax = ? ; bx = offset in segment 40 to avail mem length ; cx = segment # of next available memory (lower bound) ; dx = length of moved portion in paragraphs ; es: = operating system segment ; exit: (after moveit) ; ax = (pop) seg # next avail mem ; bx = offset in segment 40 to avail mem length ; cx = # of paragraphs offset from beginning of o.s. to fix ; dx = # of bytes offset from beginning of o.s. to fix ; ds: = segment where we expect to find bye86, if loaded ; es: = operating system segment MEMFIX: PUSH CX ;save segment # for new i/o calls SUB CX,SYSSEG ;rationalize segment # to 40h (operating sys) MOV AX,CX ;\ MOV CL,4 ; > compute offset relative to 40h SHL AX,CL ;/ MOV DX,AX CALL MOVEIT ;move routines low memory POP DS ;put segment # in ds MOV CX,DX ; and offset in cx MOV AX,(OFFSET FLAG) - (OFFSET CONSTE) ;compute new offsets ADD AX,DX ;for the locations MOV BX,(OFFSET PTCHF1) - (OFFSET CONSTE) ;flag, ptchf1 - ptchfa, MOV DS:[BX],AX ;& patch1 MOV BX,(OFFSET PTCHF2) - (OFFSET CONSTE) ;write them in their MOV DS:[BX],AX ;new locations in low MOV BX,(OFFSET PTCHF3) - (OFFSET CONSTE) ;memory. ptchf1 - a MOV DS:[BX],AX ;all point to the same MOV BX,(OFFSET PTCHF4) - (OFFSET CONSTE) ;location. MOV DS:[BX],AX ; MOV BX,(OFFSET PTCHF5) - (OFFSET CONSTE) ; MOV DS:[BX],AX ; MOV BX,(OFFSET PTCHF6) - (OFFSET CONSTE) ; MOV DS:[BX],AX ; MOV BX,(OFFSET PTCHF7) - (OFFSET CONSTE) ; MOV DS:[BX],AX ; MOV BX,(OFFSET PTCHF8) - (OFFSET CONSTE) ; MOV DS:[BX],AX ; MOV BX,(OFFSET PTCHF9) - (OFFSET CONSTE) ; MOV DS:[BX],AX ; MOV BX,(OFFSET PTCHFA) - (OFFSET CONSTE) ; MOV DS:[BX],AX ; MOV BX,(OFFSET PATCH1) - (OFFSET CONSTE) ; MOV AX,[BX] ; ADD AX,DX ;the following routines MOV DS:[BX],AX ;set up the pointers MOV BX,BCONST ;to the old and new MOV DX,(OFFSET CONSTE)-(OFFSET CONSTE) ;bios routines. fixit MOV AX,(OFFSET CON1)-(OFFSET CONSTE) ;computes the offset CALL FIXIT ;from the old jump to MOV BX, BCONIN ;the new jump and MOV DX,(OFFSET CONINE)-(OFFSET CONSTE) ;writes it in the old MOV AX,(OFFSET CON2)-(OFFSET CONSTE) ;bios jump location. CALL FIXIT ;it then computes the MOV BX, BCONOUT ;offset from the new MOV DX,(OFFSET CONOUTE)-(OFFSET CONSTE) ;location to the loca- MOV AX,(OFFSET CON3)-(OFFSET CONSTE) ;tion the old jump took CALL FIXIT ;and saves it in the MOV CX,(OFFSET CON2A) - (OFFSET CON1) ;new routine. MOV BX,(OFFSET CON1) - (OFFSET CONSTE) + 1 ; ** this routine MOV AX,DS:[BX] ;computes the offset SUB AX,CX ;for the call at loca- MOV BX,(OFFSET CON2A) - (OFFSET CONSTE) + 1 ;tion con2a of the new MOV DS:[BX],AX ;routines in low memory RET ; routine to patch 3 bios jump locations - enter with bx = offset ; (relative to 400h) of 'BIOS' jump instruction in 'BX', and offset ; (relative to beginning of available low memory) of new 'BIOS' jump ; in 'AX'. ; ; entry: ; ds: base of available memory - where the new routines ; will be moved ; es: beginning of operating system (seg 40h, 400h absolute) ; ax offset of jump vector in new routine relative to ds ; bx offset of old console routine relative to es ; cx offset of new program area relative to es (40h) ; dx offset of new console routine relative to ds ; FIXIT: PUSH CX PUSH DX MOV DX,AX INC BX MOV AX,ES:[BX] ADD AX,2 ADD AX,BX ADD CX,DX ADD CX,3 SUB AX,CX INC DX XCHG BX,DX MOV DS:[BX],AX XCHG BX,DX POP DX POP CX MOV AX,BX ADD AX,2 ADD DX,CX SUB DX,AX MOV ES:[BX],DX RET ; routine to relocate program ; ; enter: dx = # of bytes offset from beginning of o.s. to fix ; cs: = cs ; es: = operating system segment ; exit: program relocated ; ax = cs: ; cx = pgmlen ; ds: = cs: MOVEIT: MOV DI,DX MOV SI,OFFSET CONSTE MOV CX,PGMLEN REP MOVSB RET ;****************************************************************** ;*** hardware dependent code follows *** ;*** the following routines will work on a heath h100 computer *** ;****************************************************************** ; ** print signon - set time, date, and statistics in 25th line ** SIGNON: MOV AX,SYSSEG ;get operating system segment MOV DS,AX MOV SI,OFFSET MONTH MOV AX,CS MOV ES,AX MOV DI,OFFSET CAL MOV CX,8 REP MOVSB INC SI MOV DI,OFFSET TIME MOV CX,8 REP MOVSB MOV AX,CS MOV DS,AX MOV ES,AX LEA DX,LOADMSG MOV CL,SPRTSTR INT BDOS RET ; ** check modem port to see if there is a carrier ** CARDET: IN AL,RPORT ;get ring port NOT AL ;reverse for pmmi logic TEST AL,CTS ;see if car is present RET ; ** turn off dtr - forcing modem to hang up ** HANGUP: CALL SIGNOFF HANGUP2:MOV AX,NEWSEG MOV ES,AX MOV BX,(OFFSET FLAG) - (OFFSET CONSTE) MOV AL,ES:[BX] AND AL,XONLINE MOV ES:[BX],AL MOV AL,BYE OUT STPORT,AL ;reset port OUT CPORT,AL RET ; delay routine DELAY: PUSH CX MOV CX,4167*MHZ ;timing constant * clock mhz DELAY1: LOOP DELAY1 POP CX RET ; ** answer loop - monitor modem port for ring - keep track of keyboard ; for a 'CTL-C' ** ANSLOOP:IN AL,RPORT ;get ring status NOT AL ;reverse for pmmi logic TEST AL,RDET ; ringing? JNZ ANSWER ; - yes, go answer CALL KBDST ; - no, go check keyboard for abort ; has key been typed? JZ ANSLOOP ; - no, go back and check for ring CALL GETCHAR ; - yes, get character CMP AL,CTRLC ; ^c? JNZ ANSLOOP ; - no, go back and check for ring LEA DX,QUERY ; - yes, ask if for real MOV CL,SPRTSTR INT BDOS CALL GETCHAR ;get response CALL FIXUPC CMP AL,'Q' ; quit? JNZ ANSLOOP ; - no, go back to check ring POP AX ;clear stack JMP REMOVE ; ** answer phone and set proper baud rate ** ANSWER: IN AL,RPORT ;was it a ring or relay bounce NOT AL ;reverse for pmmi logic TEST AL,RDET ;test it JZ ANSLOOP ;no go back and wait for a real ring ENDRING:CALL DELAY ;delay till it stops ringing IN AL,RPORT ;check again NOT AL ;pmmi logic TEST AL,RDET JNZ ENDRING ;loop till ringing stops ANSWER1:MOV AL,LE300 ;filter value for 300 bps (dtr) OUT CPORT,AL CALL DELAY ;give it time to turn on MOV AL,P110+ANSW ;answer it OUT STPORT,AL CALL DELAY ;give it time to answer IN AL,DATPORT ;clear modem port IN AL,DATPORT ;make sure it is clear RET ; set the baud rate SETBD: MOV AL,LE300 ;filter value for less than or = 300 bps OUT CPORT,AL MOV AL,NORM ;set for 8 bits,no parity,1 stop bit OUT STPORT,AL MOV AL,B300 ;set the divisor to 300 bps OUT RPORT,AL CHKBD1: IN AL,RPORT ;is carrier still there NOT AL ;pmmi logic TEST AL,CTS JZ ABORT ;no IN AL,STPORT ;yes,now check it for data available TEST AL,DAV JZ CHKBD1 ;no try again IN AL,DATPORT ;yes, then take it AND AL,07FH ;strip the parity CMP AL,CR ;is it a carriage return JNZ NOTHI ;no JMP SPDOK ;yes NOTHI: JMP SETBD ;if it was no do it again SPDOK: LEA DX,FRSTMSG MOV CL,SPRTSTR INT BDOS ABORT: RET ; ************************************ ; *** end of system dependent code *** ; ************************************ ; print the sign on message HELLO: LEA DX,GRTING MOV CL,SPRTSTR INT BDOS RET PRLDMSG:LEA DX,LDMSG MOV CL,SPRTSTR INT BDOS RET ; check keyboard status from local console - returns zero flag set if ; character ready KBDST: MOV CL,SCONST INT BDOS TEST AL,1 RET ; get local keyboard character - keyboard status should have indicated ; that a character is ready GETCHAR:MOV CL,SCONIN INT BDOS RET ; remove bye86 from memory and put everything back the way it was REMOVE: MOV AX,SYSSEG MOV ES,AX MOV AX,NEWSEG SUB AX,SYSSEG MOV CL,4 SHL AX,CL MOV DX,AX MOV BX,(OFFSET CON1) - (OFFSET CONSTE) + 1 MOV CX,(OFFSET BCONST) + 1 CALL REMOV1 MOV BX,(OFFSET CON2) - (OFFSET CONSTE) + 1 MOV CX,(OFFSET BCONIN) + 1 CALL REMOV1 MOV BX,(OFFSET CON3) - (OFFSET CONSTE) + 1 MOV CX,(OFFSET BCONOUT) + 1 CALL REMOV1 CALL REMOV2 MOV BCALL1,GETSEGB ;get offset to bios memory area MOV CL,SBIOS MOV DX,OFFSET BCALL1 INT BDOS ADD BX,NXTAVL ;pointer is offset 1 into table MOV AX,NEWSEG MOV ES:[BX],AX ADD BX,2 MOV AX,ES:[BX] ADD AX,(PGMLEN + 15)/16 MOV ES:[BX],AX MOV CL,SRESET MOV DL,0 INT BDOS REMOV1: ADD BX,DX MOV AX,ES:[BX] ADD AX,BX SUB AX,CX MOV BX,CX MOV ES:[BX],AX RET ; remove all the patches to the bios and reset memory pointers REMOV2: PUSH DX LEA DX,TURNOFF MOV CL,SPRTSTR INT BDOS MOV CX,PGMLEN MOV AX,0 POP BX ZERO: MOV ES:[BX],AX INC BX LOOPNZ ZERO RET ; set the flag byte in the new i/o routines to show that the modem is ; on line SETFLG: MOV AX,NEWSEG MOV ES,AX MOV BX,(OFFSET FLAG) - (OFFSET CONSTE) MOV AL,ES:[BX] OR AL,ONLINE MOV ES:[BX],AL RET ; get the number of nulls required after cr GETNUL: LEA DX,NULMSG MOV CL,SPRTSTR INT BDOS CALL GETCHAR SUB AL,'0' CMP AL,0AH JNC GETNUL MOV CL,4 SHL AL,CL MOV CL,AL MOV AX,NEWSEG MOV ES,AX MOV BX,(OFFSET FLAG) - (OFFSET CONSTE) MOV AL,ES:[BX] OR AL,CL MOV ES:[BX],AL RET ;get upper case conversion option GETUPC: LEA DX,UPCMSG MOV CL,SPRTSTR INT BDOS CALL GETCHAR CALL FIXUPC CMP AL,'Y' MOV AH,UPCOFF JZ SETUPC CMP AL,'N' MOV AH,UPCON JNZ GETUPC SETUPC: PUSH AX MOV AX,NEWSEG MOV ES,AX MOV BX,(OFFSET FLAG) - (OFFSET CONSTE) MOV AL,ES:[BX] AND AL,UPCMSK POP DX OR AL,DH MOV ES:[BX],AL RET ;print the sign off message SIGNOFF:LEA DX,GDBYE MOV CL,SPRTSTR INT BDOS RET ; 'BIOS' comes here first to check console status - if modem port has a ; character, return to calling routine with al = 0ffh. else jump to ; normal bios status check for local keyboard. CONSTE: TEST FLAG,ONLINE ;put no instructions between the flag PTCHF1 EQU (OFFSET $) - 3 ;test and this patch pointer JZ CONX1 IN AL,RPORT ;check modem for carrier NOT AL ;pmmi logic TEST AL,CTS JNZ CNSTE1 ;yes JMP QUIT ;no CNSTE1: IN AL,STPORT ;now see if data is available TEST AL,DAV JNZ RMSTAT ;yes CONX1: CON1 DB JUMP DW 0 RMSTAT: OR FLAG,CHRRDY ;do not put any instructions between PTCHF2 EQU (OFFSET $) - 3 ;these two MOV AL,0FFH ;yes modem has a character RET ;*********************************************************************** ;*** the following routines are all relocated to just above the bios *** ;*********************************************************************** ; 'BIOS' comes here first for console input. check modem port for ; character. if modem has character available, return to the calling ; routine, else go to 'BIOS' for local console input. CONINE: TEST FLAG,ONLINE ;don't put any instructions between PTCHF3 EQU (OFFSET $) - 3 ;these two JZ CONX2A IN AL,RPORT ;check for carrier NOT AL ;pmmi logic TEST AL,CTS JNZ CONIN1 ;yes JMP QUIT ;no CONIN1: IN AL,STPORT ;now check for data available TEST AL,DAV JNZ RDMDAT ;yes TEST FLAG,CHRRDY ;again no instructions between PTCHF4 EQU (OFFSET $) - 3 ;these JNZ RDMDAT CONX2A: CON2A DB CALLN DW 0 TEST AL,CHRRDY JZ CONINE CON2 DB JUMP DW 0 RDMDAT: IN AL,DATPORT ;take the data AND AL,07FH ;strip the parity AND FLAG,XCHRRDY ;same here, no instructions between PTCHF5 EQU (OFFSET $) - 3 ;these two RET ; 'BIOS' comes here to output character - dual output to local and ; remote consoles CONOUTE:TEST FLAG,ONLINE ;do not put any instructions between PTCHF6 EQU (OFFSET $) - 3 ;these two JZ CONX3 PUSH CX PUSH AX OUTE1: IN AL,RPORT ;check for carrier NOT AL ;pmmi reverse logic TEST AL,CTS JZ NOCAR ;no IN AL,STPORT ;yes,now check the out status TEST AL,TRDY ;are we ready to xmit JZ OUTE1 ;no then check again MOV AL,CL ;yes,move output char. from c to a AND AL,07FH ;strip parity TEST FLAG,UPCON ;no instructions between this one PTCHF7 EQU (OFFSET $) - 3 ;and this patch pointer JZ NOTUPC CALL FIXUPC NOTUPC: OUT DATPORT,AL ;output it w/not all upper case CMP AL,CR JNZ NONULS TEST FLAG,ANYNULL ;do not separate this flag test PTCHF8 EQU (OFFSET $) - 3 ;and this patch pointer JZ NONULS MOV AL,FLAG ;same PTCHF9 EQU (OFFSET $) - 2 ;here MOV CL,4 SHR AL,CL XOR CX,CX MOV CL,AL OUTLP: IN AL,STPORT ;still ready to xmit TEST AL,TRDY JZ OUTLP MOV AL,0 OUT DATPORT,AL ;output a null LOOPNZ OUTLP NONULS: POP AX POP CX CONX3: CON3 DB JUMP DW 0 FIXUPC: CMP AL,'a' JB UPC1 CMP AL,'z' JA UPC1 AND AL,05FH UPC1: RET NOCAR: POP AX POP CX QUIT: AND FLAG,XONLINE ;here's another group PTCHFA EQU (OFFSET $) - 3 ;of MOV CL,SGETDMA ;instructions INT BDOS ;that MOV SI,(OFFSET IDMSG) - (OFFSET CONSTE) ;you PATCH1 EQU (OFFSET $) - 2 ;should MOV DI,BX ;not MOV CX,(OFFSET ENDMSG) - (OFFSET IDMSG) + 1 ;separate REP MOVSB ;these MOV CL,SCHAIN ;also INT BDOS ;do not separate FLAG DB 0 IDMSG DB 'BYE' ENDMSG DB 0 PGMLEN EQU (OFFSET $) - (OFFSET CONSTE) ; ******************************* ; *** end of relocatable area *** ; ******************************* ; data area GRTING DB CR,LF,LF,'WELCOME TO BYE86 - VER. 1.0 - 7/8/84' DB CR,LF,'COPYRIGHT 1984 - ED BERTNESS',CR,LF,CPMEOM GDBYE DB CR,LF,LF,'GOOD BYE - THANKS FOR CALLING' DB CR,LF,'ATLAS MICRO ASSOCIATES'' MCI' DB CR,LF,'BULLETIN BOARD SYSTEM',CR,LF,LF,LF,CPMEOM QUERY DB CR,LF,'IF YOU WISH TO EXIT PROGRAM - TYPE ''Q''' DB CR,LF,'- ANY OTHER KEY TO RESUME',CR,LF,CPMEOM NULMSG DB CR,LF,'HOW MANY NULLS DOES YOUR TERMINAL REQUIRE? (0-9) - ' DB CPMEOM UPCMSG DB CR,LF,'CAN YOUR TERMINAL DISPLAY LOWER CASE? (Y OR N) - ' DB CPMEOM LOADMSG DB CR,LF,'LOADED ',CR,LF,CPMEOM CAL DB 0,0,0,0,0,0,0,0,' ' TIME DB 0,0,0,0,0,0,0,0,' COUNT = 00000 ' DB ' ' DB CPMEOM LDMSG DB CR,LF,'LOADING BULLETIN BOARD SYSTEM - ' DB 'PLEASE STAND BY.',CR,LF,CPMEOM FRSTMSG DB '//',CPMEOM TURNOFF DB CPMEOM CMDLINE DB 'MENTER' ENDCMD DB 0 ENDDU DB 0 SYSSEG DW 0 NEWSEG DW 0 BCALL1 DB 0 BCALL2 DW 0 BCALL3 DW 0 OLDPTR DW 0