;XM82OSCP.ASM - XMODEMxx PATCH FILE FOR Osborne MODEM  01/16/84
;
; This is adapted from Irv Hoff's XMEX-1.ASM dated 11/17/83
;
;		by John Riehl 1-713-644-7070 days
;			      1-713-488-1257 evenings	
;
; This file adapts XMODEMxx to the Osborne 01 with the
; Osborne COMM-PAC modem. To use, first edit any options desired into
; XMODEMxx.ASM, then assemble (can use ASM.COM) and load which supplies
; XMODEMxx.COM.  Then edit this file as needed (check the CONOUT routine
; if you want to locally see file transfer time and the record count
; while programs are being sent).  Then assemble (can use ASM.COM) and
; merge via DDT or SID:
;
;	B>DDT XMODEMxx.COM
;	DDT VERS 2.2
;	NEXT  PC
;	1180 0100
;	-IXM82OSCP.HEX		(note the 'I' command)
;	-R			('R' loads in the .HEX file)
;	NEXT  PC
;	1180 0000
;	-G0			(return to CP/M)
;	B>SAVE 17 XMODEMxx.COM  (now have a modified .COM file)
;
; NOTE: Save 22 (rather than 17) if LOGCAL is YES
;
;=======================================================================
;
; 01/16/84 - Original version adapted from XMEX-1.ASM by Irv Hoff
;					John Riehl	
;
;=======================================================================
; 
YES:	EQU	0FFH
NO:	EQU	0
;
;=======================================================================
;
; The following options must be set as shown in XMODEM82:
;
; LARGEIO:	EQU	YES
; LARSIZE:	EQU	0B0H
;
; USECON:	EQU	NO	;if you are using this XMODEM with BYE3
;
; Only one of the following can be yes and the others no
;
BIOS13:	EQU	NO	;yes = Osborne uses BIOS 1.3
BIOS14: EQU	YES	;yes = Osborne uses BIOS 1.4 or 1.41
BIOS144:EQU	NO	;yes = Osborne uses BIOS 1.44+ 
			;      (Nuevos Electronics 80 column mod.)
;
; If you have none of the above you have to use DDT to find out
; where the 5th JMP instruction in your BIOS jumps to and use it
; for the JMP at 103H. Set all three equates above to NO
;
;=======================================================================
;
MODDATP: EQU	2A01H		;data in port
MODDATO: EQU	MODDATP		;data out port
MODCTLP: EQU	MODDATP-1	;control/status port
MODSNDB: EQU	2		;bit to test for send
MODSNDR: EQU	2		;value when ready
MODRCVB: EQU	1		;bit to test for receive
MODRCVR: EQU	1		;value when ready
MODDCDB: EQU	4		;carrier detect bit
MODDCDA: EQU	4		;value when active
MODPARE: EQU	40H		;value for parity error
MODOVRE: EQU	10H		;value for overrun error
MODFRME: EQU	20H		;value for framing error
;

LSPEED:	EQU	YES		;yes if using 'BYE' with speed selection
				;no if using 'SPEED' manual selection
MSPEED:	EQU	3CH		;location of baud rate factor (set by
				;'BYE')  set location in 'BYE' to agree.
				;3dh and 3eh often used by newer ver-
				;sions of 'ZCPR'.
XSPEED:	EQU	1		;speed for file time transfer without
				;auto-set.  use one of the following:
				;0=110 1=300 2=450 3=600 4=710 5=1200
BASE:	EQU	100H		;start of cp/m normal program area
;
;-------------------------------------------------------------------
;
; Jump table: The jump table must be in exactly the same sequence as the
; one in XMODEM.  Note the ORG of 103H - This jump table has no jump to
; 'BEGIN'.
;
;
	 ORG	BASE+3		;start after 'JMP BEGIN'
;
CONOUT:	  IF	BIOS13
	 JMP	0E915H		;BIOS 1.3 console output routine
	  ENDIF			;BIOS13
;
	  IF	BIOS14
	 JMP	0E738CH		;BIOS 1.4 console output routine
	  ENDIF			;BIOS14
;
	  IF	BIOS144		;BIOS 1.44+ console output routine
	 JMP	0E749H
	  ENDIF			;BIOS144
;
	  IF (NOT BIOS13) AND (NOT BIOS14) AND (NOT BIOS144)
	 JMP	0000H		;put your BIOS console out jump address here
	  ENDIF		;(NOT BIOS13) AND (NOT BIOS14) AND (NOT BIOS144)
