;	title	'(SB80GEN) - generic sysgen for sb/80'

;	see code immediately following spec block for system dependent area

;****************************************************************
;*
;* module name = sysgen
;* descriptive name = generic sysgen for sb/80
;* copyright (c) = 1981, lifeboat associates inc.
;* author =
;* date written =
;*
;* change activity =
;*    3/27/82 mlg ny:  make ncr version
;*     3/4/82 mlg ny:  make lexitron version
;*   11/09/81 mlr ny:  use full 1000h (32 sctrs) of cli
;*   10/11/81 mlr ny:  change mem addr to start at 1000h instead
;*			 of 900h; general addrs are:
;*			   1000h - boot
;*			   1100h - cli
;*			   2100h - dos
;*			   3500h - bios
;*		       - add file copy for system.cli
;*   08/11/81 mlr ny:  setup for Tarbel DD controller for sb/80
;*
;*   release = R1.2
;*   date = 09/nov/81
;*
;* environment =
;*   processor = mac (dig. rsrch)
;*
;****************************************************************
;
	PAGE
;
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>								>
;>		SYSTEM DEPENDENT MSGS, EQUATES AND DATA		>
;>								>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

	org	100h
	jmp	sysgen

vers	equ	12

CLINS:	DB	32	; # of cli sectors (in <system.cli> file);
			;   enough room for 32 sectors max

somsg:
	db	'SYSGEN Version '
	db	vers/10+'0','.',vers mod 10+'0'
	db	cr,lf
	db	'Copyright (c) 1982, Lifeboat Associates'
	db	cr,lf
	db	'for NCR 9010.'
	db	cr,lf,'$'


;
;****************************************************************
;*								*
;*		SB/80 SYSTEM DEFINITION EQUATES			*
;*								*
;****************************************************************
;
BOOTIM	EQU	1000H		; location of boot in sysgen image
CLIIM	EQU	1100H		; location of cli in sysgen image
DOSIM	EQU	2100H		; location of sb/80 dos in sysgen image
BOOTSIZ	EQU	100H		; BOOT SIZE
BIOSSIZ	EQU	1900H		; BIOS SIZE
DOSSIZ	EQU	1400H
CLISIZ	EQU	1000H
BIOSIM	EQU	03500H		; (loadadr is added) 

SYSGSZ	EQU	BOOTSIZ+BIOSSIZ+DOSSIZ+CLISIZ


	PAGE
;
;
;****************************************************************
;*								*
;*			MISCELLAENOUS EQUATES			*
;*								*
;****************************************************************
;
FALSE	EQU	0
TRUE	EQU	NOT FALSE
;
CR	EQU	13
LF	EQU	10
BEEP	EQU	7
BS	EQU	8
ESC	EQU	01BH
;
REBOOT	EQU	0000H
DOS	EQU	0005H
;
;
SECLEN	EQU	80H		; len of an o/s sector
;
;
RSTDKF	EQU	13		; CPM RESET DISK SYSTEM FN
OPENF	EQU	15		; CPM OPEN FILE FN
CLOSEF	EQU	16		; CPM CLOSE FILE FN
DELF	EQU	19		; CPM DELETE FILE FN
READF	EQU	20		; CPM READ NXT FILE SCTR FN
WRITEF	EQU	21		; CPM WRITE NXT FILE SCTR FN
CREATF	EQU	22		; CPM CREATE FILE FN
SETDMAF	EQU	26		; CPM SETDMA FUNCTION
;
FCB	EQU	005CH		; DEFAULT FCB ADDRESS
FCBCR	EQU	FCB+32		; CURRENT RECORD
;
;
;
	PAGE
;
;****************************************************************
;*								*
;*			MACRO DEFINITIONS			*
;*								*
;****************************************************************
;
;
CPM	MACRO	ADDRESS
	PUSH	H
	LXI	H,ADDRESS
	CMP	M
	POP	H
	ENDM
;
;
STORE	MACRO	ADDRESS,BYTE
	PUSH	PSW
	MVI	A,BYTE
	STA	ADDRESS
	POP	PSW
	ENDM
;
;
STD	MACRO	REG,ADDRESS		; STORE REGISTER DIRECT
	PUSH	H
	LXI	H,ADDRESS
	MOV	M,REG
	POP	H
	ENDM
;
;
LDD	MACRO	REG,ADDRESS		;; LOAD REGISTER DIRECT
	PUSH	H
	LXI	H,ADDRESS
	MOV	REG,M
	POP	H
	ENDM
;
;
STI	MACRO	REG,ADDRESS		; STORE REGISTER INDIRECT
	PUSH	H
	LHLD	ADDRESS
	MOV	M,REG
	POP	H
	ENDM
;
;
LDI	MACRO	REG,ADDRESS		;; LOAD REGISTER INDIRECT
	PUSH	H
	LHLD	ADDRESS
	MOV	REG,M
	POP	H
	ENDM
;
;
INW	MACRO	ADDRESS			;; INCREMENT A WORD IN MEMORY
	PUSH	H
	LHLD	ADDRESS
	INX	H
	SHLD	ADDRESS
	POP	H
	ENDM
;
;
DCW	MACRO	ADDRESS			;; DECREMENT A WORD IN MEMORY
	PUSH	H
	LHLD	ADDRESS
	DCX	H
	SHLD	ADDRESS
	POP	H
	ENDM
;
;
INB	MACRO	ADDRESS			;; INCREMENT A BYTE IN MEMORY
	PUSH	H
	LXI	H,ADDRESS
	INR	M
	POP	H
	ENDM
;
;
DCB	MACRO	ADDRESS			;; DECREMENT A BYTE IN MEMORY
	PUSH	H
	LXI	H,ADDRESS
	DCR	M
	POP	H
	ENDM
