  
;*************************************
;*                                   *
;*            "AUTOMODD"             *
;*                                   *
;*      LEE SWORDY   14/5/82         *
;*                                   *
;* Revision 1.1 by Jim Woolley,	FOG  *
;* Disk Librarian, 8/82.             *
;*                                   *
;* Modified for double density 2/2/83*
;* By Mike Schwab, Denver Osborne    *
;* Librarian.                        *
;*************************************
;
AUXBUF	EQU 201DH	; CP/M AUX CMND BFR ST ADR (BYTE CNT = 1st)
;
	ORG 100H
	JMP START
;
MSG1	DB 1AH,'              AUTOMOD   REV. 1.1',0DH,0AH
	DB '  PROGRAM TO INSERT A USER SELECTABLE COMMAND LINE',0DH,0AH
	DB 'INTO CP/M ON DISK, TO BE EXECUTED ON ALL COLD STARTS',0DH,0AH,0AH
	DB '           FOR OSBORNE CP/M 2.2A-00F',0DH,0AH,0AH,0AH
	DB 'ENTER CP/M SOURCE DRIVE (A or B):   ?',8,8,8,'$'
MSG2	DB 0DH,0AH,0AH,'ENTER COMMAND LINE TO BE INSERTED,',0DH,0AH
	DB '(36 CHARACTERS MAXIMUM) OR <RETURN> FOR NO COMMAND.',0DH,0AH,0AH
;
	db 'If COMMAND LINE has N characters, where N > 6,',0dh,0ah
	db 'first use SETUP.COM to establish (N - 6) dummy',0dh,0ah
	db 'characters in FUNCTION KEY 0 (zero).  This will',0dh,0ah
	db 'avoid disastrous overlay of FUNCTION and ARROW',0dh,0ah
	db 'KEY information but, also, will render FUNCTION',0dh,0ah
	db 'KEY 0 unusable.',0dh,0ah,0ah
;
	DB '   COMMAND ?: $'
MSG3	DB 0DH,0AH,0AH,0AH,'**** COMMAND INSERTION COMPLETE ****',0DH,0AH,0AH
	DB '$'
;
;**** PRINT HEADER AND REQUEST DRIVE ID
START	LXI SP,STACK	; LOCAL STACK
;
	MVI C,9
	LXI D,MSG1	; HEADER MSG/DRIVE ID REQ TO CONS
	CALL 0005
;
RETRY1	MVI C,1		; INPUT 'DRIVE ID'
	CALL 0005
	CPI 03		; ^C ?
	JZ EXIT		; YES: ABORT
	CPI 60H
	JM UPPER
	SUI 20H		; MAKE UPPER CASE
UPPER	SUI 41H		; CONV A or B TO 0 or 1
	JM CHERROR	; IF NOT 0 or 1
	CPI 2
	JM DRIVEOK
;
CHERROR	MVI C,9
	LXI D,ERR1	; 'WRONG' MSG TO CONS
	CALL 0005
	JMP RETRY1
;
DRIVEOK	MOV C,A
	PUSH B		; SAVE DRIVE #
