;  M7LB-31.ASM   as of   29 November 1985      Fred Willink
;
VER	EQU	31	; version 3.1
;
;  Ver 3.1 Corrects problem when changing speed, and parity is entered
;          as none instead of return.  Only effects non-hayes type
;	   modems ie. Racal-Vadic or Fujitsu.
;						Fred Willink
;
;  Ver 3.0 First version. 17 Jun 1985		Fred Willink
;
;  M7LB-31.ASM is for the AMPRO 'Little Board' or 'Little Board/Plus'.
;  All changes are to bios initialization settings so the the AMPRO set
;  or CONFIG utility will show the true DART settings. Initialization is
;  done by IOINIT routine in the AMPRO bios.
;
;  Features are:
;
;  Speed and parity may be changed with the SET command.  When the SET
;  command is invoked first the current speed and parity setting are shown.
;  You are then prompted for new speed and then parity. Speed may be set
;  from 300 to 9600 baud and parity to odd, even, mark, or none.  If odd or 
;  even parity is used word length is set to seven bits + parity if no
;  parity word length is 8 bits.  Mark parity sets the DART to a 7 bit word
;  with 2 stop bits this is the equalivent of an 8 bit word with the 8th bit
;  always one, ie. mark parity. Mark parity is required by some large computer
;  systems.  When a carriage return is typed on the command line for speed or 
;  parity no changes are made for that paramater.
;
;  A .5 sec. break will be sent with the ^@ command.  Time may be
;  adjusted.
;
;  Equates are included for the Racal-Vadic VA212PA intelligent modem for
;  the SETDTRH: and SETDTRL: routines in M7RV@6.ASM
;
;  To install first insure the RACAL equate is set to YES if using the
;  Racal-Vadic VA212PA modem, or NO if using a Hayes or compatable.
;  Then assemble using ASM.COM to produce M7LB-9.HEX and overlay using DDT.
;
;  Enter    DDT MDM7xxx.COM
;           DDT VERS 2.2
;           NEXT  PC
;           4A00 0100
;  Enter    -IM7RV@6.HEX           If using the Racal-Vadic
;  Enter    -R
;           NEXT  PC
;           4A00 0000
;  Enter    -IM7LB-31.HEX
;  Enter    -R
;           NEXT  PC
;           4A00 0000
;  Enter    -G0
;
;  Enter    A>SAVE 73 MDM.COM
;
; ---------------------------------------------------------------           
;  Port Equates for the AMPRO "little board" or "little board +"
;
BAUDRP:		EQU	50H	;modem baud rate port (CTC)
MODCTL1:	EQU	8CH	;modem control port
MODDATP:	EQU	88H	;modem data port
MODRCVB:	EQU	01H	;modem receive bit (for SIO/DART)
MODRCVR:	EQU	01H	;modem receive ready bit
MODSNDB:	EQU	04H	;modem send bit (for SIO/DART)
MODSNDR:	EQU	04H	;modem send ready bit
;
;  Divisor values for CTC counter/timer
;
CT300:		EQU	208	; divisor for 300 bps x32 sio clk
CT1200:		EQU	104	; divisor for 1200 bps x16 sio clk
CT2400:		EQU	52	; divisor for 2400 bps x16 sio clk
CT4800:		EQU	26	; divisor for 4800 bps x16 sio clk
CT9600:		EQU	13	; divisor for 9600 bps x16 sio clk
;
; ---------------------------------------------------------------
;
YES:		EQU	0FFH
NO:		EQU	0
;
CR:		EQU	13
LF:		EQU	10
ESC:		EQU	27
;
; ---------------------------------------------------------------
;  If using Racal-Vadic VA212PA modem EQU=YES, else set EQU=NO if not.
;
RACAL:		EQU	NO
; ---------------------------------------------------------------
;
		ORG	0100H
;
		DS	3	; jmp start
PMMIMODEM:	DB	NO	; overlay not for use with PMMI
AUTODIAL:	DB	YES	; non-PMMI modem
TOUCHPULSE:	DS	1	; T=touch, P=pulse dial
CLOCK:		DB	40	; clock speed in mhz x 10
MSPEED:		DB	5	; DART init routines is set according to
				; mspeed. 1=300 bps,5=1200 bps,6=2400 bps
				; 7=4800 bps,8=9600 bps