;
;
DADA	MACRO
	PUSH	D
	MVI	D,0
	MOV	E,A
	DAD	D
	POP	D
	ENDM
;
;
SDED	MACRO	ADDRESS			;; STORE [DE] DIRECT
	XCHG
	SHLD	ADDRESS
	XCHG
	ENDM
;
LDED	MACRO	ADDRESS			;; LOAD [DE] DIRECT
	XCHG
	LHLD	ADDRESS
	XCHG
	ENDM
;
;
SBCD	MACRO	ADDRESS			;; STORE [BC] DIRECT
	PUSH	H
	MOV	L,C
	MOV	H,B
	SHLD	ADDRESS
	POP	H
	ENDM
;
;
LBCD	MACRO	ADDRESS			;; LOAD [BC] DIRECT
	PUSH	H
	LHLD	ADDRESS
	MOV	C,L
	MOV	B,H
	POP	H
	ENDM
;
;
;
	PAGE
;
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;****************************************************************
;*								*
;*		BEGINNING OF SYSGEN 				*
;*								*
;****************************************************************
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
;
;
SYSGEN:	LXI	SP,STACK	; SETUP STACK POINTER
	CALL	SIGNON		; PRINT SIGNON MESSAGE
	CALL	CHKRD		; CHK CMD LINE FOR FILENM, & TRY TO RD IN IF
				;   THERE; RETURN NZ IF FILE NOT IN RAM
	JZ	SYS1		; FILE IN RAM, DON'T ASK FOR SOURCE
	CALL	GETSYS		; ELSE GET SYSTEM
SYS1:	CALL	PUTSYS		; AND PUT SYSTEM
	LDA	DUNFLG		; SEE IF USER FINISHED
	ORA	A	
	JNZ	REBOOT
	JMP	SYS1
;
;
	PAGE
;
;****************************************************************
;*								*
;*	CHKRD	CHECK FOR DEFAULT FCB ACTIVE			*
;*		READ FILE IN AT 'BOOTIM' ADDR IF SO		*
;*		RETURN NZ IF NO FILE				*
;*								*
;****************************************************************
;
;
CHKRD:	LDA	FCB+1		; GET 1ST BYTE OF FILE NAME
	CPI	' '		; IS IT A SPACE??
	JZ	CKR1		; YES, THEN NO FILE
	CPI	'?'		; IS IT A Q.M.
	JZ	CKR1		; YES, THEN NO FILE
				; ELSE READ FILE
	LXI	D,FCB		; [DE] POINTS TO FCB
	MVI	C,OPENF		; DO OPEN FILE FUNCTION
	CALL	DOS		; TO SYSTEM
	INR	A		; 255 IS N.G. OPEN, BUMP TO 0
	JZ	CKR2		; CAN'T OPEN FILE
	LXI	H,BOOTIM	; MEM LOCATION FOR START OF SYSGEN (1000h)
	SHLD	DMAADR		; SAVE DMA ADDRESS
	MVI	A,0
	STA	FCBCR		; SET CURRENT RECORD TO 0
CKRLP:	LDED	DMAADR		; GET DMA ADDRESS
	MVI	C,SETDMAF	; CPM DMA FUNCTION
	CALL	DOS		; SET DMA ADDRESS
	LXI	D,FCB		; POINT TO FCB
	MVI	C,READF		; CPM READ FUNCTION
	CALL	DOS		; READ
	ORA	A		; CHECK FOR END OF FILE
	JNZ	CKR3		; READ UNTIL END OF FILE
	LHLD	DMAADR		; GET DMA ADDRESS
	LXI	D,80H		; CPM SECTOR SIZE
	DAD	D
	SHLD	DMAADR		; SAVE NEW DMA ADDRESS
	JMP	CKRLP
CKR3:	XRA	A		; SET Z FOR GOOD READ
	RET			; RETURN Z FOR GOOD READ
;
;
CKR2:	LXI	D,MSG9		; CANT FIND SOURCE FILE
CKR2A:	CALL	TEXT
CKR1:	MVI	A,0FFH
	ORA	A
	RET
;
;
;
	PAGE
;
;****************************************************************
;*								*
;*	GETSYS		GET SYSTEM				*
;*								*
;****************************************************************
;
;
GETSYS:	LXI	D,MSG1		; ASK FOR SOURCE
	CALL	TEXT		; PRINT MESSAGE
	CALL	INPUT		; GET INPUT
	CALL	CRCHK		; CHECK FOR CR
	JZ	GSYS2		; SKIP TO NEXT ON CR
	MOV	A,M		; GET USER'S INPUT
	CALL	TOUPPER		; CONVERT TO UPPER CASE
	STA	SDMSG		; PLACE IN ASCII MESSAGE
	SUI	'A'		; STRIP ASCII BIAS
	STA	SDISK		; AND SAVE SOURCE DISK
	INR	A		; CVT TO FCB FORMAT
	STA	SFCBDV		; AND PUT IN SOURCE FCB
	LXI	D,MSG2		; ELSE INSTRUCT USER
	CALL	TEXT		; TO INSERT SOURCE DISK
	CALL	INPUT		; WAIT FOR CARRIAGE RETURN
	CALL	CRCHK		; CHECK FOR CR
	JNZ	GSYS2		; SKIP ON NON-CR
	LDA	SDISK		; GET SOURCE DISK
	MOV	C,A		; PASS IN [C]
	CALL	READSYS		; READ SYSTEM INTO RAM
	LXI	D,MSG7		; FUNCTION COMPLETE MESSAGE
	CALL	TEXT		; PRINT IT
GSYS2:	RET			; DONE

;
;
;
	PAGE