;
;
PMINIT:	 JMP	MINIT		;initialization routine (if needed)
PUNINIT: RET ! NOP ! NOP	;not required
PSENDR:	 JMP	SENDR		;send character (via pop psw)
PCAROK:	 JMP	CAROK		;test for carrier
PMDIN:	 JMP	MDIN		;receive data byte
PGETCHR: JMP	GETCHR		;get character from modem
PRCVRDY: JMP	RCVRDY		;check receive ready
PSNDRDY: JMP	SNDRDY		;check send ready
PSPEED:	 JMP	SPEED		;get speed value for file transfer time
POSTAT:  JMP	OSTAT		;get I/O status
PEXTRA1: RET ! NOP ! NOP	;extra for custom routine
PEXTRA2: RET ! NOP ! NOP	;extra for custom routine
;
;=======================================================================
;
; ---> CAROK - check for presence of carrier.  RET with Z = carrier on
;
CAROK:	CALL	POSTAT		;get status
	ANI	MODDCDB		;get carrier detect bit
	PUSH	PSW
	CNZ	MDIN
	POP	PSW
	RET
;
;=======================================================================
;
; ---> GETCHR - - initialize if not already done, then get character
; ---> MDIN - - get a character
;
GETCHR:	CALL	MINIT
MDIN:	JMP	OSIN		;get character from data in port
;
;=======================================================================
;
; This is the Osborne initialization routine which is required
; to relocate the memory mapped above 4000H.
;
INITFLG:  DB	0		;initialization flag
;	
MINIT:	  LDA	INITFLG		;have we been here before?
	  ORA	A
	  RNZ			;if yes, exit
	  INR	A
	  STA	INITFLG
	  PUSH	B
	  PUSH	D
	  PUSH	H
	  LXI	H,OSIN		;get address of first byte to move
	  LXI	D,0A000H	;get place to put first byte
	  LXI	B,RCVRDY-OSIN	;get length of code to move
	  DB	0EDH,0B0H	;Z80 LDIR
;
	  LXI	H,0A000H	;get new address of OSIN
	  SHLD	MDIN+1		;PATCH CALL FOR "GET CHAR." ROUTINE
	  LXI	H,0A000H+OSOUT-OSIN
	  SHLD	SENDR+2		;PATCH CALL FOR "SEND CHAR." ROUTINE
	  LXI	H,0A000H+OSTAT-OSIN
	  SHLD	POSTAT+1	;PATCH CALL FOR "GET STATUS" ROUTINE
	  POP	H
	  POP	D
	  POP	B
	  RET
;
;
; --- Routines that get placed just under 'BYE' ---
;
OSIN:	DI			;DISABLE INTERRUPTS
	OUT	0		;SWITCH TO ALTERNATE PAGE
	LDA	MODDATP		;GET DATA BYTE
	OUT	1		;SWITCH PAGES BACK
	EI			;RE-ENABLE INTERRUPTS
	RET
;.....
;
;
OSOUT:	DI			;DISABLE INTERRUPTS
	OUT	0		;SWITDH TO ALTERNATE PAGE
	STA	MODDATO		;SEND DATA BYTE
	OUT	1		;SWITCH PAGES BACK
	EI			;RE-ENABLE INTERRUPTS
	RET
;.....
;
;
OSTAT:	DI			;DISABLE INTERRUPTS
	OUT	0		;SWITCH TO ALTERNATE PAGE
	LDA	MODCTLP		;GET STATUS BYTE
	OUT	1		;SWITCH PAGES BACK
	EI			;RE-ENABLE INTERRUPTS
	RET
;
;
;=======================================================================
;
; ---> RCVRDY - check receive ready.  RET with Z = character available.
;	        Return with error code in A-reg.
;
RCVRDY:	CALL	POSTAT		;get modem status
	PUSH	B		;save scratch register
	PUSH	PSW		;check error status
	ANI	MODFRME+MODOVRE
	MOV	B,A		;save it for a moment
	POP	PSW
	ANI	MODRCVB		;isolate ready bit
	CPI	MODRCVR		;test it
	MOV	A,B		;get the error code char. back
	POP	B
	RET
;
;=======================================================================
;
; ---> SENDR - send character
;
SENDR:	POP	PSW		;get the character back
	JMP	OSOUT		;send it to the modem output
;
;=======================================================================
;
; ---> SNDRDY - check if ready to send.
;
SNDRDY:	CALL	POSTAT		;get status byte
	ANI	MODSNDB		;isolate ready bit
	CPI	MODSNDR		;ready to send?
	RET
;
;=======================================================================
;
; ---> SPEED - sets the time shown for program transfer.
;
SPEED:	 IF	LSPEED
	LDA	MSPEED		;get index for baud rate from 'BYE'
	 ENDIF
;
	 IF 	NOT LSPEED
	MVI	A,XSPEED	;get index for baud rate from 'XSPEED'
	 ENDIF
;
	RET
;
;=======================================================================
;
	END
