;===============================================================;
;								;
;	MBOOT86.A86 Ver 1.00					;
;	(preliminary release 11/08/83)				;
;								;
;	This program accepts a file that comes in over		;
;	an IBM ASYNC adapter board, port-0.			;
;								;
;                       **** BEWARE ****			;
;	This codes is a 2 hour attempt at converting MBOOT	;
;	from CP/M-80,8080 code TO CP/M-86,8086 code.  It is	;
;	not an exact translation!!  Like MBOOT, is does have	;
;	a terminal mode and will receive a file used the 	;
;	MODEM/XMODEM protocol.					;
;								;
;	CREDITS							;
;	  MODEM BOOT(MBOOT)   - Keith Petersen W8SDZ		;
;	  Terminal routine    - John Taylor			;
;	  Based on MODEM.ASM  - Ward Christensen		;
;	  MBOOT86 for CP/M-86 - Daniel Deward			;
;								;
;	FOR THE CP/M-86 OPERATING SYSTEM			;
;		To generate a .CMD file,			;
;	A>asm86 mboot86						;
;	A>gencmd mboot86					;
;								;
;===============================================================;
;
;	BDOS FUNCTION NUMBERS
;
CONINP	EQU	1		;CONSOLE INPUT
CONOUT	EQU	2		;CONSOLE OUTPUT
CSTAT	EQU	11		;GET CONSOLE STATUS
;
;	ASCII CONTROL CHARACTER EQUATES
;
SOH	EQU	01H		;START OF HEADER
EOT	EQU	04H		;END OF TRANSMISSION
CR	EQU	0DH		;CARRIAGE RETURN
LF	EQU	0AH		;LINE FEED
ESC	EQU	1BH		;ESCAPE
ACK	EQU	06H		;ACKNOWLEDGE
NAK	EQU	15H		;NEGATIVE ACK
CAN	EQU	18H		;CANCEL TRANSMISSION
;
ERRLIM	EQU	10		
EXITKEY	EQU	03H		;CONTROL-C
;
;	I/O PORT ASSIGNMENTS
;
MODDATP	EQU	03F8H		;MODEM DATA PORT
MODCTLP	EQU	03FDH		;MODEM CONTROL PORT
;
;
	CSEG
	CLI				;DISABLE INTERRUPTS
	MOV	DX,OFFSET MSG1		;LOGON
	CALL	PSTRING
;
	MOV	AL,FCB+1		;CHECK FOR FILE ON COMMAND LINE
	CMP	AL,' '
	JNZ	TERMI
;
	MOV	DX,OFFSET MSG2		;NO FILE NAME SPECIFIED
	CALL	PSTRING
	JMP	EXIT
;
TERMI:
	MOV	DX,MODDATP
	IN	AL,DX			;GOBBLE UP GARBAGE
	IN	AL,DX
;
	MOV	DX,OFFSET MSG3		;TERMINAL MODE
	CALL	PSTRING
;
TMODE:
	CALL	STAT		;GET KEYBOARD STATUS
	JZ	TERML		;NO CHAR READY
	CALL	KEYIN		;ESLE GET CHAR
	CMP	AL,EXITKEY	;TEST FOR EXIT
	JNZ	KEYOK
	JMP	EXIT
;
KEYOK:
	CMP	AL,ESC		;START FILE XFER ?
	JZ	RCVFIL
;
	MOV	DX,MODDATP
	OUT	DX,AL
;
TERML:
	MOV	DX,MODCTLP	;GET MODEM STATUS 
	IN	AL,DX
	TEST	AL,01H
	JZ	TMODE		;NO CHAR YET
	MOV	DX,MODDATP	;GET MODEM DATA
	IN	AL,DX
	CALL	COUT
	JMP	TMODE
;
RCVFIL:
	CALL	MAKEFIL
	MOV	DX,OFFSET MSG4	;FILE OPEN READY TO RECEIVE
	CALL	PSTRING
;
RCVLP:
	CALL	RCVSECT			;GET SECTOR
	JC	RCVEOT			;IF END OF TRANSFER
	CALL	WRSECT			;WRITE SECTOR
	CALL	INCRSNO			;ADVANCE SECTOR #
	CALL	SENDACK			;ACK RECORD
	JMP	RCVLP			;CONTINUE TILL EOT
;
RCVEOT:
	CALL	WRBLOCK			;WRITE OUT LAST BUFFER
	CALL	SENDACK			;SEND ACK
	CALL	CLOSEFIL		;CLOSE THE FILE
;
	MOV	DX,OFFSET MSG5		;TRANSFER COMPLETE
	CALL	PSTRING
	JMP	EXIT
;
; SUBROUTINE RCVSECT
;
RCVSECT:
	XOR	AL,AL
	MOV	ERRCT,AL	;RESET ERROR COUNT