;
;****************************************************************
;*								*
;*	PUTSYS		PUT SYSTEM				*
;*								*
;****************************************************************
;
;
PUTSYS:	LXI	D,MSG4		; ASK FOR DESTINATION
	CALL	TEXT		; PRINT MESSAGE
	CALL	INPUT		; GET INPUT
	CALL	CRCHK		; CHECK FOR CR
	MVI	A,0FFH
	JZ	PSYS2		; SKIP TO NEXT ON CR
	MOV	A,M		; GET USER'S INPUT
	CALL	TOUPPER		; CONVERT TO UPPER CASE
	STA	DDMSG		; PLACE IN ASCII MESSAGE
	SUI	'A'		; STRIP ASCII BIAS
	STA	DDISK		; AND SAVE DEST DISK
	INR	A		; CVT TO FCB FORMAT
	STA	DFCBDV		; AND PUT IN DEST FCB
	LXI	D,MSG5		; ELSE INSTRUCT USER
	CALL	TEXT		; TO INSERT DEST DISK
	CALL	INPUT		; WAIT FOR CARRIAGE RETURN
	CALL	CRCHK		; CHECK FOR CR
	MVI	A,0FFH		; FOR DUNFLG
	JNZ	PSYS2		; SKIP ON NON-CR
	LDA	DDISK		; GET DEST DISK
	MOV	C,A		; PASS IN [C]
	CALL	WRITESYS	; WRITE SYSTEM FROM RAM
	LXI	D,MSG7		; FUNCTION COMPLETE MESSAGE
	CALL	TEXT		; PRINT IT
	MVI	A,0		; NOT FINISHED
PSYS2:	STA	DUNFLG
	RET			; DONE

;
;
;
	PAGE
;
;****************************************************************
;*								*
;*	READSYS		READ SYSTEM FROM DISK			*
;*			ENTER WITH DRIVE NUMBER IN [C]		*
;*								*
;****************************************************************
;
;
READSYS:
	CALL	SELDSK		; SELECT DISK
	LXI	H,BOOTIM	; then zero out sysgen area,
	LXI	B,SYSGSZ
	CALL	ZERO
	CALL	READBOOT	; and read BOOT,
	CALL	READBIOS	;   BIOS,
	CALL	READCLI		;   CLI (from 'system.cli' file),
	CALL	READDOS		;   and SB/80 DOS
	CALL	READCHK
	RET



	PAGE

;****************************************************************
;*								*
;*	READBOOT	READ BOOT FROM RAM AT 900H		*
;*			TO TRACK 0 SECTOR 1 AND 2		*
;*								*
;****************************************************************



READBOOT:
	MVI	C,1		; BOOT ON TRACK 0
	CALL	SETTRK
	MVI	B,2		; # OF SECTORS TO READ
	MVI	C,1		; STARTING SECTOR NUMBER
	LXI	H,BOOTIM	; STARTING SYSGEN ADDRESS
	CALL	READSPAN
	RET


	PAGE
;****************************************************************
;*								*
;*	READBIOS	READ BIOS FROM RAM AT 2000H		*
;*			TO TRACK 0 SECTOR 2			*
;*								*
;****************************************************************


READBIOS:
	MVI	C,1		; BIOS LIVES ON TRACK 2	PHYSICAL TRACK 8
	CALL	SETTRK

	MVI	B,50		; # OF SECTORS TO READ
	MVI	C,3		; STARTING SECTOR NUMBER
	LXI	H,BIOSIM	; STARTING DMA ADDRESS
	CALL	READSPAN

	RET


	PAGE
;****************************************************************
;*								*
;*	READDOS		READ DOS FROM RAM AT 980H		*
;*			TO TRACK 1 SECTOR 1			*
;*								*
;****************************************************************



READDOS:
	LDA	DDISK
	MOV	C,A
	CALL	SELDSK		; RESELECT AFTER CLI STUFF

	MVI	C,2		; CPM LIVES ON TRACK 72
	CALL	SETTRK
	MVI	B,30		; # OF SECTORS TO READ
	MVI	C,1		; STARTING SECTOR
	LXI	H,DOSIM
	CALL	READSPAN

	MVI	B,10		; # OF SECTORS TO READ
	MVI	C,33		; STARTING SECTOR
	LXI	H,DOSIM+0F00H
	CALL	READSPAN
	RET


;****************************************************************
;*								*
;*	READCHK		READ THE CHECKSUM BLOCK			*
;*			AT PHYSICAL 6 (LOGICAL 16)		*
;*								*
;****************************************************************


READCHK:
	MVI	C,2		; GO ON TRACK 73
	CALL	SETTRK

	LXI	H,CHKTBL
	MVI	B,2
	MVI	C,31
	CALL	READSPAN
	RET



	PAGE
;****************************************************************
;*								*
;*	READCLI		READ SB/80 CLI FROM 'SYSTEM.CLI' FILE	*
;*								*
;*			TO RAM AT ADDR 'CLIIM' (1100h)		*
;*								*
;****************************************************************
;
;
;
READCLI:
	LXI	D,SFCB		; OPEN SOURCE 'SYSTEM.CLI'
	MVI	C,OPENF
	CALL	DOS
	INR	A		; BMP POSSIBLE -1 (255) TO 0
	JZ	RCLIERR		;   <SYSTEM.CLI> NOT FOUND
	LXI	H,CLIIM		; SET DMA ADDR TO START OF CLI IMAGE
	SHLD	DMAADR
RCLILP:
	LDED	DMAADR		; GET DMA ADDR
	MVI	C,SETDMAF	; SETDMA
	CALL	DOS
	LXI	D,SFCB
	MVI	C,READF		; READ NXT FILE SCTR
	CALL	DOS
	ORA	A		; TEST FOR EOF
	JNZ	RCLIL1
	LHLD	DMAADR		; GET DMA ADDR BACK
	LXI	D,80H
	DAD	D		; BUMP BY SECTOR SZ
	SHLD	DMAADR
	LXI	D,DOSIM		; PUT DOS IMAGE ADDR IN <DE>
	XCHG			;   THEN EXCHANGE <DE> & <HL>
	CALL	CPDEHL		;   & TEST FOR OVERWRITE
	XCHG
	JC	RCLIWRN		;   DSPLY WARNING, & THEN RET TO CONTINUE
	JMP	RCLILP