BYTDLYL:	DS	1	; 
CRDLY:		DS	1	;
NOOFCOL:	DS	1	; number of directory columns
SETUPTST:	DB	YES	; yes=non-PMMI set up routine
SCRNTEST:	DB	NO	; yes=home cursor and clear screen
RETRY:		DB	YES	; yes=reset the error limit to try again
				; no=abort after 10 consecutive errors
				; (arpanet users should select yes)
BAKUPBYTE:	DS	1	; yes=make .bak file
CRCDFLT:	DS	1	; yes=defalt to crc checking
				; no=defalt to checksum checking
TOGGLECRC:	DS	1	; yes=toggling of checksum to crc
CONVRUB:	DS	1	; yes=convert rub to backspace
TOGGLERUB:	DS	1	; yes=allow toggling of rub to backspace
ADDLF:		DS	1	; no=no lf after cr to send file in
				; terminal mode (added by remote echo)
TOGGLELF:	DS	1	; yes=allow toggling of lf after cr
TRANLOGON:	DB	NO	; yes=allow transmission of logon
SAVCCP:		DS	1	; yes=donot overwrite ccp
LOCNXTCHR:	DS	1	; yes=local cmd if extchr precedes
				; no=not local cmd if extchr precedes
TOGGLELOC:	DS	1	; yes=allow toggling of locnxtchr
LSTTST:		DS	1	; yes=allow toggling of printer on/off
				; in terminal mode. set to no if using
				; the printer port for the modem
XOFFTST:	DS	1	; yes=allow testing of xoff from remote
				; while sending a file in terminal mode
XONWAIT:	DS	1	; yes=wait for xon after sending cr while
				; transmitting a file in terminal mode
TOGXOFF:	DS	1	; yes=allow toggling of xoff testing
IGNORCTL:	DB	NO	; yes=do not send control characters
				; above ctl-M to crt in terminal mode
				; no=send any incoming ctl-chr to crt
EXTRA1:		DS	1	; for future expansion
EXTRA2:		DS	1	; for future expansion
BRKCHR:		DB	'@'-40H	; ^@ = send a 300 ms break tone
NOCONNCT:	DB	'N'-40H	; ^N = disconnect from phone line
LOGCHR:		DB	'L'-40H	; ^L = send logon
LSTCHR:		DB	'P'-40H	; ^P = toggle printer
UNSAVECHR:	DB	'R'-40H	; ^R = close input text buffer
TRANCHR:	DB	'T'-40H	; ^T = transmite ascii file to remote
SAVECHR:	DB	'Y'-40H	; ^Y = open input text buffer
EXTCHR:		DB	'^'-40H	; ^^ = send next character
		DS	2
;
; Handles in/out ports for data and status
;
IN$MODCTL1:	IN	MODCTL1 !  RET	;in modem control port
		DB	0,0,0,0,0,0,0	;spares if needed for non-PMMI
OUT$MODDATP:	OUT	MODDATP	!  RET	;out modem data port
		DB	0,0,0,0,0,0,0	;spares if needed for non=PMMI
IN$MODDATP:	IN	MODDATP !  RET	;in modem data port
		DB	0,0,0,0,0,0,0	;spares if needed for non-PMMI
ANI$MODRCVB:	ANI	MODRCVB !  RET	;bit to test for receive ready
CPI$MODRCVR:	CPI	MODRCVR !  RET	;value of receive bit when ready
ANI$MODSNDB:	ANI	MODSNDB !  RET	;bit to test for send ready
CPI$MODSNDR:	CPI	MODSNDR !  RET	;value of send bit when ready
;
IN$BAUDRP:	RET
		DS	2
OUT$BAUDRP:	OUT	BAUDRP	!  RET	; out CTC port
OUT$MODCTL1:	OUT	MODCTL1	!  RET	; out DART control port
OUT$MODCTL2:	RET
		DS	2
;
LOGONPTR:	DW	LOGON
JMP$DIAL:	DS	3
JMP$DISCONNT:	DS	3
JMP$GOODBYE:	DS	3
JMP$INITMOD:	JMP	INITMOD
;
JMP$NEWBAUD:	RET		; PMMI routines called by main
		DS	2	; pgm have now been overlayed
JMP$NOPARITY:	RET		; so insert returns
		DS	2	;
JMP$PARITY:	RET		;
		DS	2	;
;
JMP$SETUPR:	JMP	SETUPR
JMP$SPCLMENU:	RET		; PMMI special menu
		DS	2	;