;
RCVRPT:
	MOV	CH,10		;SET RETRY COUNT TO 10
	CALL	RECV
	JC	RCVSERR
	CMP	AL,SOH		;START OF HEADER
	JZ	RCVSOH		;GET IT
	OR	AL,AL
	JZ	RCVRPT
	CMP	AL,EOT		;END OF TRANSMISSION
	STC			;INDICATE EOT
	JNZ	RCVSERR
	JMP	DORET		;YES, END OF TRANSMISSION
;
RCVSERR:
	MOV	CH,1
	CALL	RECV
	JNC	RCVSERR
;
	MOV	AL,NAK		;NAK THE BAD FRAME
	CALL	SEND
	MOV	AL,ERRCT
	INC	AL
	MOV	ERRCT,AL	;SAVE IT BACK
;
	CMP	AL,ERRLIM		;ERROR LIMIT REACHED ?
	JC	RCVRPT
;
; ABORT THE RECEIVE
;
RCVSABT:
	CALL	CLOSEFIL		;SAVE WHATEVER WE GOT
	MOV	DX,OFFSET MSG6		;UNABLE TO RECEIVE BLOCK
	CALL	PSTRING
	JMP	EXIT
;
RCVSOH:
	MOV	CH,1			;TIME OUT = 1 MSEC
	CALL	RECV			;GET A CHAR
	JC	RCVSERR
;
	MOV	DL,AL
	MOV	CH,1
	CALL	RECV
	JC	RCVSERR
;
	NOT	AL
	CMP	AL,DL
	JZ	RCVDATA
	JMP	RCVSERR
;
RCVDATA:
	MOV	AL,DL
	MOV	RCVSNO,AL
	MOV	CL,0
	MOV	DI,80H
;
RCVCHR:
	MOV	CH,1			;TIME OUT OF 1 MSEC
	CALL	RECV
	JC	RCVSERR
;
	MOV	BYTE PTR[DI],AL		;SAVE THE CHARACTER
	INC	DI			;ADVANCE POINTER
	CMP	DI,0100H		;END OF BUFFER ?
	JNZ	RCVCHR			;CONTINUE UNTIL BUFFER FULL
;
	MOV	DL,CL		;SAVE CHECK SUM
	MOV	CH,1		;SET TIME OUT TO 1 MSEC
	CALL	RECV
	JC	RCVSERR
	CMP	AL,DL
	JNZ	RCVSERR
;
	MOV	AL,RCVSNO
	MOV	BL,AL
	MOV	AL,SECTNO
	CMP	BL,AL
	JZ	RECVACK
	INC	AL
	CMP	BL,AL
	JZ	RCV0
	JMP	EXIT
;
RCV0:	RET
;
;
RECVACK:
	CALL	SENDACK
	JMP	RCVSECT
;
SENDACK:
	MOV	AL,ACK
SEND:	PUSH	AX		;SAVE OUTPUT CHAR
	ADD	AL,CL
	MOV	CL,AL
;
SENDW:	MOV	DX,MODCTLP
	IN	AL,DX
	TEST	AL,20H
	JZ	SENDW
	POP	AX		;RESTORE OUTPUT CHAR
	MOV	DX,MODDATP
	OUT	DX,AL
	RET
;
INCRSNO:
	MOV	AL,SECTNO
	INC	AL
	MOV	SECTNO,AL
	RET
;
MAKEFIL:
	MOV	DX,OFFSET FCB
	MOV	CL,22
	CALL	BDOS
	INC	AL
	JZ	DIRFULL
	JMP	DORET
;
DIRFULL:
	MOV	DX,OFFSET MSG8
	CALL	PSTRING		;DIRCETORY FULL
	JMP	EXIT
;
CLOSEFIL:
	MOV	DX,OFFSET FCB
	MOV	CL,16
	CALL	BDOS
	INC	AL
	JZ	NOCLOSE
	JMP	DORET
;
NOCLOSE:
	MOV	DX,OFFSET MSG9		;CAN'T CLOSE FILE
	CALL	PSTRING
	JMP	EXIT
;
WRSECT:
	MOV	DI,SECPTR
	MOV	SI,80H
	CALL	MOVE128			;COPY TO DISK BUFFER
	MOV	SECPTR,DI		;SAVE NEW POINTER
;
	MOV	AL,SECINBF
	INC	AL
	MOV	SECINBF,AL
	CMP	AL,16
	JZ	WRBLOCK
	JMP	DORET
;
;	OUTPUT BUFFER TO DISK
;
WRBLOCK:
	MOV	AL,SECINBF		;GET SECTOR COUNTER
	OR	AL,AL
	JNZ	WR0
	JMP	DORET