;
;**** MOVE PART OF BIOS VECTOR TABLE INTO LOCAL CORE FOR CALLS
	LHLD 0001	; GET WARM ST VCTR ADRS
	LXI D,24	; INDEX INTO VCTR TBLE
	DAD D		; HL + INDEX = SOURCE
	LXI D,VECTBL	; DESTINATION
	LXI B,18	; BYTE COUNT (6 JUMP INSTR'S)
	DB 0EDH,0B0H	; Z80 'LDIR' INST (BLOCK MOVE)
;
;**** GET 'SECTORS PER TRACK' FROM 'DISK PARAM BLOCK'
	POP B		; GET DRIVE #
	CALL SELDSK	; SELECT DISK DRIVE
;
	LXI D,10	; INDEX INTO DP HEADER
	DAD D		; +DPH BASE ADRS
;
	MOV E,M
	INX H
	MOV D,M		; GET DPB ADRS
;
	XCHG
;
	MOV E,M
	INX H
	MOV D,M		; GET 'SPT'
;
	MOV A,E
	DCR A		; -1
	STA SPT		; SAVE SECTRS/TRACK
;
;**** READ CP/M FROM DISK INTO CORE STARTING AT 980H (NO BOOT LOADER)
	MVI A,0	
	STA FLAG	; RD/WRT FLAG TO READ (0)
	CALL RDWRT	; DISK READ/WRITE ROUTINE
;
;**** CHECK IF CP/M IS VALID (1st BYTE OK ?)
	LDA 980H	; GET BYTE 1 OF CPM
	CPI 0C3H	; SHOULD BE 'JMP' OP CODE
	JZ REQUEST	; YES: CPM OK
;
	MVI C,9
	LXI D,ERR3	; 'CPM BAD' MSG TO CONS
	CALL 0005
	JMP EXIT
;
;**** REQUEST COMMAND STRING AND INPUT THE STRING
REQUEST	MVI C,9
	LXI D,MSG2	; 'CMND REQ' MSG TO CONS
	CALL 0005
;
	MVI C,10
	LXI D,INBUFF	; INPUT 'CMND STRING'
	CALL 0005
;
;**** TRANSFER 'CMND STRING' FROM IP BUFF TO AUX CMND BUFF
	LDA INBUFF+1	; GET INPUT BYTE CNT
	ADI 2		; +2 FOR CCP
	STA AUXBUF	; SAVE AS AUX CMD BFR BYTE CNT
	SUI 2		; = 0 ?
	JNZ JUMP1	; NO
	STA AUXBUF	; YES: MAKE AUX BYTE CNT = 0
	JMP JUMP4
;
JUMP1	MOV C,A		; BYTE CNT
	LXI D,AUXBUF+1	; DESTINATION
	LXI H,INBUFF+2	; SOURCE
LOOP1	MOV A,M		; GET A SOURCE BYTE
	CPI 60H		; MAKE UPPER CASE
	JM JUMP5
	SUI 20H
;
JUMP5	STAX D		; BYTE TO DEST.
	INX D		; DEST. + 1
	INX H		; SOURCE + 1
	DCR C		; BYTE CNT - 1
	JNZ LOOP1	; IF NOT DONE
;
	XRA A		; A = 0
	STAX D		; LINE TERMINATOR
;
;**** WRITE CP/M BACK TO SOURCE DISK
JUMP4	MVI A,01	; RD/WRT FLAG TO WRITE
	STA FLAG
	CALL RDWRT	; DISK READ/WRITE ROUTINE
;
	MVI C,9
	LXI D,MSG3	; 'ALL DONE' MESSAGE
	CALL 0005
;
EXIT	JMP 0000	; CPM WARM ST ENTRY
;
;******* READ/WRITE CPM TO/FROM DISK SUBROUTINE:
;	 'FLAG' = 0 FOR READ, = 1 FOR WRITE
;
RDWRT	LXI H,0		; INIT SECTOR = 0
	SHLD SECTOR
	LXI H,0		; INIT TRACK = 0
	SHLD TRACK
	LXI H,980H	; INIT DMA ADRS = 980H
	SHLD DMAADR
;
LOOP2	LHLD DMAADR
	MOV B,H
	MOV C,L
	CALL SETDMA	; SET DMA ADRS
;
	LHLD TRACK
	MOV B,H
	MOV C,L
	CALL SETTRK	; SET TRACK #
;
	LHLD SECTOR
	MOV B,H
	MOV C,L
	CALL SETSEC	; SET SECTOR #
;
	LDA FLAG	; READ ? (=0)
	ORA A
	JNZ DSKWRT	; NO: WRITE
;
	CALL READ	; READ A RECORD
	ORA A		; READ ERROR ?
	JZ GOODRD	; NO
;
	MVI C,9
	LXI D,ERR2	; 'SOURCE READ' ERR MSG TO CONS
	CALL 0005
	JMP EXIT
;
DSKWRT	CALL WRITE	; WRITE A RECORD
	ORA A		; WRITE ERROR ?
	JZ GOODRD	; NO
;
	MVI C,9
	LXI D,ERR4	; 'DEST WRITE' ERR MSG TO CONS
	CALL 0005
	JMP EXIT
;
GOODRD	LDA SPT
	LHLD SECTOR
	CMP L		; END OF TRACK ?
	JNZ JUMP3	; NO
;
	LHLD TRACK
	INX H
	SHLD TRACK	; TRACK # +1
;
	LXI H,0FFFFH	; SECTOR # = -1
JUMP3	INX H		; +1
	SHLD SECTOR	; RE-SAVE SECTOR #
;
	LHLD DMAADR	; DMA ADRS + 128
	LXI D,128
	DAD D
	LXI D,2780H	; END OF CPM ?
	MOV A,D
	CMP H
	JNZ NOTEND	; NO
	MOV A,E
	CMP L
	JZ ENDCPM
;
NOTEND	SHLD DMAADR
	JMP LOOP2	; DO NEXT SECTOR
ENDCPM	RET
;
;**** BUFFERS, STORAGE AND MESSAGES:
;
VECTBL			; PORTION OF BIOS VECTOR TABLE
SELDSK	DS 3
SETTRK	DS 3
SETSEC	DS 3
SETDMA	DS 3
READ	DS 3
WRITE	DS 3
;
SPT	DB 0		; 'SECTORS PER TRACK -1'
FLAG	DB 0		; CPM RD/WRT FLAG;
;
SECTOR	DW 0
TRACK	DW 0
DMAADR	DW 0
;
INBUFF	DB 36,0
	DS 36
;
ERR1	DB 12,12,12,'WRONG!',8,8,8,8,8,8,8,8,8,8,'$'
ERR2	DB 0DH,0AH,0AH,1BH,6CH,'DISK READ ERROR',1BH,6DH,0DH,0AH,'$'
ERR3	DB 0DH,0AH,0AH,1BH,6CH,'ERROR: CP/M NOT PRESENT ON SOURCE'
	DB ' DISK',1BH,6DH,0DH,0AH,'$'
ERR4	DB 0DH,0AH,0AH,1BH,6CH,'DISK WRITE ERROR',1BH,6DH,0DH,0AH,'$'
;
	DS 64
STACK
	END