JMP$SYSVER:	JMP	SYSVER
JMP$BREAK	JMP	SENDBRK
;
JMP$ILPRT:	DS	3
JMP$INBUF:	DS	3
JMP$INLNCOMP:	DS	3
JMP$INMODEM:	DS	3
JMP$NXTSCRN:	DS	3
JMP$TIMER:	DS	3
;
;
; Clear sequences are for Televideo, Lear Siegler, etc.  Change to match
; your terminal.
;
CLREOS:		CALL	JMP$ILPRT
		DB	0,0,0,0,0	; 5 bytes do not change length
		RET
;.....
;
CLRSCRN:	CALL	JMP$ILPRT
		DB	0,0,0,0,0	; 5 bytes do not change length
		RET
;
; ---------------------- SIGN-ON MESSAGE ------------------------
;
; Send version number and date
;
SYSVER: CALL	JMP$ILPRT
	DB	'AMPRO vers. ',VER/10+'0','.',VER MOD 10+'0'
	DB	', 27 Nov 1985 ..fsw..'
	DB	CR,LF,0
	RET
;
; ------------------- LOGON MESSAGE (IF ANY) --------------------
;
; Insert your logon message here.  End with a 0 (for "CALL ILPRT").
; If used set TRANLOGON: at begining to YES.  About 100H bytes are
; available if the racal-vadic is used or NONE if Hayes or compatable.
; Best to use function keys in MDM740 for logon.
;
LOGON:	DB	0		;TO TERMINATE THE LOGON MESSAGE
;.....
;
;
; -------------------- USART INITIALIZATION ---------------------
;
; Change MSPEED to 1 if 300 baud modem is being used.  SETCTC:
; routine uses the mspeed setting for initializing the ctc and
; dart/sio.
;
INITMOD:
	JMP	SETCTC		; initialize according to mspeed
				; value
;
; ---------------------------------------------------------------
;                ****** SPEED CHANGE ******
;
; Routine called by the SET command.  Prompts user for input, if
; cr entered assumes no speed change wanted and ask for parity change
;
SETUPR:	CALL	SPDPAR		; show current speed parity settings
	CALL	JMP$ILPRT
	DB	cr,lf,'Enter new rate or return for no change'
	DB	cr,lf,'(300,1200,2400,4800,9600) ',0
	LXI	D,CBUFF		; local command buffer
	CALL	JMP$INBUF	; get response
	INX	D		; point to number of char typed
	LDAX	D		; get number of characters typed
	ORA	A		; set flags
	JZ	PRTY		; null means cr typed
	INX	D		; point to first character typed
	CALL	JMP$INLNCOMP	; and start to compare entry
	DB	'30',0
	MVI	A,1		; 1=300 bps
	JNC	PARITY
	CALL	JMP$INLNCOMP
	DB	'12',0
	MVI	A,5		; 5=1200 bps
	JNC	PARITY
	CALL	JMP$INLNCOMP
	DB	'24',0
	MVI	A,6		; 6=2400 bps
	JNC	PARITY
	CALL	JMP$INLNCOMP
	DB	'48',0
	MVI	A,7		; 7=4800 bps
	JNC	PARITY
	CALL	JMP$INLNCOMP
	DB	'96',0
	MVI	A,8		; 8=9600 bps
	JNC	PARITY
	CALL	JMP$ILPRT
	DB	'Bad entry',0
	RET			; just return if not valid entry
;
;
;  Set parity and word length.  If cr entered on command line
;  no changes are made to parity and SIO/DART is initialized
;  to present parity setting.
;
PARITY:	STA	MSPEED		; save new mspeed value
PRTY:	CALL	JMP$ILPRT
	DB	'Parity = ',0
	CALL	ODEVNO		; show current parity setting
	CALL	JMP$ILPRT
	DB	cr,lf,'Enter (O)dd,(E)ven,(M)ark,(N)one or cr ',0
	LXI	D,CBUFF		; point to command buffer
	CALL	JMP$INBUF	; get response
	INX	D		; number of char typed
	LDAX	D		; get number of char
	ORA	A		; set flags
	JZ	SETCTC		; no parity change so init CTC
	MVI	E,50H		; offset to wr4 it has parity
	CALL	GETBIOS
	MVI	A,0C4H		; mask for wr4, parity,stop bits,divisor
	ANA	M		; clear any present setting
	MOV	M,A		; and store to wr4 location
	LXI	D,CBUFF+2	; point to character typed
	LDAX	D		; get char
	CPI	'O'		; odd parity
	JZ	ODD
	CPI	'E'		; even parity
	JZ	EVEN		;
	CPI	'M'
	JZ	MARK		; mark parity
	CPI	'N'
	JNZ	PARITY		; if not 'N' get valid entry