RCLIL1:
	XRA	A		; SET Z FOR GOOD RD
	RET

RCLIERR:
	MVI	A,1
	STA	NCLIFLG		; NO CLI FLG
	LXI	D,RCLIEMG	; 'file not found on source, will not
	JMP	CKR2A		;    be created on destination'

RCLIWRN:
	LXI	D,RCLIWMG	; 'file larger than area allotted -
	CALL	TEXT		;    will be truncated'
	RET



	PAGE
;****************************************************************
;*								*
;*	READSPAN	READ A MEMORY SPAN TO A SPAN OF		*
;*			SECTORS, [B]=NUMBER OF SECTORS		*
;*			[C]=SECTOR TO START, [HL]=START MEM	*
;*			YOU MUST CALL SETRACK BEFORE ENTER	*
;*								*
;****************************************************************
;
;
READSPAN:
	PUSH	B		; SAVE [BC] AND [HL]
	PUSH	H
	PUSH	B
	MOV	B,H		; MOVE DMA ADDRESS
	MOV	C,L		; INTO [BC]
	CALL	SETDMA		; AND SET IT UP
	POP B
	CALL 	SETSEC
	CALL	READ		; READ/WRITE SECTOR
	POP	H
	POP	B
	CNZ	DSKERR		; DO ERROR STUFF
	INR	C		; BUMP SECTOR COUNT
	LXI	D,SECLEN
	DAD	D		; BUMP DMA ADDRESS
	DCR	B
	JNZ	READSPAN
	RET

	PAGE
;
;****************************************************************
;*								*
;*	WRITESYS	WRITE SYSTEM TO DISK			*
;*			ENTER WITH DRIVE NUMBER IN [C]		*
;*								*
;****************************************************************
;
;
WRITESYS:
	CALL	RSTDSK
	CALL	SELDSK		; SELECT DISK
	CALL	WRITEBOOT	; then write the BOOT,
	CALL	WRITEBIOS	;   BIOS,
	CALL	WRITECLI	;   CLI (to 'system.cli' file),
	CALL	WRITEDOS	;   and SB/80 DOS
	CALL	GENCHK
	CALL	WRITECHK
	RET
;
;
;
	PAGE

;****************************************************************
;*								*
;*	WRITEBOOT	WRITE BOOT FROM RAM AT 900H		*
;*			TO TRACK 0 SECTOR 1			*
;*								*
;****************************************************************



WRITEBOOT:
	MVI	C,1		; BOOT LIVES ON TRACK 0
	CALL	SETTRK
	MVI	B,2		; BOOT IS 2 CPM SECTORS
	MVI	C,1		; STARTING SECTOR NUMBER
	LXI	H,BOOTIM
	CALL	WRITSPAN
	RET


	PAGE
;****************************************************************
;*								*
;*	WRITEBIOS	WRITE BIOS FROM RAM AT 2000H		*
;*			TO TRACK 0 SECTOR 2			*
;*								*
;****************************************************************



WRITEBIOS:
	MVI	C,1		; BIOS LIVES ON TRACK 2	PHYSICAL TRACK 8
	CALL	SETTRK

	MVI	B,50		; # OF SECTORS TO READ
	MVI	C,3		; STARTING SECTOR NUMBER
	LXI	H,BIOSIM	; STARTING DMA ADDRESS
	CALL	WRITSPAN

	RET



	PAGE
;****************************************************************
;*								*
;*	WRITEDOS	WRITE CPM FROM RAM AT 980H		*
;*			TO TRACK 1 SECTOR 1			*
;*								*
;****************************************************************



WRITEDOS:
	LDA	DDISK		
	MOV	C,A	
	CALL	SELDSK		;RESELECT AFTER DOS STUFF

	MVI	C,2		; CPM LIVES ON TRACK 1
	CALL	SETTRK
	MVI	B,30
	MVI	C,1
	LXI	H,DOSIM
	CALL	WRITSPAN

	MVI	B,10
	MVI	C,33
	LXI	H,DOSIM+0F00H
	CALL	WRITSPAN
	RET

	PAGE

;****************************************************************
;*								*
;*	WRITECHK	WRITE THE CHECKSUM BLOCK		*
;*			AT PHYSICAL 6 (LOGICAL 16)		*
;*								*
;****************************************************************


WRITECHK:
	MVI	C,2		; GO ON TRACK 73
	CALL	SETTRK

	LXI	H,CHKTBL
	MVI	B,2
	MVI	C,31
	CALL	WRITSPAN
	RET



	PAGE
;
;****************************************************************
;*								*
;*	WRITECLI	WRITE SB/80 CLI FROM RAM AT ADDR 'CLIIM'*
;*							 (1100h)*
;*			TO 'SYSTEM.CLI' FILE			*
;*								*
;****************************************************************
;
;
;
WRITECLI:
	LDA	NCLIFLG		; TEST FOR SOURCE <SYSTEM.CLI> FILE
	ORA	A
	RNZ			;   DON'T WRITE NEW IF NO OLD
;
	LXI	D,DFCB		; DEL ANY EXISTING <SYSTEM.CLI> ON DEST
	MVI	C,DELF
	CALL	DOS
	LXI	D,DFCB
	MVI	C,CREATF	; AND CREATE A NEW ONE
	CALL	DOS
	INR	A		; BAD RC IS -1
	JZ	CCLIERR		;   CREATE ERROR
	XRA	A
	STA	DFCBNS		; ZERO OUT NEXT SECTOR IN FCB
	LXI	H,CLIIM
	SHLD	DMAADR
	LXI	H,CLINS		; pt to # of cli sctrs to wrt,
	MOV	A,M		;   & put in <A>
	STA	CLICNT		; store as cntr
