home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol065
/
bye78.asm
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
71KB
|
2,979 lines
; TITLE 'BYE V7.8 AS OF 02/20/82'
; PAGE 44
;
; BYE V7.8 (revised 02/20/82)
; REMOTE CONSOLE PROGRAM FOR CP/M AND MODEM
;
;This program allows modem callers to use your CP/M system
;just as if they were seated at the system console. Special
;assembly-time options allow limiting the caller's access by
;password and/or access to only a message-service program.
;
;Based on an original program written by Dave Jaffe, January 1979
;Rewritten for PMMI modem by Ward Christensen, February 1979.
;This program now supports DC Hayes, PMMI, and external modems.
;The UARTS supported are the Intel 8251 and the Western Digital 8250.
;Be sure to set the equates for the modem you are using.
;
;*************************************************************************
;DANGER: Pay close attention to the polarity of the jump instructions *
;after any in from a uart when running under 8250/8251's, I have tried *
;to fix them for the most common logical setup, but your system may *
;differ. *
;*************************************************************************
;
;Thanks to Bill Precht for the "label + offset" idea allowing
;this program to relocate itself without using DDT to initially
;set it up.
;
;Modifications/fixes: (in reverse order to minimize reading time)
;
;02/03/82 Fixed the buggy conditional jumps in/after RINGWT.
; Now there is conditional assembly depending on if you are
; a WD8250/IN8251 or a "standard" system.
; Fixed a few bugs in conditional assembly.
; Improved LF code.
; -- Paul S Traina
;
;01/20/82 Add equates and routines for HEATH or IMS systems and any
; other systems using External modems and the WD8250 UART.
; Included assembly option for compatability with RBBS,
; MINICBBS, and OXGATE implimentations. by Thom Quick
;
;01/09/82 Added WRTLOC flag for use with an RBBS program that sets
; this flag during disk writes; avoids files out of synch
; problem if caller hangs up during writes. Added MINICK
; routines which do the same with MINICBBS. Added patch
; to allow bye to run below the CCP with programs such as
; TYPESQ. Separated Superb conditional assembly into Externl
; and LOSER, this separates external modem operation from a
; losing feature of a particular BIOS. (P. L. Kelley)
;
;12/03/81 Implemented OxGate protocol, fixed some bugs in conditional
; equates. Variables for UCLSW and NULLS moved up so that
; programs can poke them too. (Paul Traina)
;
;12/02/81 Make variables for MAXDRV, MAXUSR, and TOVALUE that
; can be found via the warm boot BIOS vector at zero,
; so that these values can be changed while BYE is
; running to accomodate privileged users, either through
; action of the BYE-run .COM file or some other password
; program run later. Move MCBOOT and the USRLOG vector
; to just after the START vector, for easier access
; if desired.
;
;11/04/81 Print out BYE version number in PRNLOG, to allow
; program to be identified easily when running. Call
; USRCHK in all cases to print out version number on
; local ctrl-C, then ask to resume BYE instead of
; warm boot. Convert many msgs to upper/lower case.
; By Steve Bogolub
;
;10/24/81 Modified NOPASS so that COM files that look for
; a second file on the command line (such as HELP18)
; will find a 20H at FCB+1 for default purposes. Also
; added RUNCOM at the end of NOPASS and changed the
; jumps to the TPA (100h) to a CALL so that a COM file
; will return to BYE where a clean jump to warm boot
; can be done instead of going off to never-never land.
; R. L. Plouffe
;
;10/11/81 Print password on local console with DUAL$IO. Allow
; return from PRNLOG with USRLOG. Make <CR><LF> instead
; of <LF><CR> in USRLOG reports. Print out BYE version
; number for easy identification. Position PRNLOG after
; cold boot routine, and change cold boot routine to
; jump to MBOOT, thereby defining path to PRNLOG for
; all BYE programs and allowing one trivial program
; that can be run to get the BYE log. Make counters
; 16 bits for greater range. By Steve Bogolub
;
;10/01/81 Added CALL CHECK to MSTAT routine to eliminate
; possibility of system crash when carrier lost while
; performing repeated console status checks without
; any console output. This problem occurs during the
; password input of USERPW.ASM, and potentially any other
; program that does repeated direct console input, such
; as MBASIC, etc.
; By Ron Fowler and Dave Hardy
;
;05/14/81 Added CCS disk support (to turn off disks when idle)
; Added support for Godbout SS1 Real time clock.
; Added Phone to Lister, Punch & Reader patch. (AAJ)
;
;03/20/81 Fixed MOUTPUT so parity bit is stripped before outputting
; character to modem. Corrected 3/18/81 null fix. Added
; additional description to heading of this file. (KBP)
;
;03/18/81 Add first-ring debounce routine, change PMMI HANGUP
; to do break for faster disconnect, fix error in P3TODTR
; equate for PMMI, added end-of-program error message to
; mark ending address (see note at label DEST). By KBP.
; Fix bug that prevented nulls at end of line if DUAL$IO
; was true. By Hank Szyszka.
;
;02/23/81 Conditional assembly added for Intertec SuperBrain
; with Racal-Vadic 3451 modem. Corrected lack of RET in
; CONIN. In MOUTPUT, replaced CZ CHECK with JNZ SILENT,
; CALL CHECK; this eliminates chance of looping in MOUTPUT
; if modem doesn't empty USART after carrier lost.
; Also had to write a routine to patch BIOS so that after
; the warm boot disk read this program repatches the BIOS.
; Apparently the SuperBrain warm boot overwrites a portion
; of the BIOS. By P.L. Kelley
;
;02/17/81 Added check for extraneous control characters in
; hardcopy log. (Formfeed seems to be a common "hit").
; Changed local startup test to directly test for carrier
; instead of calling CARCK, to avoid 15 second delay.
; <BRR>
;
;02/15/81 Removed dependance on DC Hayes hardware timer so that
; DCHAYES conditional assembly is compatible with both
; old-style 80-103A and new-style MM100 boards.
; Rearranged patch list to "most recent first" order.
; Added message for invalid-drive test.
; Added ANI 7Fh to upper case conversion test so that
; it's not fooled by bit 7 being set.
; Added WELUSR equate for user # containing WELCOME file.
; Removed PTRPORT equate and changed hardcopy logic to
; work through the BIOS printer driver. <BRR>
;
;01/22/81 Changed carrier detect routine for DC Hayes to wait for
; 15 seconds after loss of carrier to return. <DAVID KOZINN>
;
;01/17/81 Changed timing loops to use DC Hayes hardware timer
; if present. <DAVID KOZINN>
;
;01/16/81 Added equates and code for the DC Hayes
; Micromodem 100. <DAVID KOZINN>
;
;09/23/80 Fixed bugs that prevented "bye /a" and "bye /c" from
; working properly. Also repaired several errors in
; conditional assembly nesting. By Ron Fowler
;
;09/20/80 Modified status checking during ring-wait routine to
; use cp/m BDOS call, as suggested by Keith Petersen.
; This should make the program more portable. Also
; added Bruce Ratoff's update to DCHBYE program (5.5),
; that allows the use of bye from non-zero user areas.
; By Ron Fowler
;
;09/19/80 Modified COM file load routine to prevent BDOS
; overwrite if the COM file won't fit in the TPA
; By Ron Fowler
;
;09/19/80 Added new '/' option C, which has the same affect as
; /A, except that /C loads the com file after answering
; the phone, while /A boots CP/M. By Ron Fowler
;
;09/19/80 Added conditional assembly to give the operator a
; 'twit' logout key. Added conditionals for 'message
; from operator' and 'system down in 5 minutes' keys.
; Added front-panel selection of hard-copy log, remote
; 'black-out', and password option. Also, if cpm/2 is
; used, a message is printed when an unsupported user
; area is entered. By Ron Fowler and Dave Hardy
;
;09/19/80 Modified to prevent re-load of the com file when
; a voice call comes in. Reset the DMA address back
; to 80h after the com file is loaded. By Ron Fowler
;
;09/16/80 Added conditional assembly to allow automatic
; loading of a com file instead of cp/m boot. Also
; added decimal usrlog counters as conditional
; assembly. By Ron Fowler
;
;09/15/80 Added conditional assembly for automatic timed
; log-out, drive and user number masking, lower
; case query at login, and cp/m 2.x. Thanks to
; Bruce Ratoff for the routines (lifted from his
; 'DCHBYE54.ASM') used to implement these functions
; NOTE: in order to implement the timed log-out, it
; was necessary to do timing in software loops.
; Therefore, a new equate, FASTCLK, has been added
; to allow for 4mhz clock speeds. Also added Bruce
; Ratoff's overrun/framing error checking when read-
; ing the modem port. By Ron Fowler
;
;07/16/80 Added "/R" command option to allow USRLOG
; counters to be reset upon entry. By Dave Hardy
;
;07/11/80 Added conditional assembly for password and
; user log routines, and routines to print USRLOG
; information on console after program exit.
; By Dave Hardy
;
;07/10/80 Added code to allow auto-answer after first
; or second ring for more reliable auto-answer
; when using "ringback" option. By Dave Hardy
;
;06/29/80 Added USRLOG routines to keep track of number
; of callers, and display on front panel
; of IMSAI (i.e. output number to port FFH).
; By Dave Hardy
;
;06/11/80 Added routines to allow conditional assembly for
; Morrow's Discus 2D board (all Rev's) with memory
; mapped I/O. Added 710 Baud rate selection option
; at sign-on. By Dave Hardy and Bruce Levison.
;
;01/24/80 Added routines to preserve registers when calling
; the user's CBIOS. Added conditional assembly for
; callback feature. Increased stack space to 60.
; By Keith Petersen.
;
;09/24/79 Added routines to allow automatic multiple baud
; rate selection, exit to CP/M from local console,
; echo nr. of nulls selected. By Keith Petersen,
; with thanks to Bob Mathias for suggestions.
;
;05/06/79 Added routine to allow "callback" operation so modem
; does not answer normal voice calls. By Robbin Hough
; and Keith Petersen, W8SDZ.
;
;------------------------------------------------
;
;This program runs up in high RAM. It gets there
;by being moved there when 'BYE' is typed.
;
;The program in high RAM does the following:
;
; 1. Hangs up the phone
; 2. Awaits ring detect, allows exit
; to CP/M if local KBD types CTL-C
; 3. Outputs carrier (see callback routines)
; 4. Awaits incoming carrier going to step 1
; if none found in 15 seconds
; 5. Asks number of nulls (0-9)
; 6. Types the file "WELCOME" from
; disk, allowing CTL-C to skip it
; 7. Asks for a password, allowing
; 5 tries to get it right.
; 8. When password entered, if used,
; drops into CP/M.
; 9. Caller can leave by hanging up,
; (any time carrier is lost, it
; waits 15 seconds, then goes
; back to step 1), or the caller
; may type the program name (BYE)
;
;------------------------------------------------
;
;System equates
;
FALSE EQU 0
TRUE EQU NOT FALSE
;
CR EQU 0DH
LF EQU 0AH
MINUTES EQU 20*60 ;CONSTANT FOR 1 MIN TIME DELAY
;
;Change the following equate to an area in your
;high memory where this program may patch itself in.
;Approximate memory requirements: 2k bytes or more,
;depending upon the options selected. A marker has
;been placed at the end to deliberately print an error
;message during assembly in order to determine the actual
;ending address of the program. The error message will
;not affect the assembly. Make sure you have memory
;available up to the address shown.
;
DEST0 EQU 0F900H ;RUNNING LOCATION OF CODE
;
;Change the following to specify either DCHAYES, PMMI or systems
;with EXTERNAL modems. Be sure to change either TPORT for PMMI or
;DATA for DCHAYES if they are not at the standard locations.
;
DCHAYES EQU TRUE ;TRUE FOR DC HAYES MODEM
PMMI EQU FALSE ;TRUE FOR PMMI MODEM
IN8251 EQU FALSE ;TRUE FOR EXTERNAL AND INTEL 8251
WD8250 EQU FALSE ;TRUE FOR EXTERNAL AND WESTERN DIGITAL 8250
;
;Change the following if you have a DC Hayes modem that is
;not based at 80H. All other port equates are based on this.
;
IF DCHAYES
DATA EQU 80H ;DC HAYES DATA PORT
ENDIF ;DCHAYES
;
;Change the following if you have a PMMI modem that is not
;based at 0C0H. All other port equates are based on this.
;
IF PMMI
TPORT EQU 0C0H ;UART CONTROL/STATUS PORT
ENDIF
;
IF WD8250
BASE$PORT EQU 20H
ENDIF
;
;You will likely also want to change the password,
;located below at label 'PASSWD', and the messages
;printed at label 'WELCOME' and just above label
;'HANGUP'. The names of the welcome and com files
;are at lables 'WELFIN' and 'COMFCB' respectively.
;
;****************************************************
;* Option configuration section *
;****************************************************
;
;-----------------General Options------------------
;
OXGATE EQU TRUE ;WANT TO RUN AN OXGATE NODE?
PRINTER EQU TRUE ;WANT TO RETAIN LIST DEVICE?
DUAL$IO EQU TRUE ;WANT CONSOLE & MODEM?
CALLBAK EQU FALSE ;WANT CALLBACK FEATURE?
PWRQD EQU FALSE ;WANT TO USE PASSWORD?
BOOTMSG EQU FALSE ;TRUE IF BOOT MESSAGE
FKEYS EQU TRUE ;WANT SPECIAL FUNCTION KEYS
USRLOG EQU FALSE ;WANT TO COUNT NUMBER OF USERS?
HARDLOG EQU TRUE ;WANT TO ECHO REMOTE KBD TO PRINTER?
TIMEOUT EQU TRUE ;WANT AUTO LOG-OFF FOR SLEEPY CALLERS?
TOVALUE EQU 5 ;MINUTES TO AUTO LOGOFF
COMFILE EQU TRUE ;WANT TO AUTOBOOT A COM FILE?
DECIMAL EQU TRUE ;WANT DECIMAL VALUES FOR LOGS?
TRAPLC EQU FALSE ;WANT TO TRAP LOWER CASE?
ALLDEV EQU FALSE ;RETAIN PUNCH, READER, LISTER
MINICK EQU FALSE ;TRUE IF MINICBBS
RBBSCK EQU FALSE ;TRUE IF RBBS SETS/RESETS FLAG AT 'WRTLOC'
IOBYTE EQU 0003 ;LOCATION OF INTEL IOBYTE
IOVAL EQU 0 ;INITIAL VALUE TO STORE IN IOBYTE
;
;----------System and hardware dependent options--------------
;
ZCPRT EQU TRUE ;TRUE IF RUNNING NewZCPR (IN SECURE MODE)
WHEEL EQU 0FFFFH ;LOCATION OF NZCPR'S WHEEL FLAG
BYELOW EQU FALSE ;TRUE IF BYE BELOW CCP
LOSER EQU FALSE ;TRUE IF WARM BOOT OVERWRITE PART OF THE BIOS
NORING EQU FALSE ;UART RING INDICATOR NOT AVAILABLE
CPM2 EQU TRUE ;USING CP/M 2.X?
MAXUSR EQU 15 ;SET TO 0 FOR CP/M 1.4
WELUSR EQU 14 ;USER # OF WELCOME FILE, CPM2 TRUE
COMUSR EQU 14 ;USER # OF COM FILE, CPM2 TRUE
FASTCLK EQU TRUE ;SET TRUE FOR 4MHZ CLOCK
MAXDRV EQU 3 ;HIGHEST DRIVE SUPPORTED
IMSAI EQU FALSE ;ADDS VARIOUS OPTIONS W/SENSE SW'S
TWITKEY EQU 'N'-40H ;KEYCODE TO LOG-OUT A CREEP
MSGKEY EQU 'Q'-40H ;KEYCODE TO PRINT 'MESG FROM OPER:'
SYSDKEY EQU 'O'-40H ;KEYCODE TO PRINT SYS DOWN MSG
SENSE EQU 0FFH ;SENSE SWITCH PORT NUMBER IMSAI TRUE
BLKOUT EQU FALSE ;SWITCH TO TURN OFF REMOTE SEND IMSAI TRUE
SELPASS EQU FALSE ;SWITCH TO REQUIRE A PASSWORD IMSAI TRUE
CCSDISK EQU FALSE ;SET TRUE IF CCS DISK CONTROLLER
RTC EQU FALSE ;SET TRUE IF GODBOUT SS1 BOARD
;
IF CCSDISK
;
DISKON EQU 071H ;MOTORS ON, SELECT DISK A
DISK EQU 34H ;DISK CONTROL PORT
DISKOFF EQU 051H ;MOTORS OFF, SELECT DISK A;
ENDIF ;CCSDISK
;
;Assignment of front-panel options to switches:
;
LOGSW EQU 01H ;TURN ON FOR HARDCOPY
PWDSW EQU 02H ;TURN ON FOR 'PASSWORD' MODE
BLACKSW EQU 04H ;TURN ON TO BLACK OUT REMOTE END
ENABLF EQU 08H ;TURN ON TO ENABLE SPL FUNC KEYS
;
IF BYELOW
DEST EQU DEST0+3 ;KEEP ON TARGET
;
;****WARNING *** WMLOC AND OLDBD ARE SYSTEM DEPENDENT****
;WMLOC can be found in the BIOS by tracing through the
;warm boot routine with DDT until you find:
; LXI H,OLDBD
; SHLD 0006
;WMLOC is the address containing the LSB of OLDBD
;
WMLOC EQU 0E04DH
OLDBD EQU 0D006H
;
ENDIF ;BYELOW
;
IF NOT BYELOW
DEST EQU DEST0
ENDIF ;NOT BYELOW
;
;There are some cases where warm boot overwrites the
;initial bios jump table. This problem was solved for
;the Superbrain 3.0 bios by finding a warmboot call
;to high in the bios. This call is then patched by
;BYE. The form of the call is:
; WBCALL CALL WMSTRT
;
IF LOSER
;
WBCALL EQU 0DE48H ;CHECK THIS IN YOUR BIOS
;
;The following location is called
;
WMSTRT EQU 0EE48H ;CHECK THIS IN YOUR BIOS
;
ENDIF ;LOSER
;
;****************************************************
;* End of option configuration section *
;****************************************************
;
;All modem I/O and control are here
;
;
;************ D.C. Hayes modem I/O area ************
;
IF DCHAYES
;
;Port equates
;
DPORT EQU DATA ;DATA PORT
STATUS EQU DATA+1
RPORT EQU STATUS ;MODEM STATUS PORT
CR1 EQU DATA+1
CR2 EQU DATA+2
CR3 EQU DATA+3
;
;Bit functions
;
; Status register
;
RRF EQU 1 ;RECEIVE REGISTER FULL
TRE EQU 2 ;TRANSMITTER HOLDING REGISTER EMPTY
PE EQU 4 ;PARITY ERROR
FE EQU 8 ;FRAMING ERROR
OE EQU 10H ;OVERRUN ERROR
TMR EQU 20H ;TIMER STATUS (MM100 ONLY)
CD EQU 40H ;CARRIER PRESENT
RI EQU 80H ;NOT RING INDICATOR (LOW TRUE)
P2RDET EQU RI ;SAME AS ABOVE
;
; Control register 1 (CR1)
;
EPE EQU 1 ;EVEN PARITY ENABLE
LS1 EQU 2 ;WORD LENGTH SELECT BIT 1
LS2 EQU 4 ;WORD LENGTH SELECT BIT 2
SBS EQU 8 ;STOP BITS
PI EQU 10H ;PARITY INHIBIT
TMIE EQU 20H ;TIMER INTERRUPTS ENABLE (MM100 ONLY)
;
; Control register 2 (CR2)
;
BRS EQU 1 ;BAUD RATE CONTROL
TXE EQU 2 ;TRANSMIT CARRIER ENABLE
MS EQU 4 ;MODE (0=ANSWER 1=ORIGINATE)
BRK EQU 8 ;SEND BREAK
ST EQU 10H ;SELF TEST
TIE EQU 20H ;TRANSMITTER INTERRUPT ENABLE
RIE EQU 40H ;RECEIVER INTERRUPT ENABLE (MM100 ONLY)
OH EQU 80H ;OFF-HOOK
;
ENDIF ;DCHAYES
;
;
;************ PMMI modem I/O area ************
;
IF PMMI
;
;PMMI modem port equates (TPORT previously done)
;
DPORT EQU TPORT+1 ;DATA PORT
RPORT EQU TPORT+2 ;RATE GEN/MODEM STATUS
CPORT EQU TPORT+3 ;MODEM CONTROL
;
;Switch hook and modem commands, output to TPORT (port 0)
;
P0BYE EQU 0 ;ON HOOK, OR DIALING BREAK
P0ORIG EQU 1 ;OFF HOOK, ORIG.
P0ANSW EQU 2 ;ANSWER PHONE
P08BIT EQU 0CH ;8 DATA BITS
P0NOPY EQU 10H ;NO PARITY
P0EPS EQU 20H ;EVEN PARITY SELECT
P0TSB EQU 40H ;2 STOP BITS
P0EI EQU 80H ;ENABLE INTERRUPTS
P0NORM EQU P08BIT+P0NOPY ;NORMAL 8 BITS, NO PARITY
P0110 EQU P08BIT+P0NOPY+P0TSB ;SAME W/2 STOP BITS
;
;Modem status, input on RPORT (port 3)
;
P2DTD EQU 1 ;DIAL TONE DETECT
P2RDET EQU 2 ;RING DETECT
P2CTS EQU 4 ;CTS (CARRIER DETECT)
P2RXBRK EQU 8 ;RECEIVE BREAK
P2CONN EQU 10H ;CONNECTED? (0=YES, 1=MODEM CHIP HUNG UP)
P2TMPUL EQU 80H ;TIMER PULSES (40% UP CYCLE)
;
;Timer rate selection
;
TRATE EQU 250 ;VALUE FOR .1 SEC
;
;PMMI modem status masks
;
P0TBMT EQU 1 ;XMIT BUFF EMPTY
P0DAV EQU 2 ;DATA AVAILABLE
P0TEOC EQU 4 ;TEST END OF CHAR
P0RPE EQU 8 ;REC'D PARITY ERR
P0ORUN EQU 10H ;OVERRUN
P0FERR EQU 20H ;FRAMING ERROR
;
;Baud rate divisors
;
B110 EQU 142 ;110 BAUD
B300 EQU 52 ;300 BAUD
B450 EQU 35 ;450 BAUD
B600 EQU 26 ;600 BAUD
B710 EQU 22 ;710 BAUD
;
ENDIF ;PMMI
;
;************ EXTERNAL MODEM I/O AREA ************
;
IF IN8251
;
;True if uart is Intel 8251 or equivalent
;
DPORT EQU 58H ;DATA PORT
CPORT EQU 59H ;CONTROL PORT
SPORT EQU CPORT ;STATUS PORT
BPORT EQU 60H ;BAUD RATE PORT
RPORT EQU 69H ;RING INDICATOR PORT
;
;The following are CPORT commands
;
RSTINS EQU 42H ;RESET USART AND SEND DTR
MODINS1 EQU 4EH ;8 BITS, NO PARITY, 1 STOP BIT, 16X BAUD RATE
MODINS2 EQU 0CEH ;8 BITS, NO PARITY, 2 STOP BITS, 16X BAUD RATE
ONINS EQU 17H ;RESET ERROR FLAGS, SEND DTR, ENABLE RECEIVE
;AND TRANSMIT
OFFINS EQU 10H ;DROP DTR, DISABLE RECEIVE AND TRANSMIT
;
;The following are SPORT status masks
;
TRNRDY EQU 01H ;TRANSMITER EMPTY
RCVRDY EQU 02H ;DATA AVAILABLE
PERR EQU 08H ;PARITY ERROR
ORERR EQU 10H ;OVERRUN ERROR
FRERR EQU 20H ;FRAMING ERROR
TOERR EQU ORERR + FRERR ;OVERRUN PLUS FRAMING ERROR
DSR EQU 80H ;DATA SET READY
;
;The following are baud rates for BPORT. The upper 4 bits are
;for the modem port while the lower four are for the auxiliary
;port.
;
BD110 EQU 27H ;110 BAUD
BD300 EQU 57H ;300 BAUD
BD1200 EQU 77H ;1200 BAUD
;
;Ring indicator port mask
;
RI EQU 40H ;NOT RING INDICATOR (LOW TRUE)
P2RDET EQU RI
;
ENDIF ;IN8251
;
;****************WD8250 I/O AREAS*************************
;True if usar is Western Digital 8250 or equivilent.
;
IF WD8250
;
DPORT EQU BASE$PORT ;DATA PORT
LPORT EQU BASE$PORT+3 ;LINE CONTROL
CPORT EQU BASE$PORT+4 ;MODEM CONTROL
SPORT EQU BASE$PORT+5 ;LINE STATUS PORT
MSPORT EQU BASE$PORT+6 ;MODEM STATUS PORT
RPORT EQU BASE$PORT+6 ;RING INDICATOR PORT
;
*****************LINE STATUS MASKS************************
;
P0TBMT EQU 20H ;XMIT BUFFER EMPTY
P0DAV EQU 01H ;DATA AVAILABLE
P0RPE EQU 04H ;PARITY ERROR
P0ORUN EQU 02H ;OVERRUN ERROR
P0FERR EQU 08H ;FRAMING ERROR
P0BRK EQU 10H ;BREAK DETECT
;
;****************MODEM STATUS MASKS***********************
;
P2DSR EQU 20H ;DATA SET READY
P2CTS EQU 080H ;CARRIER DETECT
P2RDET EQU 040H ;RING DETECT
;
;******************BAUD RATE DIVISORS*********************
;
BR300LS EQU 000H ;300 BAUD
BR300MS EQU 001H
BR450LS EQU 0ABH ;450 BAUD
BR450MS EQU 000H
BR600LS EQU 080H ;600 BAUD
BR600MS EQU 000H
BR120LS EQU 040H ;1200 BAUD
BR120MS EQU 000H
;
;*******************MODEM CONTROL****************************
;
MCDTR EQU 01H ;
MCRTS EQU 02H
MCOUT1 EQU 04H
MCOUT2 EQU 08H
;
;*********************LINE CONTROL****************************
;
LCWLS0 EQU 01H
LCWLS1 EQU 02H
LCSTB EQU 04H
LCPEN EQU 08H
LCPES EQU 10H
LCSPS EQU 20H
LCBRK EQU 40H
LCDLAB EQU 80H
ENDIF ;WD8250
;
;---------------------------------------------------------
;
ORG 100H
;
IF BYELOW
;This code allow running below ccp and using programs such as
;Mbasic or Typesq ect....
;
LXI H,OLDBD ;OLD LOCATION STORED IN 6 AND 7 FOR
;JUMP FROM BDOS CALL
SHLD DEST-2 ;STORE IT JUST ABOVE BYE
LXI H,DEST-3 ;POINT TO THREE BYTE ABOVE
;NORMAL BYE
MVI M,0C3H ;PUT A JUMP THERE
SHLD 0006H ;STORE DEST-3 FOR BDOS JUMP
SHLD WMLOC ;STORE DEST-3 IN YOUR BIOS
;
ENDIF ;BYELOW
;
;Move modem interface program up to high RAM and jump to it
;
MOVEUP LXI B,PEND-START+1 ;NUMBER OF BYTES TO MOVE
LXI H,DEST+PEND-START+1 ;END OF MOVED CODE
LXI D,SOURCE+PEND-START ;END OF SOURCE CODE
;
MVLP LDAX D ;GET BYTE
DCX H ;BUMP POINTERS
MOV M,A ;NEW HOME
DCX D
DCX B ;BUMP BYTE COUNT
MOV A,B ;CHECK IF ZERO
ORA C
JNZ MVLP ;IF NOT, DO SOME MORE
;
PUSH H ;SAVE FOR LATER JUMP
MVI A,0C3H ;CLEAR ANY TRAPS SO SYSOP..
STA 0 ;CAN USER "BYE /A"
XRA A ;NEXT WARMBOOT TO USR0/DRV A
STA 4
MVI C,14 ;MAKE DRIVE A DEFAULT
MOV E,A ;LOG-IN DRIVE CP/M FUNCTION
CALL BDOS
;
IF CPM2 ;SET USER 0
MVI C,32 ;GET/SET USR CP/M FUNCTION
MVI E,WELUSR
CALL BDOS
ENDIF ;CPM2
;
RET ;TO ADRS PUSHED ABOVE
;
;
SOURCE EQU $ ;BOUNDARY MEMORY MARKER
;
OFFSET EQU DEST-SOURCE ;RELOC AMOUNT
;
;-----------------------------------------------;
; The following code gets moved ;
; to high RAM located at "DEST", ;
; where it is executed. ;
;-----------------------------------------------;
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;XX C A U T I O N : If modifying anything XX
;XX in this program from here on: XX
;XX A-L-L labels must be of the form: XX
;XX LABEL EQU $+OFFSET XX
;XX in order that the relocation to high XX
;XX RAM work successfully. Forgetting to XX
;XX specify '$+OFFSET' will cause the pro- XX
;XX gram to JMP into whatever is currently XX
;XX in low memory, with unpredictable XX
;XX results. Be careful.... XX
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;
START EQU $+OFFSET
JMP START0 ;HOP OVER FIXED VECTORS
;
;Cold boot vector ends up here. Our cold boot routine
;consists of a jump to the warm boot routine. We are
;defined to consist of only this jump, with a jump
;to PRNLOG immediately after this jump, and other
;modifiable variables after that. By doing this,
;a trivial program can be written that calculates
;where PRNLOG is thru the warm boot vector at 0001H,
;then calls PRNLOG, allowing remote users to get the
;BYE log printed. Such a program, easily entered
;with DDT, is as follows:
;
; LHLD 0001H ;PT TO COLD BOOT VECTOR + 3
; DCX H ;PT TO VECTOR HIGH BYTE
; MOV D,M ;GET THAT IN D
; DCX H ;PT TO VECTOR LOW BYTE
; MOV E,M ;GET THAT IN E
; LXI H,3 ;CALC PRNLOG ADDRESS
; DAD D ; BY ADDING TO COLD BOOT ADDRESS
; PCHL ;GO PRINT LOG INFO, THEN
; ; RETURN TO CCP
;
;A similar calculation can be used to determine
;the locations of the MXUSR, MXDRV, and TOVAL
;variables to change them on the fly for special
;users. Since this will often be done by a
;BASIC signon program, the following sequence
;of code is recommended:
;
; 10 A=PEEK(2)*256+PEEK(1)-2 'Pt to cold boot address
; 20 A=PEEK(A+1)*256+PEEK(A)+6 'Get address of MXUSR
; 30 POKE A,8 'Set MXUSR to 8, allows 0-8
; 40 POKE A+1,4 'Set MXDRV to 4, allows A-D
; 50 POKE A+2,5 'Set TOVAL to 5, allows 5 min of inactivity
;
;The values POKE'ed will be reset to the assembly
;values of MAXUSR, MAXDRV and TOVALUE respectively
;the next time BYE answers the phone.
;
;The following will test whether bye is active and then set
;the flag at WRTLOC.
;
; 10 A=PEEK(2)*256+PEEK(1)-2
; 20 A=PEEK(A+1)*256+PEEK(A)+9 'Get Address of WRTLOC
; 30 IF CHR$(PEEK(A+1))+SHR$(PEEK(A+2))+CHR$(PEEK(A+3))<>"BYE" THEN
; 40 POKE A,&HFF 'SET FLAG FOR WRITE IN PROGRESS
;
;The routine on line 30 should be used in RBBS so that when RBBS is
;running locally nothing will be poked into the bios.
;
MCBOOT EQU $+OFFSET
JMP MBOOT ;OFF TO WARM BOOT
JMP PRNLOG ;GO PRINT OUT ITEMS OF INTEREST
;
;Variables follow in a predefined order that can
;be manipulated by a passworded or other program
;to give special users different capabilities.
;
MXUSR EQU $+OFFSET
DB MAXUSR ;RUNTIME MAX USER # (UNUSED
; UNDER CP/M 1.4)
;
MXDRV EQU $+OFFSET
DB MAXDRV ;RUNTIME # DRIVES ACCESSABLE
;
TOVAL EQU $+OFFSET
DB TOVALUE ;RUNTIME # INACTIVE MINUTES
; BEFORE AUTO LOGOFF
NULLS EQU $+OFFSET
DB 5 ;INITIAL NUMBER OF NULLS
;
ULCSW EQU $+OFFSET
DB 0 ;UPPER CASE ONLY SWITCH
;
LFEEDS EQU $+OFFSET
DB 0 ;LINE FEED SWITCH
;
WRTLOC EQU $+OFFSET
DB 0 ;LOCATION OF FLAG FOR RBBS TO
;SET WHILE DOING DISK WRITES
;Program version number message.
;
VMSG EQU $+OFFSET
DB 'BYE version 7.8 as of 02/20/82',CR,LF,'$'
;
;----------------------------------------------
;This is the official start of the BYE program.
;----------------------------------------------
;
;If carrier lost, hang up, await ring.
;Otherwise, say goodbye, and hang up
;
START0 EQU $+OFFSET
;
XRA A ;GET 0
STA LOSTFLG ;SHOW NO CARR. LOST
;
IF MINICK
;
;Set MINICK to true if you use MINICBBS and want to take
;advantage of its feature which can prevent the modem
;from hanging up if the caller should happen to discon-
;nect during a file update. MINICBBS sets the high-order
;bit of IOBYTE to (address 0003) to indicate a file update
;is in progress.
;
MVI A,IOVAL
STA IOBYTE
;
ENDIF ;MINICK
;
;Don't allow a remote user to do 'BYE /A'
;
IF DCHAYES
IN STATUS
ANI CD ;CHECK CARRIER DETECT
JNZ GOODBY ;SAY GOODBYE IF REMOTE
ENDIF ;DCHAYES
;
IF PMMI
IN RPORT ;AS ABOVE, FOR PMMI MODEM
ANI P2CTS ;CD DEDUCED FROM CTS
JZ GOODBY
ENDIF ;PMMI
;
IF IN8251
IN SPORT
ANI DSR ;CHECK CARRIER DETECT
JNZ GOODBY ;GOODBYE IF REMOTE
ENDIF ;IN8251
;
IF WD8250
IN MSPORT
ANI P2CTS
JNZ GOODBY
ENDIF ;WD8250
;
;Identify version of program
;
MVI C,PRINTF
LXI D,VMSG
CALL BDOS
;
;Check for /A option on command - request to
;go immediately into answer mode
LXI H,FCB+1 ;TO OPTION
MOV A,M
CPI '/' ;OPTION?
JNZ HANGUP
;Got an option - validate it
INX H ;TO OPTION BYTE
MOV A,M ;GET IT
STA OPTION ;MIGHT NEED LATER
CPI 'A' ;ANSWER?
JZ ANSWER
;
IF COMFILE
CPI 'C'
JZ ANSWER
ENDIF ;COMFILE
;
IF USRLOG ;CHECK FOR RESET OF COUNTERS
CPI 'R'
CZ RESET
ENDIF ;USRLOG
;
JMP HANGUP ;WE KNOW IT'S LOCAL, SO SKIP CALL TO CARCK
;
;No option, or invalid one
;
NOSLASH EQU $+OFFSET
CALL CARCK ;SIGNED OFF W/THIS PROG?
JC HANGUP ;NOBODY THERE
;
GOODBY EQU $+OFFSET
CALL ILPRT ;PRINT THIS MSG:
DB CR,LF,'Good-bye, call again...'
IF RTC
DB CR,LF,CR,LF,'Off at ',0
CALL TIME
CALL ILPRT
ENDIF ;RTC
;
DB CR,LF,CR,LF,0
CALL UNPATCH ;UNDO BIOS PATCHES
;
;Nobody there, or we are done, so hang up
;
HANGUP EQU $+OFFSET
LXI SP,STACK ;SET UP LOCAL STACK
XRA A ;FORCE NEXT WARMBOOT TO USER 0
STA 4 ;AND DRIVE A
;
IF CCSDISK
;
CALL DSKOFF ;SHUT DOWN THE DRIVES
;
ENDIF ;CCSDISK
;
MVI C,14 ;MAKE DRIVE A DEFAULT
MOV E,A
CALL BDOS
MVI A,' ' ;DON'T ALLOW OPTIONS..
STA OPTION ;..AFTER 1 "BYE / <ANYTHING>"
;
IF CPM2 AND COMFILE
MVI C,32 ;GET/SET USER CODE
MVI E,COMUSR ;LOCATION OF OUR COMFILE
CALL BDOS
ENDIF ;CPM2 AND COMFILE
;
IF COMFILE
CALL LODCOM ;LOAD THE COM FILE
ENDIF ;COMFILE
;
;
HANGUP2 EQU $+OFFSET
;
;Clear DTR causing phone to hang up
;
IF DCHAYES
XRA A ;GET A ZERO
OUT CR2 ;WRITE TO CR2, CAUSING HANGUP
ENDIF ;DCHAYES
;
IF PMMI
XRA A ;GET DISCONNECT VALUE
OUT TPORT ;RESET ORIG/ANSW
OUT CPORT ;TURN OFF DTR, DO BREAK
ENDIF ;PMMI
;
IF IN8251
MVI A,OFFINS ;CLEAR DTR
OUT CPORT ;CAUSING HANGUP
PUSH B ;PRESERVE IN CASE WE NEED IT
MVI B,150 ;15 SECOND DELAY
;
OFFTI EQU $+OFFSET
CALL DELAY ;0.1 SECOND DELAY
DCR B
JNZ OFFTI ;KEEP LOOPING UNTIL FINISHED
POP B ;RESTORE B
MVI A,ONINS ;TURN DTR ON ALLOWING MODEM TO ANSWER PHONE
OUT CPORT
ENDIF ;IN8251
;
IF WD8250
XRA A ;SHUT OFF DTR & RTS
OUT CPORT ;SHUT OFF MODEM
ENDIF ;WD8250
;
IF WD8250 AND NORING
;
PUSH B ;PRESERVE IT IF WE NEED IT
MVI B,150 ;15 SEC DELAY
OFFTI EQU $+OFFSET
CALL DELAY ;0.1 SEC DELAY
DCR B
JNZ OFFTI ;KEEP LOOPING UNTIL DONE
POP B ;RESTORE B
MVI A,MCDTR+MCRTS ;TURN ON DTR/RTS
OUT CPORT
ENDIF ;WD8250
;
MVI A,0C3H ;CLEAR ANY TRAPS..
STA 0 ;..LEFT FROM COM FILE
;
;Await ringing
;
RINGWT EQU $+OFFSET
;
;Check local keyboard for CTL-C exit request.
;NOTE: Must do input via BDOS because CBIOS patches
;are not done until call comes in.
;
CALL UCSTS
ANI 7FH ;STRIP PARITY BIT
CPI 'C'-40H ;CONTROL C?
CZ USRCHK ;Check for exit if so
;
IF NORING
IN MSPORT
ANI P2CTS ;GOT CARRIER
JNZ ANSWER
JMP RINGWT ;KEEP CHECKING
ENDIF ;NORING
;
RINGW2 EQU $+OFFSET
IN RPORT ;GET THE STATUS
ANI P2RDET ;RINGING?
;
IF WD8250 OR IN8251
JZ RINGWT ;NO, WAIT
ENDIF ;WD8250 OR IN8251
;
IF NOT (WD8250 OR IN8251)
JNZ RINGWT ;NO, WAIT
ENDIF ;NOT (WD8250 OR IN8251)
;
;The phone may be ringing. Wait .1 sec and look
;again to make sure it isn't just relay bounce
CALL DELAY ;.1 SEC DELAY FOR DEBOUNCE
IN RPORT ;GET STATUS
ANI P2RDET ;STILL RINGING?
;
IF WD8250 OR IN8251
JZ RINGWT ;NO, IT WAS RELAY BOUNCE
ENDIF ;WD8250 OR IN8251
;
IF NOT (WD8250 OR IN8251)
JNZ RINGWT ;NO, IT WAS A RELAY BOUNCE
ENDIF ;NOT (WD8250 OR IN8251)
;
;The phone is definitely ringing, now wait until ring is finished
;
ENDRING EQU $+OFFSET
CALL DELAY ;.1 SEC DELAY FOR DEBOUNCE
IN RPORT ;GET STATUS
ANI P2RDET ;STILL RINGING?
;
IF WD8250 OR IN8251
JNZ ENDRING ;WAIT UNTIL RING FINISHED
ENDIF ;WD8250 OR IN8251
;
IF NOT (WD8250 OR IN8251)
JZ ENDRING ;WAIT UNTIL RING FINISHED
ENDIF ;NOT (WD8250 OR IN8251)
;
IF CALLBAK ;NEXT ROUTINES IMPLEMENT CALLBAK
;
;This routine minimizes the computer's interference
;with normal household phone use by having computer
;folk dial, let the phone ring once, hang up and
;then dial again. When the phone rings only once it
;alerts the computer which then waits for and answers
;any ring which occurs within the next 40 seconds.
;
MVI L,45 ;DELAY 4.5 SECONDS FOR NEXT RING
;
WAITNX EQU $+OFFSET
CALL DELAY ;WAIT .1 SECONDS
DCR L ;MORE TO GO?
JNZ WAITNX ;YES, LOOP
IN RPORT ;GET THE STATUS
ANI P2RDET ;RINGING AGAIN?
ENDIF ;CALLBAK
;
IF CALLBAK AND (WD8250 OR IN8251)
JZ EXPECT ;NO?...ITS FOR ME!
ENDIF
;
IF CALLBAK AND NOT (WD8250 OR IN8251)
JNZ EXPECT ;NO?...ITS FOR ME!
ENDIF
;
IF CALLBAK
;
;If second ring, then check for third ring, in case
;caller's phone exchange not synch'ed with computer's
;
ENDRNG2 EQU $+OFFSET
IN RPORT ;GET THE STATUS
ANI P2RDET ;STILL RINGING?
ENDIF ;CALLBAK
;
IF CALLBAK AND (WD8250 OR IN8251)
JZ ENDRNG2 ;WAIT UNTIL RING FINISHED
ENDIF
;
IF CALLBAK AND NOT (WD8250 OR IN8251)
JNZ ENDRNG2 ;WAIT UNTIL RING FINISHED
ENDIF
;
IF CALLBAK
MVI L,45 ;DELAY 4.5 SECONDS FOR NEXT RING
;
WAITNX2 EQU $+OFFSET
CALL DELAY ;WAIT .1 SECONDS
DCR L ;MOE TO GO?
JNZ WAITNX2 ;YES, LOOP
IN RPORT ;GET THE STATUS
ANI P2RDET ;RINGING AGAIN?
ENDIF ;CALLBAK
;
IF CALLBAK AND (WD8250 OR IN8251)
JZ EXPECT ;NO?...ITS FOR ME!
ENDIF
;
IF CALLBAK AND NOT (WD8250 OR IN8251)
JNZ EXPECT ;NO?...ITS FOR ME!
ENDIF
;
IF CALLBAK
;
;Call not for computer - wait until ringing done, then reset
;
WAITNR EQU $+OFFSET
MVI L,100 ;WAIT FOR 10 SECS NO RINGING
;
WAITNRL EQU $+OFFSET
CALL DELAY ;DELAY .1 SECONDS
IN RPORT ;GET THE STATUS
ANI P2RDET ;STILL RINGING?
ENDIF ;CALLBAK
;
IF CALLBAK AND (WD8250 OR IN8251)
JNZ WAITNR ;YES, WAIT 10 MORE SECONDS
ENDIF
;
IF CALLBAK AND NOT (WD8250 OR IN8251)
JZ WAITNR ;YES, WAIT 10 MORE SECONDS
ENDIF
;
IF CALLBAK
DCR L ;NO RING, MAYBE WE'RE DONE
JNZ WAITNRL ;NO, LOOP SOME MORE
ENDIF
;
IF CALLBAK AND USRLOG
LXI H,NONUSR ;RECORD AS VOICE CALL
CALL BOPLOG ;CALL ROUTINE TO ADD ONE
ENDIF ;CALLBAK AND USRLOG
;
IF CALLBAK ;CONTINUE WITH CALLBAK ROUTINES
JMP HANGUP2 ;GO WAIT FOR NEXT CALL
;
EXPECT EQU $+OFFSET
LXI H,400 ;40 SECONDS TO WAIT FOR SECOND CALL
;
RELOOK EQU $+OFFSET
IN RPORT ;GET THE STATUS
ANI P2RDET ;RINGING AGAIN?
ENDIF ;CALLBAK
;
IF CALLBAK AND (WD8250 OR IN8251)
JNZ ANSWER ;YES, GO ANSWER IT
ENDIF
;
IF CALLBAK AND NOT (WD8250 OR IN8251)
JZ ANSWER ;YES, GO ANSWER IT
ENDIF
;
IF CALLBAK
CALL DELAY ;WAIT .1 SECOND
DCX H ;ONE LESS COUNT
MOV A,H
ORA L ;IS COUNT ZERO?
JNZ RELOOK ;NO, LOOK SOME MORE
JMP HANGUP2 ;COUNT DONE, WAIT FOR NEW CALL
;
ENDIF ;END OF CALLBAK ROUTINES
;
;Setup modem
;
ANSWER EQU $+OFFSET
;
IF ZCPRT ;RESET WHEEL STATUS
XRA A ;WHEN RUNNING ZCPR-T## FOR YOUR CCP.
STA WHEEL
ENDIF ;ZCPRT
;
IF USRLOG AND PWRQD ;COUNT # OF LOGON ATTEMPTS
LXI H,OLDUSR ;GET # OF ATTEMPTS
CALL BOPLOG CALL ROUTINE TO ADD ONE
ENDIF ;USRLOG AND PWRQD
;
IF DCHAYES
MVI A,LS1+LS2+PI+SBS ;8 DATA BITS, NO PARITY, 2 STOP BITS
OUT CR1
MVI A,TXE+OH ;TURN ON CARRIER AND ANSWER PHONE
OUT CR2
IN DATA ;CLEAR DATA INPUT PORT
IN DATA ;MAKE SURE IT'S CLEAR
CALL CARCK ;LOOK FOR CARRIER
JC HANGUP2 ;AWAIT ANOTHER CALLER
;
;Now test input for baud rate
CALL PATCH ;PATCH JUMP TABLE
CALL TSTBAUD ;SEE IF BAUD = 110
JZ WELCOME ;YES, EXIT
;
MVI A,LS1+LS2+PI ;SET FOR 1 STOP BIT, 8 DATA, NO PARITY
OUT CR1
MVI A,TXE+OH+BRS ;SET FOR 300 BAUD
OUT CR2
CALL TSTBAUD ;SEE IF BAUD = 300
JZ WELCOME ;YES,EXIT
ENDIF ;DCHAYES
;
IF PMMI
MVI A,7FH ;TURN ON DTR
OUT CPORT ;.. AND SET FILTER VALUE FOR 300 BAUD
CALL DELAY ;GIVE TIME TO TURN ON
MVI A,P0110+P0ANSW
OUT TPORT ;ANSWER PHONE
CALL DELAY ;GIVE TIME FOR ANSWER
CALL UCSTS
IN DPORT ;CLEAR MODEM PORT
IN DPORT ;MAKE SURE ITS CLEAR
MVI A,B110 ;SET DIVISOR
OUT RPORT ;.. TO 110 BAUD RATE
;Output value allowing modem to hang up on loss of carrier
MVI A,P0110 ;NORMAL MODE FOR 110 BAUD
OUT TPORT
CALL CARCK ;LOOK FOR CARRIER
JC HANGUP2 ;AWAIT ANOTHER CALLER
;Now test input for baud rate
CALL PATCH ;PATCH JMP TABLE
CALL TSTBAUD ;SEE IF BAUD = 110
JZ WELCOME ;YES, EXIT
;
MVI A,P0NORM ;SET FOR 1 STOP BIT, ETC.
OUT TPORT
MVI A,B300 ;SET DIVISOR
OUT RPORT ;.. TO 300 RATE
CALL TSTBAUD ;SEE IF BAUD = 300
JZ WELCOME ;YES, EXIT
;
MVI A,B450 ;SET DIVISOR
OUT RPORT ;.. TO 450 RATE
MVI A,5FH ;SET FILTER VALUE
OUT CPORT ;.. FOR > 300
CALL TSTBAUD ;SEE IF BAUD = 450
JZ WELCOME ;YES, EXIT
;
MVI A,B600 ;SET DIVISOR
OUT RPORT ;.. TO 600 RATE
CALL TSTBAUD ;SEE IF BAUD = 600
JZ WELCOME ;YES, EXIT
;
MVI A,B710 ;SET DIVISOR
OUT RPORT ;.. TO 710 RATE
CALL TSTBAUD ;SEE IF BAUD = 710
JZ WELCOME ;YES, EXIT
ENDIF ;PMMI
;
IF IN8251
MVI A,BD300 ;LOAD 300 BAUD
OUT BPORT
IN DPORT ;CLEAR
IN DPORT ;DATA PORT
MVI A,RSTINS ;RESET USART
OUT CPORT
CALL UDELAY ;USART DELAY
MVI A,MODINS1 ;1 STOP BIT, ETC.
OUT CPORT
CALL UDELAY ;USART DELAY
MVI A,ONINS ;DSR, ETC.
OUT CPORT
CALL CARCK ;SEE IF CARRIER IS PRESENT
JC HANGUP2
;Test input for baud rate
CALL PATCH ;PATCH JUMP TABLE
CALL TSTBAUD ;SEE IF 300 BAUD
JZ WELCOME ;YES, EXIT
;
MVI A,BD1200 ;LOAD 1200 BAUD
OUT BPORT
CALL TSTBAUD ;SEE IF 1200 BAUD
JZ WELCOME ;YES,EXIT
;
MVI A,RSTINS ;RESET USART
OUT CPORT
CALL UDELAY ;DELAY FOR USART
MVI A,MODINS2 ;2 STOP BITS, ETC.
OUT CPORT
CALL UDELAY ;DELAY FOR USART
MVI A,ONINS ;DTR, ETC.
OUT CPORT
MVI A,BD110 ;LOAD 110 BAUD
OUT BPORT
CALL TSTBAUD ;TEST FOR 110 BAUD
JZ WELCOME
ENDIF ;IN8251
;
IF WD8250 AND NOT NORING
;
MVI A,MCDTR+MCRTS ;TURN ON DATA SET, ANSWER PHONE;
OUT CPORT
ENDIF ;WD8250 AND NOT NORING
;
IF WD8250
MVI A,(LCWLS0+LCWLS1) AND 0FFH ;8 BIT DATA 1 STOP BIT NO PAR
OUT LPORT
CALL PATCH ;PATCH DRIVERS
;
; BAUD RATE SELECTOR
;
TST300: EQU $+OFFSET
PUSH D ;SAVE D/E
MVI D,BR300MS
MVI E,BR300LS
CALL SETBAUD
POP D
CALL TSTBAUD
JNZ TST450
CALL TSTBAUD
JZ WELCOME
TST450: EQU $+OFFSET
PUSH D
MVI D,BR450MS
MVI E,BR450LS
CALL SETBAUD
POP D
CALL TSTBAUD
JNZ TST600
CALL TSTBAUD
JZ WELCOME
TST600: EQU $+OFFSET
PUSH D
MVI D,BR600MS
MVI E,BR600LS
CALL SETBAUD
POP D
CALL TSTBAUD
JNZ TST120
CALL TSTBAUD
JZ WELCOME
TST120: EQU $+OFFSET
PUSH D
MVI D,BR120MS
MVI E,BR120LS
CALL SETBAUD
POP D
CALL TSTBAUD
JNZ BADDO
CALL TSTBAUD
JZ WELCOME
ENDIF ;WD8250
;
BADDO EQU $+OFFSET
CALL UNPATCH ;RESTORE ORIG BIOS JMP TBL
JMP ANSWER ;TEST MORE - INVALID BAUD RATE
;
IF IN8251
UDELAY EQU $+OFFSET
NOP ! NOP ! NOP !
RET
ENDIF ;IN8251
;
;Get the console status when unpatched
;
UCSTS EQU $+OFFSET
;
IF CPM2
MVI C,DRECTIO ;DIRECT I/O CALL
MVI E,0FFH ;ASK FOR INPUT
CALL BDOS ;A=0 IF NO CHAR WAITING
RET
ENDIF ;CPM2
;
IF NOT CPM2
MVI C,CSTS ;IN CPM 1.4, WE HAVE TO GET..
CALL BDOS ;..THE STATUS FIRST
ORA A
RZ
MVI C,CI ;AND THEN THE CHARACTER
CALL BDOS
RET
ENDIF ;NOT CPM2
;
;Following are the USRLOG routines
;
IF USRLOG ;INCLUDE RESET FUNCTIONS
RESET EQU $+OFFSET ;RESET ALL LOGON COUNTERS
LXI H,0 ;ZEROING 16 BIT COUNTERS
ENDIF ;USRLOG
;
IF USRLOG AND PWRQD
SHLD OLDUSR ;RESET ATTEMPT COUNTER
ENDIF ;USRLOG AND PWRQD
;
IF USRLOG
SHLD NEWUSR ;RESET LOGON COUNTER
ENDIF ;USRLOG
;
IF USRLOG AND CALLBAK
SHLD NONUSR ;RESET VOICE COUNTER
ENDIF ;USRLOG AND CALLBAK
;
IF USRLOG AND IMSAI
MVI A,0FFH
OUT SENSE ;RESET IMSAI PANEL DISPLAY
ENDIF ;USRLOG AND IMSAI
;
IF USRLOG
RET
ENDIF ;USRLOG
;
; PRNLOG is called to print out the BYE version
; # and USRLOG info. It can be called from
; outside the program, using the vector after
; MCBOOT.
;
PRNLOG EQU $+OFFSET
;
MVI C,PRINTF ;PRINT OUT PROG VERSION #
LXI D,VMSG
CALL BDOS
;
IF USRLOG AND PWRQD ;PRINT # OF LOGON ATTEMPTS
MVI C,PRINTF
LXI D,ATMSG
CALL BDOS
LXI H,OLDUSR+1 ;PT TO HIGH BYTE
CALL HXOUT
ENDIF ;USRLOG AND PWRQD
;
IF USRLOG ;PRINT # OF LOGONS
MVI C,PRINTF
LXI D,SUMSG
CALL BDOS
LXI H,NEWUSR+1
CALL HXOUT
ENDIF ;USRLOG
;
IF USRLOG AND CALLBAK ;# OF VOICE CALLS
MVI C,PRINTF
LXI D,VCMSG
CALL BDOS
LXI H,NONUSR+1
CALL HXOUT
ENDIF ;USRLOG AND CALLBAK
;
RET ;IF NO LOG, NULL PRNLOG ROUTINE
;
USRCHK EQU $+OFFSET
CALL PRNLOG ;GIVE INFO
MVI C,PRINTF
LXI D,RS1MSG
CALL BDOS ;PROMPT FOR RESUME BYE
;
PRNREL EQU $+OFFSET
CALL UCSTS ;GET REPLY
ORA A
JZ PRNREL ;WAIT UNTIL ANSWERED
CPI 'R' ;IS ANSWER "R", FOR RESUME?
JZ PRNRES ;GO DO IT IF SO
CPI 'R'+20H ;TAKE LOWER CASE ALSO
JNZ EXCPM ;IF NOT "R", WARM BOOT CP/M
;
PRNRES EQU $+OFFSET
MVI C,PRINTF
LXI D,RS2MSG
JMP BDOS ;RESUME VIA BDOS AFTER MSG
;
RS1MSG EQU $+OFFSET
DB CR,LF,CR,LF,'Type "R" to resume,'
DB ' anything else to warm boot: $'
RS2MSG EQU $+OFFSET
DB 'Resuming...',CR,LF,'$'
;
; Here to exit to CP/M
;
EXCPM EQU $+OFFSET
;
IF CCSDISK
;
CALL DSKON ;TURN ON THE DRIVES
;
ENDIF ;CCSDISK
;
IF BYELOW
;
LXI H,OLDBD ;RESET THE OLD BDOS JUMP IN
SHLD WMLOC ;THE BIOS WARM BOOT ROUTINE
;
ENDIF ;BYELOW
;
JMP 0000H ;Warm boot CP/M
;
IF USRLOG
;
; BOPLOG INCREMENTS THE 16 BIT COUNTER PT'ED AT BY
; HL. IF DECIMAL SWITCH IN USE, NUMBER IS KEPT AS
; 4 BCD DIGITS.
;
BOPLOG EQU $+OFFSET
MOV A,M ;GET LOW BYTE
INR A ;INCREMENT
ENDIF ;USRLOG
;
IF USRLOG AND DECIMAL
DAA ;DECIMAL ADJUST
ENDIF ;USRLOG AND DECIMAL
;
IF USRLOG
MOV M,A ;REPLACE LOW ORDER
RNC ;IF NO CARRY, BOP DONE
INX H ; ELSE CARRY TO HIGH ORDER
MOV A,M ;GET HIGH ORDER
INR A ; AND BOP IT
ENDIF
;
IF USRLOG AND DECIMAL
DAA ;DECIMAL ADJUST
ENDIF ;USRLOG AND DECIMAL
;
IF USRLOG
MOV M,A ;REPLACE HIGH ORDER
RET ;CARRY OUT OF HIGH DROPPED
ENDIF ;USRLOG
;
IF USRLOG AND PWRQD
ATMSG EQU $+OFFSET
DB CR,LF,'Number of logon attempts: $'
ENDIF ;USRLOG AND PWRQD
;
IF USRLOG
SUMSG EQU $+OFFSET
DB CR,LF,'Number of logons: $'
ENDIF ;USRLOG
;
IF USRLOG AND CALLBAK
VCMSG EQU $+OFFSET
DB CR,LF,'Number of voice calls: $'
ENDIF ;USRLOG AND CALLBAK
;
IF USRLOG
HXOUT EQU $+OFFSET
PUSH H ;SAVE PTR
CALL HXHAF ;DO HIGH ORDER HALF OF #
POP H ;RESTORE PTR
DCX H ;PT TO LOW, THEN DROP
; IN TO DO LOW HALF
;
HXHAF EQU $+OFFSET
MOV A,M ;GET HALF # IN ACC
MOV B,A ;SAVE NUMBER
RAR ;ROTATE RIGHT 4 BITS
RAR ;TO MAKE AN ASCII DIGIT
RAR
RAR
CALL ONEOUT ;OUTPUT MSH TO CONSOLE
MOV A,B ;GET NUMBER BACK
;
ONEOUT EQU $+OFFSET
ANI 0FH ;GET LSH FOR OUTPUT
ADI 90H ;CVT TO DECIMAL ASCII
DAA
ACI 40H
DAA
PUSH B
MVI C,02H
MOV E,A ;OUTPUT THE NUMBER
CALL BDOS
POP B
RET
ENDIF ;USRLOG
;
;Welcome to the system
;
WELCOME EQU $+OFFSET
;
IF CCSDISK
;
CALL DSKON ;TURN ON THE DRIVES
;
ENDIF ;CCSDISK
;
IF CPM2
MVI A,MAXUSR ;RESET MAX USER #
STA MXUSR
ENDIF ;CPM2
;
MVI A,MAXDRV ;RESET MAX DRIVE #
STA MXDRV
;
IF TIMEOUT
MVI A,TOVALUE ;RESET TIMEOUT COUNT
STA TOVAL
ENDIF ;TIMEOUT
;
MVI A,5 ;Assume this many nulls
STA NULLS ; in case error
;
IF NOT OXGATE
;
GETNULL EQU $+OFFSET
;
CALL ILPRT ;PRINT THIS MSG:
DB CR,LF
DB 'HOW MANY NULLS (0-9) DO YOU NEED? ',0
CALL MINPUT ;GET VALUE
MOV C,A ;TO C FOR MOUTPUT
CALL MOUTPUT ;ECHO CHAR
MOV A,C ;RESTORE VALUE
CPI '0'
JC GETNULL ;BAD, RETRY
CPI '9'+1
JNC GETNULL ;BAD
SUI '0' ;MAKE BINARY
STA NULLS ;SAVE COUNT
;
ENDIF ;NOT OXGATE
;
IF TRAPLC AND (NOT OXGATE)
GETULC EQU $+OFFSET
CALL ILPRT ;PRINT THIS MSG:
DB CR,LF
DB 'CAN YOUR TERMINAL DISPLAY LOWER CASE? ',0
MVI A,20H ;FORCE CASE CONVERSION FOR NOW
STA ULCSW
CALL MINPUT ;GET Y OR NO
MOV C,A
CALL MOUTPUT ;ECHO
MOV A,C
CPI 'N'
JZ DONEOPT ;WE'RE ALREADY SET UP FOR NO LWR CASE
CPI 'Y'
JNZ GETULC ;WASN'T Y OR N...GO ASK AGAIN
XRA A
STA ULCSW ;SET FLAG FOR NO CONVERSION
;
DONEOPT EQU $+OFFSET
ENDIF ;TRAPLC AND (NOT OXGATE)
;
CALL ILPRT
DB CR,LF,0
;Print the welcome file
LXI H,WELFILN ;SOURCE
LXI D,FCB ;DESTINATION
MVI B,13 ;LENGTH
CALL MOVE ;MOVE THE NAME
;Set DMA address to 80h
LXI D,80H
MVI C,STDMA
CALL BDOS
;
IF CPM2
;Set user number for welcome file
MVI C,32
MVI E,WELUSR
CALL BDOS
ENDIF ;CPM2
;
;Open the welcome file
LXI D,FCB
MVI C,OPEN
CALL BDOS
;Did it exist?
INR A ;A=> 0 MEANS "NO"
JZ PASSINT ;NO WELCOME FILE
;Got a file, type it
XRA A ;GET 0
STA FCBRNO ;ZERO RECORD #
LXI H,100H ;GET INITIAL BUFF POINTER
;
;Type the welcome file
WELTYLP EQU $+OFFSET
CALL RDBYTE ;GET A BYTE
CPI 1AH ;EOF?
JZ PASSINT ;YES, DONE
MOV C,A ;SETUP FOR TYPE
CALL MOUTPUT ;TYPE THE CHAR
CALL MSTAT ;CHECK FOR..
ORA A ;CHAR TYPED?
JZ WELTYLP ;..NO, LOOP
CALL MINPUT ;..YES, GET CHAR
CPI 'C'-40H ;CTL-C?
JNZ WELTYLP ;..NO, LOOP UNTIL EOF
;
;Get the password
;
PASSINT EQU $+OFFSET
;
IF PWRQD AND IMSAI AND SELPASS
IN SENSE ;TURN THE SWITCH UP..
ANI PWDSW ;..TO REQUIRE THE PASSWORD
JZ NOPASS
ENDIF ;PWRQD AND IMSAI AND SELPASS
;
IF PWRQD
MVI D,5 ;5 TRIES AT PASSWORD
;
PASSINP EQU $+OFFSET
CALL ILPRT
DB CR,LF,'Enter password: ',0
LXI H,PASSWD ;POINT TO PASSWORD
MVI E,0 ;NO MISSED LETTERS
IN DPORT ;CLEAR OUT GARBAGE
;
PWMLP EQU $+OFFSET
CALL MINPUT ;GET A CHAR
CPI 60H ;LOWER CASE?
JC NOTLC ;NO,
ANI 5FH ;MAKE UPPER CASE ALPHA
;
NOTLC EQU $+OFFSET
ENDIF ;PWRQD
IF DUAL$IO AND PWRQD
PUSH PSW ;SAVE CHAR INPUT
CPI 20H ;IS CHAR CONTROL?
JNC PWDIS ;PASS IF DISPLAYABLE
MVI C,'^' ;IF CONTROL,
CALL CONOUT ; MAP TO UP-ARROW,
POP PSW ; THEN DISPLAYABLE
PUSH PSW
ADI 40H
PWDIS EQU $+OFFSET
MOV C,A
CALL CONOUT ;OUTPUT CHAR LOCALLY
POP PSW ;RESTORE TO ACC
ENDIF ;DUAL$IO AND PWRQD
IF PWRQD
CPI 'U'-40H ;CTL-U?
JZ PASSINP ;YES, RE-GET IT
CMP M ;MATCH PASSWORD?
JZ PWMAT ;..YES
MVI E,1 ;..NO, SHOW MISS
CPI CR ;C/R?
JNZ PWMLP ;..NO, WAIT FOR C/R
;
;Password didn't match
;
PWNMAT EQU $+OFFSET
CALL ILPRT
DB 'Incorrect',CR,LF,0
DCR D ;MORE TRIES?
JNZ PASSINP ;YES
JMP BADPASS ;NO, GO HANG UP
;
;Character matched in password
;
PWMAT EQU $+OFFSET
INX H ;TO NEXT CHAR
CPI CR ;END?
JNZ PWMLP ;..NO, LOOP
;End of password. Any missed chars?
MOV A,E ;GET FLAG
ORA A
JNZ PWNMAT ;NOT RIGHT
;Password correct
ENDIF ;PWRQD
;
NOPASS EQU $+OFFSET
;
IF RTC
CALL ILPRT
DB CR,LF,CR,LF,'On at ',0
CALL TIME
CALL ILPRT
DB CR,LF,0
ENDIF ;RTC
;
;
IF USRLOG ;COUNT # OF SUCCESSFUL LOGONS
LXI H,NEWUSR ;GET LAST VALUE
CALL BOPLOG ;CALL ROUTINE TO ADD ONE
ENDIF ;USRLOG
;
IF IMSAI AND USRLOG
LDA NEWUSR ;RE-GET LOW ORDER VALUE
CMA ;INVERT FOR LIGHTS
OUT SENSE ;DISPLAY ON IMSAI FRONT PANEL
ENDIF ;IMSAI AND USRLOG
;
IF BOOTMSG
;
CALL ILPRT
DB CR,LF
DB 'Please Wait... ' ;BOOT MSG HERE
DB 0
ENDIF ;BOOTMSG
;
IF COMFILE AND CPM2
MVI C,32
MVI E,COMUSR ;SWITCH TO COM FILE USER #
CALL BDOS
ENDIF ;COMFILE AND CPM2
;
;
IF COMFILE
MVI A,20H ;FOOL THE SYSTEM
STA FCB+1 ;SO THAT COM FILE WILL SEE
;20H AT FCB+1 FOR DEFAULT PURPOSES.
LDA OPTION
CPI 'A' ;SYSOP CAN BYPASS COM FILE BY..
JZ 0 ;..TYPING "BYE /A"
CPI 'C' ;OPER CAN ALSO GO TO COM..
JNZ RUNCOM ;..FILE LOAD WITH "BYE /C"
CALL ILPRT ;PRINT THIS MESSAGE:'
DB 'Loading system...',CR,LF,0
CALL LODCOM
RUNCOM EQU $+OFFSET ;EVERYONE ELSE GETS COM FILE
CALL 100H
ENDIF ;COMFILE
;
JMP 0 ;WARM BOOT NOW FOR "NORMAL" CP/M USE
;
;TSTBAUD attempts to read a LF or CR, returns with
;zero flag if the character read is one of these two.
;
TSTBAUD EQU $+OFFSET
CALL MINPUT ;GET CHARACTER FROM MODEM
CPI CR ;IF A CARRIAGE RETURN...
RZ ;.. RETURN
CPI LF ;IF A LINEFEED...
RZ
CPI 'C'-40H ;IF A CONTROL C
RET ;RET ZERO FLAG, ELSE NOT ZERO
;
;**************SET WD8250 BAUD RATE************************
;
IF WD8250
;
SETBAUD: EQU $+OFFSET
MVI A,83H ;SET DLAB
OUT LPORT
MOV A,E ;GET LSB
OUT DPORT
MOV A,D ;GET MSB
OUT DPORT+1
CPI 04H ;110?
JNZ ONESTOP
MVI A,LCWLS0+LCWLS1+LCSTB ;8 DATA 2 STOP BITS
OUT LPORT
JMP DLOOP
ONESTOP: EQU $+OFFSET
MVI A,LCWLS0+LCWLS1
OUT LPORT
DLOOP: EQU $+OFFSET
XCHG ;PUT DIVISOR IN HL
DAD H!DAD H!DAD H!DAD H ;MULTIPLY BY 16
;SO WE DELAY APPROX 2 CHARS TIMES
DLOOP1: EQU $+OFFSET
DCX H
MOV A,L
ORA H
JNZ DLOOP1
XCHG
IN DPORT
IN DPORT
RET
;
ENDIF ;WD8250
;
;Loss of connection test
;
CARCK EQU $+OFFSET
;
IF DCHAYES
;
;The DC Hayes has a hardware hangup feature, but we won't use it.
;Instead, if we detect that there is no carrier upon entry to
;this routine, we'll keep checking for 15 seconds to see if the
;carrier returns. If so, we'll just continue on. If not, we'll
;signal this by setting the carry flag.
;
IN STATUS ;GET MODEM STATUS
ANI CD ;GOT A CARRIER?
JNZ CARCK2 ;YES, GO ON WITH TESTS
PUSH B ;PRESERVE SO WE CAN USE IT
MVI B,150 ;SET FOR 15 SECONDS
;
CARLP EQU $+OFFSET
CALL DELAY ;WAIT .1 SECONDS
IN STATUS ;GET MODEM STATUS
ANI CD ;HAS CARRIER RETURNED?
MOV A,B ;PRESERVE COUNTDOWN VALUE
POP B ;FIX STACK IN CASE ALL IS OK
JNZ CARCK2 ;GOT CARRIER, CONTINUE ON
DCR A ;COUNT TIME DOWN
STC ;IN CASE THIS IS THE END OF TIME
RZ ;RETURN IF TIMED OUT
PUSH B ;PRESERVE B
MOV B,A ;GET COUNTER VALUE IN B
JMP CARLP ;KEEP CHECKING
ENDIF ;DCHAYES
;
IF PMMI
;
;The PMMI modem automatically hangs up the phone after
;15 seconds of loss of carrier, providing you output to
;port 0 to allow it (which this program does).
;
;..so, this routine first checks if the modem has hung up,
;and if so, returns with carry set. If not, it checks for
;carrier and returns if carrier is on; otherwise waits for
;carrier while still testing for disconnect.
;
;It tests the PMMI "CTS" (clear to send) bit
;which is 0 when there is carrier
;
IN RPORT ;GET STATUS
ANI P2CONN ;CONNECTED?
STC ;(IN CASE NOT)
RNZ ;HUNG UP.
;Still connected, check for carrier
IN RPORT ;LOOK AT STATUS
ANI P2CTS ;GET CARRIER DETECT BIT
JZ CARCK2 ;CONTINUE W/TESTS
;Loop until either connection lost, or carrier returns
JMP CARCK
ENDIF ;PMMI
;
IF IN8251
;
;Racal-Vadic modem automatically hangs up phone 1 second
;after carrier loss.
;
IN SPORT ;GET STATUS
ANI DSR ;CHECK IF CARRIER ON
JNZ CARCK2 ;YES, CONTINUE ON
STC ;SET CARRY BIT FOR NO CARRIER
RET
ENDIF ;IN8251
;
IF WD8250
;THE WD8250 HAS HARDWARE HANGUP. BUT WE WILL USE CARRIER DETECT
;ROUTINE TO DETERMINE CARRIER LOSS AFTER 15 SECONDS.......
;
IN MSPORT ;GET MODEM STATUS
ANI P2CTS ;GOT A CARRIER
JNZ CARCK2 ;YES, GO ON WITH TESTS
PUSH B ;PRESERVE SO WE CAN USE IT
MVI B,150 ;SET FOR 15 SECONDS
;
CARLP EQU $+OFFSET
;
CALL DELAY ;WAIT .1 SECOND
IN MSPORT ;GET MODEM STATUS
ANI P2CTS ;HAS CARRIER RETURNED ?
MOV A,B ;PRESERVE COUNT DOWN VALUE
POP B ;FIX STACK IF ALL IS OK
JNZ CARCK2 ;HAVE CARRIER - CONTINUE
DCR A ;COUNT DOWN TIME
STC ;IN CASE THIS IS THE END OF TIME
RZ ;RETURN IF TIMED OUT
PUSH B ;PRESERVE B
MOV B,A ;GET COUNTER VALUE IN B
JMP CARLP ;CONTINUE - KEEP CHECKING
ENDIF ;WD8250
;Now test drive #'s and (if CP/M 2.x) user #'s to
;insure that maximums are not exceeded.
;
CARCK2 EQU $+OFFSET
LDA 4 ;CHECK DISK/USER #
ANI 0FH ;ISOLATE DRIVE
PUSH H ;SAVE HL
LXI H,MXDRV ;PT TO ALLOWED # DRIVES
CMP M ;VALID DRIVE?
JC CARCK3 ;YES, SKIP THIS JUNK
LDA 4 ;GET WHOLE LOGIN BYTE
ANI 0F0H ;RETAIN USER # & FORCE DRIVE TO A
STA 4 ;UPDATE LOGIN BYTE
CALL ILPRT ;TELL USER WHAT HE DID
DB 'A>',0
JMP 0 ;WARM BOOT
;
CARCK3 EQU $+OFFSET
;
IF CPM2
LDA 4 ;GET LOGIN BYTE
ANI 0F0H ;ISOLATE USER #
RRC ;MOVE TO LOW BITS
RRC
RRC
RRC
LXI H,MXUSR ;PT TO MAX USER #
CMP M ;VALID USER #?
JC CARCK4 ;YES, DON'T CHANGE
JZ CARCK4
LDA 4 ;GET LOGIN BYTE AGAIN
ANI 0FH ;KEEP DRIVE, ZERO USER
STA 4 ;UPDATE LOGIN BYTE
CALL ILPRT ;TELL HIM WHAT HAPPENED
DB '> [Invalid user number, returning to 0]',0
JMP 0 ;WARM BOOT
ENDIF ;CPM2
;
CARCK4 EQU $+OFFSET
POP H ;RESTORE HL
ORA A
RET
;
;.1 sec delay routine
;
DELAY EQU $+OFFSET
PUSH B
;
IF FASTCLK
LXI B,16667 ;4 MHZ TIMING CONSTANT
ENDIF
;
IF NOT FASTCLK
LXI B,8334 ;2 MHZ TIMING CONSTANT
ENDIF
;
DELAY1 EQU $+OFFSET
DCX B
MOV A,B
ORA C
JNZ DELAY1
POP B
RET
;
;50 ms delay routine
;
KDELAY EQU $+OFFSET
PUSH B
;
IF FASTCLK
LXI B,8334
ENDIF
;
IF NOT FASTCLK
LXI B,4167
ENDIF
;
JMP DELAY1
;
;Patch in the new JMP table (saving the old)
;
PATCH EQU $+OFFSET
CALL TBLADDR ;CALC HL= CP/M JMP TABLE
LXI D,VCOLDBT ;POINT TO SAVE LOCATION
MVI B,24 ;SAVE ALL VECTORS
CALL MOVE ;MOVE IT
;Now move new JMP table to CP/M
CALL TBLADDR ;CALC HL=CP/M'S JMP TABLE
XCHG ;MOVE TO DE
LXI H,NEWJTBL ;POINT TO NEW
CALL MOVE ;MOVE IT
;
IF IN8251
LXI H,NWBCALL ;POINT TO NEW CALL
SHLD WBCALL+1 ;MODIFY CALL IN BIOS
ENDIF ;IN8251
;
RET
;
UNPATCH EQU $+OFFSET
CALL TBLADDR ;HL=CP/M'S JMP TABLE
XCHG ;MOVE TO DE
LXI H,VCOLDBT ;GET SAVED TABLE
CALL MOVE ;MOVE ORIG BACK
;
IF LOSER
LXI H,WMSTRT ;LOAD OLD CALL LOCATION
SHLD WBCALL+1 ;RESTORE OLD CALL
ENDIF ;LOSER
;
RET
;
;Calculate HL=CP/M's jump table, B=length
;
TBLADDR EQU $+OFFSET
LHLD 1 ;GET BIOS POINTER
DCX H ;..SKIP
DCX H ;..TO
DCX H ;..COLD BOOT
;
IF (NOT PRINTER) and (NOT ALLDEV)
MVI B,18 ;BYTES TO MOVE
ENDIF ;NOT PRINTER AND NOT ALLDEV
;
IF PRINTER ;RETAIN LIST DEVICE?
MVI B,15 ;DON'T MOVE LISTER JUMP
ENDIF ;PRINTER
;
IF ALLDEV ;THIS PATCHES ALL DEVICES TO PHONE
MVI B,24 ;MOVE ALL JUMPS
ENDIF ;ALLDEV
RET
;
;Move (HL) to (DE), length in (B)
;
MOVE EQU $+OFFSET
MOV A,M ;GET A BYTE
STAX D ;PUT AT NEW HOME
INX D ;BUMP POINTERS
INX H
DCR B ;DEC BYTE COUNT
JNZ MOVE ;IF MORE, DO IT
RET ;IF NOT,RETURN
;
IF LOSER
NWBCALL EQU $+OFFSET
CALL WMSTRT ;WARM BOOT DISK READ
CALL PATCH ;FIX BIOS AGAIN AFTER WMSTRT
RET
ENDIF ;LOSER
;
;Common routine to check for carrier lost, called from console out
;
CHECK EQU $+OFFSET
;
IF MINICK
;
LDA IOBYTE ;GET IOBYTE
ANI 80H ;TEST FOR DISK UPDATE
RTN ;BUSY WAIT UNTIL DONE
;
ENDIF ;MINICK
;
IF RBBSCK
;
LDA WRTLOC ;GET WRITE IN PROGRESS FLAG
ORA A
RNZ ;BUSY WAIT UNTIL DONE
;
ENDIF ;RBBSCK
;
CALL CARCK ;SEE IF CARRIER STILL ON
RNC ;ALL OK
;
;Carrier is lost. Type message so local console shows the reason
;
BADPASS EQU $+OFFSET ;COME HERE ON BAD PASSWORD
MVI A,1 ;SHOW CARRIER LOST SO
STA LOSTFLG ;..WE WON'T CK AGAIN
LXI SP,STACK ;ENSURE VALID STACK
CALL ILPRT
DB CR,LF
DB '[Carrier Lost]'
DB CR,LF,' ',0
CALL UNPATCH ;RESTORE ORIG BIOS JMP TBL
XRA A ;CLEAR OUT CARRIER..
STA LOSTFLG ;..LOST FLAG
JMP HANGUP
;
;Readbyte routine - used to read the welcome file
;
RDBYTE EQU $+OFFSET
MOV A,H ;TIME TO READ?
ORA A ;..IF AT 100H
JZ NORD ;NO READ REQ'D
;Have to read a sector
LXI D,FCB
MVI C,READ
CALL BDOS
ORA A ;OK?
MVI A,1AH ;FAKE UP EOF
RNZ ;RET EOF IF BAD
LXI H,80H
;
NORD EQU $+OFFSET
MOV A,M ;GET CHAR
INX H ;TO NEXT
RET
;
;Keyboard/modem status test routine
;
MSTAT EQU $+OFFSET
;
CALL CHECK ;CHECK FOR CARRIER LOST
;
IF DUAL$IO ;WANT LOCAL CONSOLE?
CALL CONSTAT ;GET LOCAL STATUS
ORA A
RNZ ;RET IF LOCAL CHAR
ENDIF ;DUAL$IO
;
IF DCHAYES
IN STATUS ;GET MODEM STATUS
ANI RRF ;GOT A CHARACTER?
RZ ;RETURN IF NOT
IN STATUS ;GET MODEM STATUS
ANI FE+OE ;CHECK FOR FRAMING AND OVERRUN ERROR
JZ MSTAT1 ;NO ERROR, CHARACTER IS VALID
IN DATA ;SWALLOW CHARACTER (ALSO CLEAR OE & FE)
XRA A ;RETURN FALSE
RET
ENDIF ;DCHAYES
;
IF PMMI
IN TPORT ;GET STATUS
ANI P0DAV ;DATA AVAILABLE?
RZ ;RETURN IF NOT READY
IN TPORT ;GET STATUS
ANI 30H ;CHECK FRAMING AND OVERRUN BITS
JZ MSTAT1 ;NO ERRORS...LEGIT CHARACTER
IN DPORT ;SWALLOW CHARACTER (CLEARS PODAV)
XRA A ;RETURN FALSE
RET
ENDIF ;PMMI
;
IF IN8251
IN SPORT ;GET STATUS
ANI RCVRDY ;GOT A CHARACTER
RZ ;RETURN IF NOT
IN SPORT ;GET STATUS
ANI TOERR ;CHECK FOR PARITY, FRAMING AND OVERRUN ERRORS
JZ MSTAT1 ;NO ERRORS
MVI A,ONINS ;RESET ERROR FLAGS
OUT CPORT
XRA A ;RETURN FALSE
RET
ENDIF ;IN8251
;
IF WD8250
IN SPORT ;GET STATUS
ANI P0DAV ;DATA AVAILABLE
RZ ;RTN IF NOT RDY
IN SPORT ;GET STATUS
ANI 0EH ;CHECK PAR, FRAM ERR AND OVRN BITS
JZ MSTAT1
IN DPORT
XRA A ;RTN FALSE
RET
ENDIF ;WD8250
MSTAT1 EQU $+OFFSET
MVI A,0FFH ;SHOW READY
ORA A
RET
;
;Modem input function, checks local console first
;
MINPUT EQU $+OFFSET
;
IF TIMEOUT
LDA TOVAL ;GET # MINUTES BEFORE TIMEOUT
;
MINPUT0 EQU $+OFFSET
STA TOCNTM ;SET MINUTES COUNTER
PUSH H
LXI H,MINUTES ;INIT ONE MINUTE TIMEOUT COUNTER
SHLD TOCNT
POP H
ENDIF ;TIMEOUT
;
MINPUT1 EQU $+OFFSET
LDA LOSTFLG ;KNOWN LOSS..
ORA A ;..OF CARRIER?
CZ CHECK ;CARRIER STILL ON?
CALL MSTAT ;ANYTHING?
ORA A
;
IF NOT TIMEOUT
JZ MINPUT ;LOOP TILL CHAR RCD
ENDIF ;NOT TIMEOUT
;
IF TIMEOUT
JNZ MINPUT2
CALL KDELAY ;KILL 50 MS
PUSH H
LHLD TOCNT ;KNOCK DOWN TIMEOUT COUNTER
DCX H
SHLD TOCNT
MOV A,H
ORA L
POP H
JNZ MINPUT1 ;STILL TIME LEFT..KEEP TRYING
LDA TOCNTM ;COUNT OFF LAST MINUTE
DCR A
JNZ MINPUT0 ;GO BACK IF TIME LEFT
CALL ILPRT
DB '[Input timed out]',7,7,0
JMP NOSLASH
ENDIF ;TIMEOUT
;
MINPUT2 EQU $+OFFSET
;
IF DUAL$IO ;BOTH LOCAL AND REMOTE
CALL CONSTAT ;CHECK LOCAL CONSOLE
ORA A ;CHAR?
JNZ CONIN ;..YES, READ IT, RET.
ENDIF
;
;Local console wasn't ready, so read modem
;
IN DPORT ;GET DATA BYTE
ANI 7FH ;DELETE PARITY
JZ MINPUT ;IGNORE NULLS
;
IF IMSAI AND HARDLOG
PUSH B
MOV B,A
IN SENSE
ANI LOGSW
MOV A,B
POP B
JZ NOLOG
ENDIF ;IMSAI AND HARDLOG
;
IF HARDLOG
CPI 20H
JNC MINPUT3
CPI CR
JNZ NOLOG
;
MINPUT3 EQU $+OFFSET
CALL LISTOUT ;ECHO ON PRINTER
CPI CR
JNZ NOLOG ;CR NEEDS LINEFEED
MVI A,LF
CALL LISTOUT ;SO SEND IT
MVI A,CR ;GET BACK CR
ENDIF ;END OF HARDLOG
;
NOLOG EQU $+OFFSET
;
CPI 3 ;IS IT CONTROL-C?
RNZ ;NO, PASS IT THRU
LDA 0 ;SEE IF WARM BOOT DISABLED
CPI 0C3H ;JMP MEANS WARM BOOT OK
MVI A,3 ;SO RETURN CONTROL-C
RZ
XRA A ;ELSE CONVERT TO NULL
RET
;
;Modem output function
;
MOUTPUT EQU $+OFFSET
;
;If we already know carrier is lost, don't check
;for it again or loop trying to output.
;
LDA LOSTFLG ;KNOWN LOSS OF CARRIER?
ORA A
JNZ SILENT ;AVOID LOOP IN CASE CARRIER LOST
CALL CHECK ;CARRIER STILL ON?
;
IF DCHAYES
IN STATUS ;GET MODEM STATUS
ANI TRE ;TRANSMIT BUFFER EMPTY?
ENDIF ;DCHAYES
;
IF PMMI
IN TPORT ;GET MODEM STATUS
ANI P0TBMT ;TRANSMIT BUFFER EMPTY?
ENDIF ;PMMI
;
IF IN8251
IN SPORT ;GET MODEM STATUS
ANI TRNRDY ;TRANSMIT BUFFER EMPTY?
ENDIF ;IN8251
;
IF WD8250
IN SPORT
ANI P0TBMT
ENDIF ;WD8250
;
JZ MOUTPUT ;LOOP IF NOT READY
;
IF IMSAI AND BLKOUT AND DUAL$IO
IN SENSE ;FLIP SWITCH UP...
ANI BLACKSW ;..TO BLIND REMOTE USER
JNZ SILENT
ENDIF ;IMSAI AND BLKOUT AND DUAL$IO
;
MOV A,C ;GET CHAR
ANI 7FH ;STRIP PARITY BIT
;
IF TRAPLC
CPI 60H ;CHECK FOR LOWER CASE
JC MOUTP2 ;SKIP IF NOT LC
CPI 7FH ;CHECK FOR RUBOUT
JZ MOUTP2
PUSH H
LXI H,ULCSW ;SUBTRACT EITHER 20H OR 0
SUB M
POP H
MOV C,A ;FORCE ON LOCAL AS WELL AS REMOTE
;
MOUTP2 EQU $+OFFSET
ENDIF ;TRAPLC
;
OUT DPORT ;OUTPUT TO MODEM
;
SILENT EQU $+OFFSET
;
IF DUAL$IO ;TO LOCAL ALSO?
PUSH PSW ;SAVE CHAR
CALL CONOUT ;SEND TO REGULAR BIOS
POP PSW ;GET CHAR AGAIN
ENDIF ;DUAL$IO
;
;Check for nulls
CPI LF ;TIME FOR NULLS?
RNZ ;NO, RETURN
;Send nulls if required
LDA NULLS ;GET COUNT
ORA A ;ANY?
RZ ;..NO
PUSH B
MOV B,A ;SAVE COUNT
MVI C,0 ;0 IS A NULL
;
NULLP EQU $+OFFSET
CALL MOUTPUT ;TYPE A NULL
DCR B ;MORE?
JNZ NULLP ;..YES, LOOP
POP B
MVI C,LF ;RESTORE LF
RET
;
;Boot trap - becomes disconnect if JMP at 0 has been altered
;
MBOOT EQU $+OFFSET
LDA 0 ;LOOK AT OPCODE
CPI 0C3H ;IS IT STILL JMP?
JZ VWARMBT ;YES, ALLOW IT
JMP NOSLASH ;NO, DISCONNECT
;
;Inline print routine
;
ILPRT EQU $+OFFSET
XTHL ;SAVE HL, GET MSG
PUSH B ;SAVE BC REGS
;
ILPLP EQU $+OFFSET
MOV C,M ;GET CHAR
CALL MOUTPUT ;OUTPUT IT
INX H ;POINT TO NEXT
MOV A,M ;TEST
ORA A ;..FOR END
JNZ ILPLP
POP B ;RESTORE BC REGS
XTHL ;RESTORE HL, RET ADDR
RET ;RET PAST MSG
;
IF PWRQD ;KEEP PASSWORD HERE
;Access password (ends in carriage return)
;
PASSWD EQU $+OFFSET
DB 'TWIT' ;THE PASSWORD ITSELF
DB CR ;END OF PASSWORD
;Allow room for bigger password to be patched in
DB 0,0,0,0,0,0,0,0,0,0,0,0,0
ENDIF ;PWRQD
;
;Routine to load the COM file
;
IF COMFILE
LODCOM EQU $+OFFSET
XRA A ;INITIALIZE FCB
STA COMFCB
LXI H,COMFCB+12
MVI B,21
;
ZLOOP EQU $+OFFSET
MVI M,0
INX H
DCR B
JNZ ZLOOP
;
MVI C,OPEN ;NOW OPEN THE FILE
LXI D,COMFCB
CALL BDOS
INR A ;SHOULD BE NON-ZERO
JZ ABORT ;NO FILE, ABORT
;
;Now load the file
LHLD 6 ;GET TOP OF MEMORY
LXI D,-80H ;RECORD LOADS CAN'T START..
DAD D ;..ABOVE (BDOS) - 80H
PUSH H ;SAVE ON STACK
;
LXI D,80H ;TPA-80H
LXI B,0 ;KEEP A RECORD COUNTER
PUSH B ;SAVE COUNTER
PUSH D ;AND LOAD ADDRESS
;
GLOOP EQU $+OFFSET
POP D ;GET TPA ADRS
LXI H,80H ;POINT TO NXT ADRS TO READ TO
DAD D ;HL HAS THE ADDRESS
POP B ;INCREMENT THE COUNTER
;Check for load past top-of-memory
POP D ;GET (TOP-OF-MEMORY)
PUSH D ;RE-SAVE FOR NEXT TIME
MOV A,E ;SUBTRACT: (TOP) - (ADRS)
SUB L
MOV A,D ;ONLY THE CARRY NEEDED
SBB H
JNC SIZEOK ;CY= BETTER MOVCPM
CALL ERRXIT ;SO TELL THE STORY
DB '[Program area too small]','$'
;
SIZEOK EQU $+OFFSET
INX B
PUSH B
PUSH H ;SAVE TPA ADRS
XCHG ;ALIGN REGISTERS
MVI C,STDMA ;TELL BDOS WHERE TO PUT RECORD
CALL BDOS
LXI D,COMFCB ;NOW READ THE RECORD
MVI C,READ
CALL BDOS
ORA A
JZ GLOOP ;A=0 IF MORE TO READ
POP B ;UNJUNK STACK
POP B ;THIS IS OUR COUNTER
POP H ;MORE JUNK ON STACK
MOV A,B ;CHECK FOR ZERO
ORA C
JZ ABORT ;WE SHOULD HAVE READ SOMETHING
LXI D,80H ;WE DID, RESET DMA TO 80H
MVI C,STDMA
CALL BDOS
CALL LOADOK ;PRINT THIS MSG TO CONSOLE:
DB 'COM file loaded',CR,LF,'$'
;
LOADOK EQU $+OFFSET
POP D
LDA OPTION ;SEE IF THIS WAS "BYE /C"
CPI 'C' ;IF IT WAS THEN..
RZ ;..DON'T PRINT MESSAGE
MVI C,PRINTF
CALL BDOS
RET
;
ABORT EQU $+OFFSET
CALL ERRXIT
DB CR,LF
DB '[Cannot find COM file]','$'
;
ERRXIT EQU $+OFFSET
POP D
MVI C,PRINTF
CALL BDOS ;PRINT THE ABORT MSG
JMP EXCPM ;WARM BOOT
ENDIF ;COMFILE
;
;This area is used for vectoring calls to the
;user's CBIOS, but saving the registers first
;in case they are destroyed.
;
CONSTAT EQU $+OFFSET
PUSH B
PUSH D
PUSH H
CALL VCONSTAT
POP H
POP D
POP B
RET
;
CONIN EQU $+OFFSET
PUSH B
PUSH D
PUSH H
CALL VCONIN
;
IF FKEYS
CALL CKFUNC
ENDIF ;FKEYS
;
POP H
POP D
POP B
RET
;
CKFUNC EQU $+OFFSET
;
IF FKEYS AND IMSAI
PUSH B
MOV B,A ;SAVE CHAR
IN SENSE ;READ THE SWITCHES
ANI ENABLF ;CHECK FKEY ENAB SW
MOV A,B ;GET CHAR
POP B
RZ ;NO FUNCT IF SW OFF
ENDIF ;FKEYS AND IMSAI
;
IF OXGATE
CPI LF ;WE HAVE A TOGGLE FOR LINE FEEDS
JNZ MOUTP3 ;NOPE, NOT A LF
LDA LFEEDS ;YES, SEE IF WE CAN SEND IT...
ORA A
MVI A,0
RNZ ;NOPE, DON'T!
MVI A,LF
MOUTP3 EQU $+OFFSET
ENDIF ;OXGATE
;
IF FKEYS
CPI SYSDKEY
JZ SYSDOWN ;TELL CALLER TO LEAVE
CPI TWITKEY
JZ GOODBY ;MAKE CALLER LEAVE
CPI MSGKEY
RNZ
CALL ILPRT ;SEND CALLER A MESSAGE
DB 'Message from Sysop:',0
MVI A,' ' ;SOMETHING TO RETURN WITH
RET
;
SYSDOWN EQU $+OFFSET
CALL ILPRT
DB 'System going down in'
DB ' 5 minutes...',0
MVI A,' '
RET
ENDIF ;FKEYS
;
CONOUT EQU $+OFFSET
PUSH B
PUSH D
PUSH H
CALL VCONOUT
POP H
POP D
POP B
RET
;
LISTOUT EQU $+OFFSET
PUSH B
PUSH D
PUSH H
PUSH PSW
MOV C,A
CALL VLISTOUT
POP PSW
POP H
POP D
POP B
RET
;
;This is the JMP table which is copied on top
;of the one pointed to by location 1 in CP/M
;
NEWJTBL EQU $+OFFSET
JMP MCBOOT ;COLD BOOT
JMP MBOOT ;WARM BOOT
JMP MSTAT ;MODEM STATUS TEST
JMP MINPUT ;MODEM INPUT ROUTINE
JMP MOUTPUT ;MODEM OUTPUT ROUTINE
IF NOT ALLDEV
RET ;DUMMY LIST DEVICE
NOP
NOP
ENDIF ;NOT ALLDEV
;
IF ALLDEV
JMP MOUTPUT ;MODEM LIST DEVICE
JMP MOUTPUT ;MODEM PUNCH DEVICE
JMP MINPUT ;MODEM READER DEVICE
ENDIF ;ALLDEV
;
IF CCSDISK
;
DSKON EQU $+OFFSET
PUSH PSW ;SAVE THE A AND FLAGS
MVI A,DISKON ;VALUE TO TURN ON MOTORS
OUT DISK ;TO THE DISK CONTROLLER
PUSH H ;THIS IS TIMER
LXI H,0000H ;THIS LONG
DSKLP EQU $+OFFSET
XTHL
XTHL
DCX H ;COUNT LOOP
MOV A,H ;CHECK FOR DONE
ORA L
JNZ DSKLP
POP H ;RESTORE HL
POP PSW ;AND A & FLAGS
RET
;
DSKOFF EQU $+OFFSET
PUSH PSW ;SAVE A & FLAG
MVI A,DISKOFF ;VALUE TO TURN MOTORS OFF
OUT DISK
POP PSW
RET
;
ENDIF ;CCSDISK
;
IF RTC
CLKBASE EQU 50H ;BASE OF SYSTEM SUPPORT 1 CARD
CLKCTL EQU CLKBASE+10 ;CLOCK CONTROL PORT
CLKDATA EQU CLKBASE+11 ;CLOCK DATA PORT
CREAD EQU 10H+40H ;READ COMMAND + HOLD COUNT COMMAND
;
TIME EQU $+OFFSET
PUSH H
PUSH D
PUSH B
PUSH PSW
MVI D,CREAD+5 ;POINT TO 10S OF HOURS
MVI B,3 ;3 LOOPS
JMP TX ;START W/ NO SEPARATOR
;
T1 EQU $+OFFSET
MVI C,':' ;SEPARATOR
CALL MOUTPUT ;TO THE PRINTER
TX EQU $+OFFSET
MOV A,D ;GET THE DIGIT ADDRESS
CALL CLOCK ;GET THE VALUE
MOV C,A ;SAVE IT
MVI A,CREAD+5 ;TEST FOR FIRST LOOP
CMP D ;1ST LOOP?
MOV A,C ;RECOVER THE VALUE
JNZ T2 ;JUMP IF NOT 1ST LOOP
ANI 3 ;DROP PM INDICATOR
T2 EQU $+OFFSET
ADI '0' ;ADD ASCII BIAS
MOV C,A
CALL MOUTPUT ;AND PRINT IT
DCR D ;POINT TO NEXT DIGIT
MOV A,D ;GET THE DIGIT ADDRESS TO A
CALL PCLOCK ;GET & PRINT ASCII
DCR D ;BUMP DIGIT COUNTER
DCR B
JNZ T1 ;LOOP TILL ALL PRINTED
;
;
CALL ILPRT ;PRINT THE TIME ZONE
DB ' CST ',0 ;CENTRAL STANDARD TIME
;
; WE WILL NOW PRINT THE DAY OF THE WEEK, FOLLOWED
; BY THE MONTH, DATE AND YEAR
;
;
MVI A,CREAD+6 ;THIS IS DAY OF WEEK
CALL CLOCK ;GET THE DAY NUMBER
;
DAYDONE EQU $+OFFSET
ADD A ;DOUBLE DAY COUNT
LXI H,DAYS ;POINT TO TABLE
MOV E,A ;ADD OFFSET TO DE
MVI D,0
DAD D ;NEW POINTER IN HL
MOV A,M ;GET LO BYTE OF WORD
INX H ;POINT TO HI BYTE
MOV H,M ;TO H
MOV L,A ;PLUS LO BYTE POINTS TO STRING
CALL LINOUT ;PRINT THE DAY
;
MVI A,CREAD+10 ;10S OF MONTHS
CALL CLOCK
ORA A ;WE GOT 10'S OF MONTHS?
JZ NOTENS ;JUMP IF NOT
MVI A,10 ;ADD 10S IF WE GOT EM
NOTENS EQU $+OFFSET
MOV B,A ;SAVE 10S IN B
MVI A,CREAD+9 ;GET THE ONES
CALL CLOCK
ADD B ;ADD TO THE 10S PLACE TO GET MONTH
DCR A ;CORRECT FOR JAN=1
ADD A ;DOUBLE MONTH NUMBER
LXI H,MONTHS ;POINT TO DISPATCH TABLE
MOV E,A ;OFF SET TO DE
MVI D,0
DAD D ;POINTER TO STRING AT (HL)
MOV A,M ;GET LO BYTE TO A
INX H ;POINT TO NEXT
MOV H,M ;HI BYTE TO H
MOV L,A ;LO BYTE TO L POINTS TO STRING
CALL LINOUT ;PRINT THE MONTH
;
MVI A,CREAD+8 ;10S OF DAYS
CALL CLOCK
ANI 3 ;DROP LEAP YEAR INDICATOR
JZ NTENS ;JUMP IF NO TENS PLACE
CALL PASC ;PRINT IT
NTENS EQU $+OFFSET
MVI A,CREAD+7 ;ONES OF DAYS
CALL PCLOCK ;PRINT THEM
LXI H,YEAR ;PLUS YEAR MESSAGE
CALL LINOUT ;TO LISTER
MVI A,CREAD+12 ;TENS OF YEAR
CALL PCLOCK ;PRINT THEM
MVI A,CREAD+11 ;ONES OF YEAR
CALL PCLOCK
CALL ILPRT ;FINISH THE LINE
DB CR,LF,CR,LF,0
POP PSW
POP B
POP D
POP H
RET
;
PCLOCK EQU $+OFFSET
CALL CLOCK ;GET THE DIGIT
PASC EQU $+OFFSET
ADI '0' ;ADD ASCII BIAS
MOV C,A
JMP MOUTPUT ;AND PRINT
;
CLOCK EQU $+OFFSET
OUT CLKCTL ;TELL IT ADDRESS
IN CLKDATA ;GET THE DATA NYBBLE
PUSH PSW ;SAVE THE DATA
XRA A ;GET 0
OUT CLKCTL ;RESET HOLD BIT
POP PSW ;RESTORE DATA
RET
;
LINOUT EQU $+OFFSET
MOV A,M ;GET THE CHARACTER
CPI '$' ;DONE?
RZ ;RETURN IF DONE
MOV C,A ;ELSE PRINT IT
CALL MOUTPUT
INX H ;POINT TO NEXT CHARACTER
JMP LINOUT ;THEN LOOP TILL DONE
;
;
SUN EQU $+OFFSET
DB 'Sunday, $'
MON EQU $+OFFSET
DB 'Monday, $'
TUE EQU $+OFFSET
DB 'Tuesday, $'
WED EQU $+OFFSET
DB 'Wednesday, $'
THU EQU $+OFFSET
DB 'Thursday, $'
FRI EQU $+OFFSET
DB 'Friday, $'
SAT EQU $+OFFSET
DB 'Saturday, $'
;
JAN EQU $+OFFSET
DB 'January $'
FEB EQU $+OFFSET
DB 'February $'
MAR EQU $+OFFSET
DB 'March $'
APR EQU $+OFFSET
DB 'April $'
MAY EQU $+OFFSET
DB 'May $'
JUN EQU $+OFFSET
DB 'June $'
JUL EQU $+OFFSET
DB 'July $'
AUG EQU $+OFFSET
DB 'August $'
SEP EQU $+OFFSET
DB 'September $'
OCT EQU $+OFFSET
DB 'October $'
NOV EQU $+OFFSET
DB 'November $'
DEC EQU $+OFFSET
DB 'December $'
;
YEAR EQU $+OFFSET
DB ', 19$'
;
;#################################################
DAYS EQU $+OFFSET
DW SUN
DW MON
DW TUE
DW WED
DW THU
DW FRI
DW SAT
DW SUN
;
MONTHS EQU $+OFFSET
DW JAN
DW FEB
DW MAR
DW APR
DW MAY
DW JUN
DW JUL
DW AUG
DW SEP
DW OCT
DW NOV
DW DEC
;
;
ENDIF ;RTC
;
WELFILN EQU $+OFFSET
DB 0,'WELCOME ',0
;Welcome file name ^^^^^^^^^^^ (must be 11 characters)
;
COMFCB EQU $+OFFSET
;
IF NOT OXGATE
DB 0,'RBBS COM'
;COM file name ^^^^^^^^^^^ (must be 11 characters)
ENDIF ;NOT OXGATE
;
IF OXGATE
DB 0,'OXENTR COM'
;COM file name ^^^^^^^^^^^ (must be 11 characters)
ENDIF ;OXGATE
;
PEND EQU $+OFFSET ;END OF RELOCATED CODE
;
;These areas are not initialized
;
DS 21 ;REST OF COM FCB
;
OPTION EQU $+OFFSET
DS 1
;
TOCNTM EQU $+OFFSET
DS 1
;
TOCNT EQU $+OFFSET
DS 2
;
;Byte to keep track of lost carrier when
;typing "[Carrier Lost]" so we don't loop
;
LOSTFLG EQU $+OFFSET
DS 1
;
;Save the CP/M jump table here
;
VCOLDBT EQU $+OFFSET
DS 3
;
VWARMBT EQU $+OFFSET
DS 3
;
VCONSTAT EQU $+OFFSET
DS 3
;
VCONIN EQU $+OFFSET
DS 3
;
VCONOUT EQU $+OFFSET
DS 3
;
VLISTOUT EQU $+OFFSET
DS 3
;
VPUNCH EQU $+OFFSET
DS 3
;
VREADER EQU $+OFFSET
DS 3
;
;
;
;Since these areas are not initialized,
;the following counters will not be changed
;by subsequent loads of this program
;
IF USRLOG
OLDUSR EQU $+OFFSET
DS 2
;
NEWUSR EQU $+OFFSET
DS 2
;
NONUSR EQU $+OFFSET
DS 2
ENDIF ;USRLOG
;
;
DS 60
STACK EQU $+OFFSET ;LOCAL STACK
;
ENDMARK EQU $+OFFSET ;! IGNORE ERROR. THIS MARKS END OF PGM
;
;BDOS equates
;
CI EQU 1
WRCON EQU 2
DRECTIO EQU 6
PRINTF EQU 9
CSTS EQU 11
OPEN EQU 15
READ EQU 20
STDMA EQU 26
BDOS EQU 5
FCB EQU 5CH
FCBRNO EQU FCB+32
;
END