;
;  No parity so restore everthing for 8 bit word length
;  with no parity.  Has wr4 location in 'HL'
;
NONE:	INX	H		; 
	INX	H		; point to wr5
	MVI	M,0EAH		; tx 8 bit char, tx enable, DTR/RTS enable
	MOV	A,M		; get the value if needed for exit to SAME:
	INX	H		;
	INX	H		; point to wr3
	MVI	M,0C1H		; rx 8 bit char, rx enable
;
	IF	RACAL
	JMP	SAME		; 'a'=wr5 command value
	ENDIF
;
	IF NOT	RACAL
	JMP	SETCTC
	ENDIF
;
;  The DART/SIO adds a parity bit to the word length set in wr3 and
;  wr5 when parity is enabled.  Will make for 9 bit data word if word
;  length is not set for 7 bits.  Entered with wr4 location in 'HL'
;
;  Set for Mark parity. When using a DART/SIO set for 7 bit word and
;  2 stop bits, this is equal to 7 bits with mark parity.
;
MARK:	MOV	A,M		; get wr4 value
	ORI	0CH		; or 2 stop bits value
	JMP	REST		; store and set to 7 bit word

;  Set for odd parity
;
ODD:	MOV	A,M		; get wr4 value
	ORI	01H		; set parity enable, odd parity
	JMP	REST		; rest is same as EVEN:
;
;  Set for even parity
;
EVEN:	MOV	A,M		; get wr4 value
	ORI	03H		; set parity enable, even parity
REST:	MOV	M,A		; store value
	INX	H
	INX	H		; point to wr5 location
	MOV	A,M		; get present value
	ANI	09FH		; mask off 8 bit word bit length
	ORI	20H		; or in 7 bit word
	MOV	M,A		; and store
	PUSH	PSW		; save 'a' for now
;
	INX	H
	INX	H		; point to wr3 location
	MOV	A,M		; get present value
	ANI	3FH		; mask off word length
	ORI	40H		; or in 7 bit word length
	MOV	M,A		; and store
	POP	PSW		; restore 'a' and set dtr mask
;
	IF 	RACAL
SAME:	STA	SETDTRH+6
	ANI	068H		; to mask off RTS/DTR bit
	STA	SETDTRL+6
	ENDIF
;
; Initialize CTC and SIO/DART B side
;
;  Initialize CTC according to mspeed setting
;
SETCTC:	MVI	E,3FH		; offset to port b ctc 3F hex bytes
	CALL	GETBIOS
	MVI	A,47H		; counter mode,CTC reset,value follows
	MOV	M,A		; store value
	PUSH	H		; save pointer
	CALL	LOOKUP
	MOV	A,M		; get ctc divisor
	POP	H
	INX	H		; location of ctc divisor
	MOV	M,A		; store new divisor
;
; Set up wr4 clock divisor according to mspeed
;
NOCTC:	MVI	E,50H		; offset to DART wr4
	CALL	GETBIOS
	MVI	A,3FH		; mask for wr4 clock bits
	ANA	M		; mask off bits
	MOV	M,A		; and save to wr4
	LDA	MSPEED		; get mspeed value
	DCR	A		; set flags, zero = 300 bps
	MVI	A,80H		; x32 clock bit
	JZ	LBPS		; setup wr4 for 300 bps x32 clock
;
;  Set up wr4 value for 1200 bps x16 clock 'HL' has wr4 loc
;
HBPS:	MVI	A,40H		; x16 clock
;
;  Setup wr4 value for 300 bps x32 clock 'HL' has wr4 loc
;
LBPS:	ORA	M		; set clock bits saving parity
	MOV	M,A		; store new clock divisor to wr4 value
;
;  Initialize SIO/DART
;
INTSIO:	LXI	H,SPDPAR
	PUSH	H		; set up for return
	MVI	E,36H		; offset to ioinit
	CALL	GETBIOS
	PCHL			; we pushed return address
;
;  Show interface speed and parity setting
;
SPDPAR:	CALL	JMP$ILPRT
	DB	'Dart set to ',0
	CALL	LOOKUP		; get table entry to print
	INX	H		; skip over ctc divisor
	CALL	PSTRING		; print message
	CALL	JMP$ILPRT
	DB	'00 bps, parity = ',0