WCLILP:
	LDED	DMAADR		; GET DMA ADDR
	MVI	C,SETDMAF	; SETDMA
	CALL	DOS
	LXI	D,DFCB
	MVI	C,WRITEF	; READ NXT FILE SCTR
	CALL	DOS
	ORA	A		; TEST FOR EOF
	JNZ	WCLIL1
	LDA	CLICNT		; GET CUR CLI SCTR CNT
	DCR	A
	STA	CLICNT
	JZ	WCLIL1		; ALL DONE WHEN 0
	LHLD	DMAADR		; GET DMA ADDR BACK
	LXI	D,80H
	DAD	D		; BUMP BY SECTOR SZ
	SHLD	DMAADR
	JMP	WCLILP
WCLIL1:
	LXI	D,DFCB
	MVI	C,CLOSEF
	CALL	DOS
	XRA	A		; SET Z FOR GOOD RD
	RET

CCLIERR:
	LXI	D,CRCLIEMG
	CALL	TEXT
	RET

	PAGE
;
;****************************************************************
;*								*
;*	WRITESPAN	WRITE A MEMORY SPAN TO A SPAN OF	*
;*			SECTORS, [B]=NUMBER OF SECTORS		*
;*			[C]=SECTOR TO START, [HL]=START MEM	*
;*			YOU MUST CALL SETRACK BEFORE ENTER	*
;*								*
;****************************************************************
;
;
WRITSPAN:
	PUSH	B		; SAVE [BC] AND [HL]
	PUSH	H
	PUSH	B
	MOV	B,H		; MOVE DMA ADDRESS
	MOV	C,L		; INTO [BC]
	CALL	SETDMA		; AND SET IT UP
	POP B
	CALL 	SETSEC
	MVI	C,2		; WRITE UNALLOCATED
	CALL	WRITE		; READ/WRITE SECTOR
	POP	H
	POP	B
	CNZ	DSKERR		; DO ERROR STUFF
	INR	C		; BUMP SECTOR COUNT
	LXI	D,SECLEN
	DAD	D		; BUMP DMA ADDRESS
	DCR	B
	JNZ	WRITSPAN
	RET
;
	PAGE

;****************************************************************
;*								*
;*	GENCHK	GENERATE CHECKSUM AND INSERT			*
;*								*
;*								*
;****************************************************************


GENCHK:
	CALL	CHKBOOT		; CHECKSUM THE BOOT LOADER
	STA	CHKTAB		; SAVE IN TABLE
	CALL	CHKDOS		; CHECKSUM THE DOS (FUNNY SECTORS)
	STA	CHKTAB+1	; SAVE IN TABLE
	CALL	CHKBIOS		; CHECKSUM THE BIOS
	STA	CHKTAB+2	; SAVE IN TABLE
	CALL	CHKDUMMY
	LXI	H,CHKTAB
	ADD	M
	INX	H
	ADD	M
	INX	H
	ADD	M
	CMA			; TWO'S COMPLIMENT
	INR	A		; 
	STA	CHKSUMAD	; STUFF IN CHECKSUM LOCATION
	RET

CHKTAB:	DB	0
	DB	0
	DB	0


CHKBOOT:
	LXI	H,BOOTIM	; GET BOOT ADDRESS
	LXI	B,BOOTSIZ	; AND BOOT SIZE
	CALL	CHKSUM
	RET




CHKDOS:
	LXI	H,DOTBL		; SETUP TABLE OF ADDRESS IN DOS TO CHECKSUM
	LXI	B,0*256+5	; SET B[SUM]=0 AND C[COUNT] =5

CHKDO1:	PUSH	H		; SAVE OUR COUNTERS AND POINTERS
	PUSH	B
	MOV	D,M		; GET VAL FROM TABLE AS HIGH BYTE
	MVI	E,0		; SET LOW=0
	XCHG			; PUT TO HL FOR LOC TO SUM
	LXI	B,256		; SUM A CHUNK
	CALL	CHKSUM
	POP	B		; GET BACK COUNTERS
	POP	H
	ADD	B		; ADD TO SUM
	MOV	B,A		; PUT IN SUM
	INX	H		; BUMP POINTER
	DCR	C		; DEC LOOP CONTER
	JNZ	CHKDO1		; GO TILL DONE

	MOV	A,B		; GET SUM BACK TO [A]
	RET


DOTBL:	DB	21H
	DB	24H
	DB	27H
	DB	2AH
	DB	2DH



CHKBIOS:
	LXI	H,BIOSIM
	LXI	B,BIOSSIZ
	CALL	CHKSUM
	RET

CHKDUMMY:
	LXI	H,CHKTBL
	LXI	B,255
	CALL	CHKSUM
	RET




	PAGE
;****************************************************************
;*								*
;*	 CHKSUM	CHECKSUM GENERATOR 				*
;*								*
;****************************************************************


CHKSUM:	MVI	D,0		; ZERO CHECKSUM
CHKS1:	MOV	A,D		; GET CHECKSUM TO [A]
	ADD	M		; ADD NEXT BYTE
	MOV	D,A		; REPLACE CHECKSUM
	INX	H
	DCX	B
	MOV	A,B
	ORA	C		; 
	JNZ	CHKS1		; LOOP TILL DONE
	MOV	A,D		; 
	RET			; 


	PAGE

CHKTBL:
	DB	'MARTY IS A DOPE '
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDEF'
	DB	'0123456789ABCDE'
CHKSUMAD:
	DB	0



;
;****************************************************************
;*								*
;*	RSTDSK		RESET DISK SYSTEM			*
;*								*
;****************************************************************
;
;
RSTDSK:
	PUSH B! PUSH D! PUSH H
	LXI	D,0
	MVI	C,13
	CALL	DOS
	POP H! POP D! POP B
	RET