;
WR0:
	MOV	CL,AL			;CL = WRITE COUNTER
	MOV	DX,OFFSET DBUF
;
DKWRLP:
	PUSH	DX
	PUSH	BX
	PUSH	CX		;SAVE REGISTERS
;
	MOV	CL,26
	CALL	BDOS
;
	STI			;ENABLE INTERRUPTS
	MOV	DX,OFFSET FCB
	MOV	CL,21
	CALL	BDOS
	CLI			;DISABLE INTERRUPTS
;
	POP	CX
	POP	BX
	POP	DX
	OR	AL,AL		;TEST DISK WRITE STATUS
	JNZ	WRERR		;DISK WRITE ERROR
;
	ADD	DX,80H		;ADVANCE DMA POINTER
	DEC	CL
	JNZ	DKWRLP		;CONTINUE WRITTING
;
	MOV	SECINBF,0
	MOV	DX,OFFSET DBUF
	MOV	SECPTR,DX
;
RSDMA:	MOV	DX,80H
	MOV	CL,26
	CALL	BDOS
	RET
;
WRERR:	CALL	RSDMA
	MOV	DX,OFFSET MSG10
	CALL	PSTRING		;ERROR IN WRITTING FILE
	JMP	EXIT
;
;	RECV
;	UPON ENTRY
;		CH = # OF MSEC BEFORE TIME OUT
;
;	UPON EXIT
;		CL = UPDATED CHECKSUM
;
RECV:
	PUSH	DX
	PUSH	BX
MSEC:	MOV	BX,50000
MWTI:	MOV	DX,MODCTLP
	IN	AL,DX
	TEST	AL,01H
	JNZ	MCHAR
	DEC	BL
	JNZ	MWTI
	DEC	BH
	JNZ	MWTI
	DEC	CH
	JNZ	MSEC
	POP	BX
	POP	DX
	STC
	RET
;
MCHAR:	MOV	DX,MODDATP
	IN	AL,DX
	ADD	CL,AL		;UPDATE CHECKSUM
	OR	AL,AL
	POP	BX
	POP	DX
	RET
;
MOVE128:
	PUSH	BX
	MOV	BL,128
MOVE:	MOV	AL,BYTE PTR [SI]
	MOV	BYTE PTR [DI],AL
	INC	SI
	INC	DI
	DEC	BL
	JNZ	MOVE
	POP	BX
	RET
;
EXIT:
	STI
	MOV	CL,0
	CALL	BDOS
;
PSTRING:
	MOV	CL,9
	CALL	BDOS
	RET
;
KEYIN:
	PUSH	BX
	PUSH	DX
	MOV	CL,CONINP
	CALL	BDOS
	POP	DX
	POP	BX
	RET
;
COUT:
	PUSH	BX
	PUSH	DX
	MOV	DL,AL
	MOV	CL,CONOUT
	CALL	BDOS
	POP	DX
	POP	BX
	RET
;
STAT:
	PUSH	BX
	PUSH	DX
	MOV	CL,CSTAT
	CALL	BDOS
	OR	AL,AL
	POP	DX
	POP	BX
	RET
;
DORET:	RET
;
BDOS:
	INT	224
	RET
;
;	DATA AREA
;
	DSEG
	ORG	5CH
FCB	RB	35		;FILE CONTROL BLOCK
BUFF	RB	128		;DISK WRITE BUFFER
;
	DW	0		;ALIGN TO WORD BOUNDARY
;
RCVSNO	DB	0		;RECEIVED SECTOR NUMBER
SECTNO	DB	0		;CURRENT SECTOR NUMBER
ERRCT	DB	0		;ERROR COUNT
SECPTR	DW	DBUF		;DISK BUFFER POINTER
SECINBF	DB	0		;# OF SECTORS IN DISK BUFFER
;
DBUF	RS	4096		;DISK BUFFER
	DW	0
;
;	MESSAGES
;
MSG1	DB	CR,LF,'MBOOT FOR THE IBM-PC',CR,LF
	DB	'Version 1.00',CR,LF,'$'

MSG2	DB	CR,LF,'No file name specified',CR,LF,'$'

MSG3	DB	CR,LF,'Terminal mode',CR,LF,LF,'$'

MSG4	DB	CR,LF,'File open, ready to receive',CR,LF,'$'

MSG5	DB	CR,LF,'Transfer complete',CR,LF,'$'

MSG6	DB	CR,LF,'Unable to receive block',CR,LF,'$'

MSG8	DB	CR,LF,'Directory full',CR,LF,'$'

MSG9	DB	CR,LF,'Cannot close file',CR,LF,'$'

MSG10	DB	CR,LF,'Error in writting file',CR,LF,'$'
;
	END