;
;  figure and show current parity setting
;
ODEVNO:	MVI	E,50H		; offset to wr4
	CALL	GETBIOS
	MVI	A,08H		; test for 2 stop bits
	ANA	M
	JNZ	MPAR		; show mark parity
	MVI	A,03H
	ANA	M		; mask off all but parity
	LXI	H,SPAR		; parity table
	CALL	LKUP		; get table string
				; print message string and return
;
;
; Print table string pointed to by 'HL' using cp/m function 9,
; all strings terminated with '$'.
;
PSTRING:
	XCHG			; put string address in 'DE'
	MVI	C,9		; cp/m print string function
	JMP	5		; go bdos and return
;
MPAR:	LXI	H,MPMSG
	JMP	PSTRING
;
;  LOOKUP: returns correct table entry in 'HL' according to MSPEED:
;  value.
;  LKUP: Entered with lookup table in 'HL' and multiplier in 'A'
;  returns with correct table entry point in 'HL'.
;
LOOKUP:	LXI	H,BRATE		; for CTC divisor and baud rate string
	LDA	MSPEED		; get current mspeed value
	DCR	A		; 0 = 300 bps is first in tables
	JZ	LKUP		;
	SUI	3		; adjust for mspeed gap (1,5,6,7,8)
LKUP:	MVI	D,0		; clear d
	MOV	E,A
	ADD	A		; x2
	ADD	A		; x4
	ADD	E		; x5
	MOV	E,A		; table offset in 'E'
	DAD	D		; add to 'HL'
	RET
;
;  Return bios location in 'hl' called with offset in 'e'
;
GETBIOS:
	LHLD	1		; get bios location
	MVI	D,0		; clear 'd'
	DAD	D
	RET
;
;  Send .5 second break uses SIO WR5 send break bit 4
;
SENDBRK:
	MVI	E,52H		; offset to wr5 command
	CALL	GETBIOS
	MVI	A,05H		; select wr5
	OUT	MODCTL1
	MOV	A,M		; get present value
	PUSH	PSW		; save current command
	ORI	10H		; set break bit on 
	OUT	MODCTL1
	PUSH	B		; just in case
	MVI	B,5		; 5 times .1 sec = .5 sec.
	CALL	JMP$TIMER
	POP	B
	MVI	A,05H		; select WR 5
	OUT	MODCTL1
	POP	PSW		; restore old wr5
	OUT	MODCTL1		; send out and return
	RET
;
;  *** All tables are 5 bytes in length ***
;
;  Table for parity 
SPAR:	DB	'none$'		; parity bits = 0
	DB	'odd$',0	; parity bits = 1
MPMSG:	DB	'mark$'		; mark parity
	DB	'even$'		; parity bits = 3
;
;  Speed table for CTC divisor and to show interface settings.
;  first entry is CTC divisor
;
BRATE:	DB	CT300,'3$',0,0		;  300 baud mspeed =1
	DB	CT1200,'12$',0		; 1200 baud        =5
	DB	CT2400,'24$',0		; 2400 baud        =6
	DB	CT4800,'48$',0		; 4800 baud        =7
	DB	CT9600,'96$',0		; 9600 baud        =8
;
; local command buffer
;
CBUFF:	DB	4,0,0,0,0,0
;
;  NOTE: Any additions must terminate before 400h if using with Hayes
;        type modem or 500h if using Racal-Vadic modem
;
OVLEND:	EQU	$		; end of overlay
;
; --------------------------------------------------------------------
;  This overlays SETDTRH: and SETDTRL: for M7RV@6.ASM if using the
;  Racal-Vadic VA212PA autodial modem.  The AMPRO "little board" 
;  uses RTS instead of DTR.
;
	IF	RACAL
	ORG	500H		; Puts in right place for racal overlay
;
;  Raise RTS to enable modem (11 bytes long for M7RV@6.ASM)
;
SETDTRH:
	MVI	A,05H		; raise again to enable dialing
	CALL	OUT$MODCTL1
	MVI	A,0EAH		; restore DTR/RTS 
	JMP	OUT$MODCTL1
	DB	0		; make it 11 bytes
;
; Drop RTS to disable modem (10 bytes long for M7RV@6.ASM)
; 
SETDTRL:
	MVI	A,05H		; select SIO WR5
	CALL	OUT$MODCTL1
	MVI	A,68H		; and set the DTR/RTS line low
	JMP	OUT$MODCTL1
;
	ENDIF
;
	END