;
;
	PAGE
;
;****************************************************************
;*								*
;*			BIOS CALLS				*
;*								*
;****************************************************************
;
;
CONST:	MVI	A,3
	JMP	UBIOS
CONIN:	MVI	A,6
	JMP	UBIOS
CONOUT:	MVI	A,9
	JMP	UBIOS
LIST:	MVI	A,12
	JMP	UBIOS
PUNCH:	MVI	A,15
	JMP	UBIOS
READER:	MVI	A,18
	JMP	UBIOS
HOME:	MVI	A,21
	JMP	UBIOS
SELDSK:	MVI	A,24		; OFFSET TO SELECT JUMP
	JMP	TBIOS
SETTRK:	MVI	A,27		; OFFSET TO SET TRACK
	JMP	UBIOS
SETSEC:	MVI	A,30		; OFFSET TO SET SECTOR
	JMP	UBIOS
SETDMA:	MVI	A,33		; OFFSET TO SET DMA ADDRESS
	JMP	UBIOS
READ:	MVI	A,36		; OFFSET TO READ SECTOR
	JMP	UBIOS
WRITE:	MVI	A,39		; OFFSET TO WRITE SECTOR
	JMP	UBIOS
LISTST:	MVI	A,42		; OFFSET TO LIST STATUS
	JMP	UBIOS
SECTRN:	MVI	A,45
	JMP	TBIOS
;
;
;
TBIOS:	PUSH	B
	PUSH	D
	CALL	VBIOS
	POP	D
	POP	B
	RET
;
UBIOS:	PUSH	B
	PUSH	D
	PUSH	H
	CALL	VBIOS
	POP	H
UB1:	POP	D
	POP	B
	RET
;
VBIOS:	LHLD	1
	ADD	L
	MOV	L,A
	PCHL
;
;
;
	PAGE
;
;****************************************************************
;*								*
;*	INPUT	GETS BUFFERED INPUT FROM IBUF			*
;*		RETURNS WITH CHAR COUNT IN [A]			*
;*			[HL] POINTS TO 1ST CHAR			*
;*								*
;****************************************************************
;
;
INPUT:	LXI	H,IBUF
	CALL	BUFIN
	CALL	CRLF			; SEND CRLF
	LXI	H,IBUF+1		; POINT TO CHAR COUNT
	MOV	A,M
	INX	H
	RET
;
IBUF:	DB	16			; INPUT BUFFER LENGTH
	DB	0			; CHAR COUNT
	DS	16			; INPUT BUFFER
;
;
;
;****************************************************************
;*								*
;*	CRCHK	CHECK FOR CARRIAGE RETURN FROM INPUT ROUTINE	*
;*		RETURNS ZERO IF JUST CR WAS HIT			*
;*								*
;****************************************************************
;
;
CRCHK:	PUSH	H		; SAVE [HL]
	LXI	H,IBUF+1	; POINT TO LOCATION CONTAINING COUNT
	MOV	A,M		; GET CHAR COUNT
	ORA	A		; SET FLAGS
	POP	H		; RESTORE [HL]
	RET
;
;
;
;****************************************************************
;*								*
;*	BUFIN	BUFFERED INPUT ROUTINE ENTER WITH [HL] 		*
;*			POINTING TO BUFFER.			*
;*								*
;****************************************************************
;
;
BUFIN:	XCHG	
	MVI	C,10
	CALL	DOS
	RET

	IF FALSE
BUFIN:
	MOV	C,M			; 1ST BYTE OF BUFFER IS # OF CHARS
	INX	H			; POINT TO CHAR COUNT
	MVI	M,0			; INITIALIZE TO 0
	PUSH	H			; SAVE POINTER TO CHAR COUNT
	INX	H
	MVI	B,0
BUFIN1:	CALL	CONIN
	CPI	CR			; IS IT <CR>
	JZ	BUFIN3			; YES, RETURN
	CPI	BS			; IS IT BACKSPACE
	JZ	BUFIN2			; YES, BACKUP
	MOV	M,A			; INSERT CHAR IN BUFFER
	CALL	ACONO			; ECHO CHAR IN [A]
	INX	H			; BUMP MEMORY POINTER
	INR	B			; BUMP CHAR COUNTER
	DCR	C			; COUNTDOWN SPACE
	JNZ	BUFIN1			; NOT DONE, KEEP LOOPING
BUFIN3:	POP	H			; GET POINTER TO CHAR. COUNT
	MOV	M,B			; PUT NUMBER OF CHAR'S IN MEM
	CALL	CRLF
	RET
;
BUFIN2:	MOV	A,B			; SEE HOW FAR INTO BUFFER
	ORA	A
	JZ	BUFIN1			; BEGINNING OF BUFFER, DO NOTHING
	PUSH	B
	MVI	C,BS
	CALL	CONOUT
	MVI	C,' '
	CALL	CONOUT
	MVI	C,BS
	CALL	CONOUT
	JMP	BUFIN1
;
;
ACONO:	PUSH	B
	MOV	C,A
	CALL	CONOUT
	POP	B
	RET
;
;
IBLOC:	DS	2
;
	ENDIF
;
;
	PAGE
;
;****************************************************************
;*								*
;*	DECIN	GETS DECIMAL INPUT FROM CONSOLE			*
;*		RETURNS NUMBER IN [HL]				*
;*		CARRY SET AND 0 IN [HL] IF ILLEGAL INPUT	*
;*								*
;****************************************************************
;
;
DECIN:	PUSH B ! PUSH D
	CALL	INPUT		; GET ASCII STRING
	LXI	H,IBUF+1	; GET CHARACTER COUNT
	MOV	A,M		; IN [A]
	ORA	A
	JZ	DECI5		; NO CHARACTERS
	MOV	B,A		; COUNT TO [B]
	INX	H		; POINT TO 1ST CHARACTER
	SHLD	DPOINT		; SAVE POINTER TO BUFFER
	LXI	H,0		; 0 OUT RESULT REG
DECI1:	LDI	A,DPOINT	; GET LO ORDER CHAR IN [A]
	INW	DPOINT		; AND BUMP COUNTER
	CALL	VCHECK		; STRIP ASCII BIAS
	JC	DECI5		; BAD CHARACTER
	CALL	X10		; MULTIPLY [HL] BY 10
	DADA			; AND ADD IN LO ORDER VALUE
	DCR	B		; COUNTDOWN
	JNZ	DECI1
	JMP	DECI2		; RETURN
DECI5:	LXI	H,0
	STC
DECI2:	POP D ! POP B
	RET
;
;
DPOINT:	DW	$-$
;
;
X10:	PUSH	D	 	; MULT [HL] BY 10, RESULT IN [HL]
	DAD	H		; [HL] * 2
	PUSH H ! POP D		; TO [DE]
	DAD	H		; * 4
	DAD	H		; * 8
	DAD	D
	POP	D
	RET
;
;
VCHECK:	SUI	'0'
	RC			; BAD CHAR
	CPI	10
	CMC			; AND COMPLIMENT CARRY
	RET
;
;
	PAGE
;
;****************************************************************
;*								*
;*	DECOUT	PRINTS [HL] IN DECIMAL				*
;*								*
;****************************************************************
;
;
DECOUT:	LXI	D,DECBUF+5
	MVI	B,5
DECO1:	MVI	A,10
	CALL	DIV
	DCX	D
	ADI	'0'
	STAX	D
	DCR	B
	JNZ	DECO1
	MVI	B,4
DECO2:	LDAX	D
	CPI	'0'
	JNZ	TEXT
	INX	D
	DCR	B
	JNZ	DECO2
	JMP	TEXT
;
;
DECBUF:	DB	0,0,0,0,0,'$'
;
;
;
	PAGE
;
;
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;*****************************************************************
;**								**
;**		MISCELLANEOUS ROUTINES				**
;**								**
;*****************************************************************
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
;
;
;****************************************************************
;*								*
;*	MOVE	MOVE [BC] BYTES FROM [HL] TO [DE]		*
;*								*
;****************************************************************
;
;
MOVE:	MOV	A,M		; GET A SOURCE BYTE
	STAX	D
	INX	D
	INX	H
	DCX	B
	MOV	A,C
	ORA	B
	JNZ	MOVE
	RET
;
;
;
;****************************************************************
;*								*
;*	ZERO	ZERO  <BC> BYTES AT <HL>			*
;*								*
;****************************************************************
;
;
ZERO:	XRA	A
	MOV	M,A
	INX	H
	DCX	B
	MOV	A,C
	ORA	B
	JNZ	ZERO
	RET

	PAGE
;
;****************************************************************
;*								*
;*	COMPR	COMPARE [BC] BYTES STARTING AT [HL],[DE]	*
;*		RETURNS W/NZ SET ON 1ST NON-MATCH		*
;*								*
;****************************************************************
;
;
COMPR:	LDAX	D		; GET A BYTE TO COMPARE
	CMP	M
	RNZ			; RETURN IF DIFFERENT
	INX	D		; BUMP POINTERS
	INX	H
	DCX	B
	MOV	A,C		; TEST FOR NO MORE BYTES
	ORA	B		; TO COMPARE
	JNZ	COMPR		; LOOP IF MORE
	RET
;
;
;
;****************************************************************
;*								*
;*	LDEM	LOAD [DE] FROM 2 BYTES POINTED TO BY [HL]	*
;*								*
;****************************************************************
;
;
LDEM:	MOV	E,M
	INX	H
	MOV	D,M
	INX	H
	RET
;
;
;
;****************************************************************
;*								*
;*	OFFSET	DOUBLE ADD A TO HL				*
;*								*
;****************************************************************
;
;
OFFSET:	ADD	L
	MOV	L,A
	RNC
	INR	H
	RET

	PAGE
;
;****************************************************************
;*								*
;*	TEXT	PRINT MESSAGE POINTED TO BY [DE]		*
;*								*
;****************************************************************
;
;
TEXT:	PUSH	B
	PUSH	H
	MVI	C,9
	CALL	DOS
	POP	H
	POP	B
	RET
;
;
;
;****************************************************************
;*								*
;*	CRLF	PRINT CARRIAGE RETURN LINE FEED			*
;*								*
;****************************************************************
;
;
CRLF:	MVI	C,CR
	CALL	CONOUT
	MVI	C,LF
	CALL	CONOUT
	RET
;
;
;
;****************************************************************
;*								*
;*	TOUPPER	CONVERT ASCII CHAR IN [A] TO UPPER CASE		*
;*								*
;****************************************************************
;
;
TOUPPER:
	CPI	'a'		; LESS THAN a 
	RC			; RETURN IF SO
	CPI	'z'+1		; GREATER THAN z
	RNC			; RETURN IF SO
	ANI	05FH		; ELSE STRIP BITS
	RET

	PAGE
;
;****************************************************************
;*								*
;*	DBLSUB	SUBTRACT [HL]-[DE]				*
;*		RESULT IN [HL]					*
;*								*
;****************************************************************
;
;
DBLSUB:	MOV	A,L		; GET LO BYTE OF SUBTRAHEND
	SUB	E		; SUBTRACT LO MINUEND
	MOV	L,A		; RETURN DIFFERENCE
	MOV	A,H		; DO HI BYTE
	SBB	D		; AND SUBTRACT WITH BORROW
	MOV	H,A		; DIFFERENCE TO [HL]
	RET			; (CARRY IS SET IF DE > HL)
;
;
CPDEHL:	MOV	A,L
	SUB	E
	MOV	A,H
	SBB	D
	RET

;
;
;****************************************************************
;*								*
;*	MULT	MULTIPLY [A] BY [HL]				*
;*		RESULT IN [HL]					*
;*								*
;****************************************************************
;
;
MULT:	XCHG
	LXI	H,0
	LXI	B,800H		; B IS LOOP COUNTER, C IS OVERFLOW INDICATOR
MUL1:	DAD	H		; SHIFT LEFT
	JNC	MUL2
	INR	C		; BUMP OVERFLOW
MUL2:	RLC			; ROTATE NEXT BIT OF MULTIPLICAND INTO CARRY
	JNC	MUL3
	DAD	D		; 
	JNC	MUL3		; 
	INR	C		; OVERFLOW INDICATOR
MUL3:	DCR	B		; DEC SHIFT COUNTER
	JNZ	MUL1
	MOV	A,C		; SEE IF OVERFLOW
	ORA	A		; TEST ZERO FLAG AND RESET CARRY
	RZ
	STC			; CARRY INDICATES OVERFLOW
	RET
;
;
	PAGE
;
;****************************************************************
;*								*
;*	DIV	DIVIDE [HL] BY [A]				*
;*		QUOTIENT IN [HL], REMAINDER IN [A]		*
;*								*
;****************************************************************
;
;
DIV:	PUSH	B
	PUSH	D
	MOV	D,A		; DIVISOR TO [D]
	LXI	B,1000H		; 16 IN B,0 IN C
DIV1:	DAD	H
	MOV	A,C
	RAL
	JC	DIV2
	CMP	D
	JC	DIV3
DIV2:	SUB	D
	INR	L
DIV3:	MOV	C,A
	DCR	B
	JNZ	DIV1
	MOV	A,C
	POP	D
	POP	B
	RET
;
;
;
	PAGE
;
;****************************************************************
;*								*
;*	SIGNON	PRINT SIGNON MESSAGE				*
;*								*
;****************************************************************
;
;
SIGNON:	LXI	D,SOMSG
	CALL	TEXT
	RET
;
;
;
;****************************************************************
;*								*
;*	DSKERR	DISK ERROR HANDLING				*
;*								*
;****************************************************************
;
;
DSKERR:	LXI	D,MSG6		; ERROR MESSAGE
	CALL	TEXT
	CALL	INPUT		; GET OPERATOR INPUT
	RET

	PAGE
;
;****************************************************************
;*								*
;*			MESSAGES				*
;*								*
;****************************************************************
;
;
MSG1:	DB	CR,LF
	DB	'Source drive NAME (or RETURN to skip) $'
;
MSG2:	DB	'Place SOURCE disk on '
SDMSG:	DB	'X:, then type RETURN $'
;
MSG3:	DB	CR,LF,'CP/M image in RAM at 0900H is ready to write'
	DB	CR,LF,'or reboot and "SAVE '
	DB	'57 CPMxx.COM"$'
;
MSG4:	DB	CR,LF
	DB	'Destination drive NAME (or RETURN to reboot) $'
;
MSG5:	DB	'Place DESTINATION disk on '
DDMSG:	DB	'X:, then type RETURN $'
;
MSG6:	DB	'Permanent ERROR - Type RETURN to ignore $'
MSG7:	DB	'Function complete$'
MSG8:	DB	'Invalid drive name (Use A B C or D) $'
MSG9:	DB	'No source file on disk$'
;
;
RCLIEMG:
	DB	CR,LF
	DB	'*** WARNING:  <SYSTEM.CLI> file not found on source drive,'
	DB	CR,LF
	DB	'              and will not be created on destination drive.'
	DB	CR,LF,'$'
RCLIWMG:
	DB	CR,LF
	DB	'*** WARNING:  the <SYSTEM.CLI> file is larger than the'
	DB	CR,LF
	DB	'              area allotted, and will be truncated.'
	DB	CR,LF,'$'
;
CRCLIEMG:
	DB	CR,LF
	DB	'No directory space for <SYSTEM.CLI> file'
	DB	' on destination drive'
	DB	CR,LF,'$'
WCLIEMG:
	DB	CR,LF
	DB	'Error writing to <SYSTEM.CLI> file on destination drive'
	DB	CR,LF,'$'
;
;
;
	PAGE
;
;****************************************************************
;*								*
;*			DATA AREA				*
;*								*
;****************************************************************
;
;
SFCB:	EQU	$
SFCBDV:	DB	0
SFCBFN:	DB	'SYSTEM  '
SFCBTP:	DB	'CLI'
SFCBXT:	DB	0,0
SFCBAT:	DB	0
SFCBSC:	DB	0
SFCBDM:	DB	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
SFCBNS:	DB	0
SFCBLR:	DB	0,0
SFCBND:	DB	0
;
DFCB:	EQU	$
DFCBDV:	DB	0
DFCBFN:	DB	'SYSTEM  '
DFCBTP:	DB	'CLI'
DFCBXT:	DB	0,0
DFCBAT:	DB	0
DFCBSC:	DB	0
DFCBDM:	DB	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DFCBNS:	DB	0
DFCBLR:	DB	0,0
DFCBND:	DB	0
;
DSKCMD:	DB	$-$		; DISK OPERATION COMMAND
DMAADR:	DW	$-$		; CURRENT DMA ADDRESS
SDISK:	DB	$-$		; SOURCE DRIVE #
DDISK:	DB	$-$		; DESTINATION DRIVE #
BSEC:	DB	$-$		; BIOS SECTOR STORAGE
CLICNT:	DB	$-$		; CLI SCTR CNT
NCLIFLG: DB	$-$		; NO CLI FLAG
DUNFLG:	DB	$-$		; ALL DONE WITH PROGRAM


;
;
	DS	64
STACK	EQU	$
;
	END
