ווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווווN:
;	MOVCPM XXH N
; THE SYSTEM IS GENERATED FOR XXFFH OF MEMORY WITH A BIOS OF N PAGES
; (256 BYTE BLOCKS) IN LENGTH
;
BASE	EQU	0		;LOCATION TO JUMP TO FOR BASE
	ORG	BASE+100H
;
; LOCATIONS OF INFORMATION FROM COMMAND LINE, PUT IN DEFAULT BUFFERS
; BY CCP:
;
NAME1	EQU	BASE+5DH	;FIRST "FILENAME" (NO. OF K)
NAME2	EQU	BASE+6DH	;2ND "FILENAME" (BLANK OR *)
;
ENTRY	EQU	BASE+5		;LOCATION OF JUMP TO BDOS
SYSTEM	EQU	BASE+900H	;WHERE RELOC'S COPY OF SYSTEM RESIDES
SERIAL	EQU	BASE+1200H	;START OF SERIAL NUMBER IN THAT SYSTEM
SIZE	EQU	801H		;WHERE LENGTH OF SYSTEM IS STORED
;
FIRST:	JMP	START
	DB	'COPYRIGHT (C) DIGITAL RESEARCH, 1979     '
;
START:	LXI	SP,BASE+800H
	LXI	D,NAME1
	LDAX	D		;GET 1ST CHAR. OF K
	CPI	' '
	JZ	UNSPEC		;JUMP IF NO NUMBER TYPED IN COMMAND
	CPI	'?'
	JZ	UNSPEC		;RECOGNIZE BLANK OR QUESTION MARK AS NO-NUMBER
;
; IF WE ARE HERE, THERE IS A NUMBER AT 5DH TO READ; ASSUME IT'S HEX
;
	LXI	H,0		;H WILL CONTAIN THE VALUE OF THE NUMBER
HXDGT:	LDAX	D		;GET NEXT DIGIT (ASCII)
	INX	D		;INCREMENT DIGIT POINTER
	ORA	A		;TEST FOR NULL (0)
	JZ	DECDGT		;NO. TERMINATED WITH NULL, NOT HEX
	CPI	'H'		;END OF HEX NO. ?
	JNZ	TSTHX		;NO, TEST FOR VALID HEX
	LXI	D,NAME2		;POINT TO 2ND PARAMETER
	MOV	A,H		;HIGH ORDER BYTE MUST BE ZERO
	ORA	A		;
	JNZ	INVAL
	MOV	A,L		;GET LOW ORDER BYTE
	CPI	3FH		;MUST BE AT LEAST 3FFFH (16K) OF MEMORY
	JC	INVAL		;BAD VALUE IF NOT
	STA	MEMSIZ		;SAVE AS MEMORY SIZE
	JMP	DECDG1		;GET SIZE OF BIOS
TSTHX:	SUI	'0'		;CONVERT TO BINARY
	CPI	10		;SEE IF ALPHA
	JC	HXOK		;GOOD DIGIT
	SUI	7		;CONVERT ALPHA HEX
	CPI	10H		;GREATER THAN 16 ?
	JNC	INVAL		;INVALID IF >= 16
HXOK:	DAD	H		;ROTATE OLD VALUE OF H,L LEFT NIBBLE
	DAD	H
	DAD	H
	DAD	H
	ADD	L		;ADD TO LOW ORDER NIBBLE IN L
	MOV	L,A		;
	JMP	HXDGT		;AND GO BACK FOR NEXT DIGIT
;
DECDGT:	LXI	D,NAME1		;RESET BUFFER POINTER
DECDG1:	LXI	H,0		;H WILL CONTAIN THE VALUE OF THE NUMBER
DIGIT:	LDAX	D		;GET NEXT DIGIT (ASCII)
	INX	D		;INCREMENT DIGIT POINTER
	CPI	' '
	JZ	TESTNO		;FINISHED GETTING NUMBER IF BLANK OR NULL
	ORA	A		;TEST FOR NULL (0)
	JZ	TESTNO
	SUI	'0'		;SUB ASCII 0; THIS CONVERTS DIGIT TO NUMBER
	CPI	10		;MAKE SURE IT WAS REALLY A DIGIT (0-9)
	JNC	INVAL		;JUMP IF NOT
	DAD	H		;DOUBLE ACCUMULATED VALUE
	PUSH	H		;SAVE RESULT
	DAD	H		;DOUBLE IT AGAIN
	DAD	H		;AND AGAIN
	POP	B		;NOW GET RESULT SAVE ABOVE AND ADD TO VALUE
	DAD	B		;WE HAVE NOW MULTIPLIED VALUE BY 10
	MOV	C,A		;NOW ADD TO IT THE VALUE OF THE NEW DIGIT
	MVI	B,0
	DAD	B
	JMP	DIGIT		;AND GO BACK FOR NEXT DIGIT
;
TESTNO:	MOV	A,H		;GET HIGH BYTE OF NUMBER OF K SPECIFIED
	ORA	A		;IF IT'S NOT ZERO, NUMBER WAS 256 OR BIGGER
	JNZ	INVAL		;AND THEREFORE NOT A VALID MEMORY SIZE
	LDA	MEMSIZ		;GET MEMORY SIZE
	ORA	A		;ZERO ?
	JZ	DECVAL		;NO, HEX VALUES WERE GIVEN
	MOV	H,A		;SET UP SIZE IN H,L
	MOV	A,L		;GET BIOSIZ
	CPI	64		;ALLOW 64 PG. BIOS (16K) MAX
	JNC	INVAL
	STA	BIOSIZ		;SAVE
	MVI	L,0
	INR	H		;NEED TO ADD 1
	JMP	PUTK		;NO. OF K
DECVAL:	MOV	A,L		;GET NO. OF K
	CPI	16		;SYSTEM MUST BE AT LEAST 16K
	JC	INVAL 		;SO ERROR IF <16.
;
; NOW MULTIPY NO. OF K BY 1024 TO GET SPECIFIED MEMORY SIZE
;
NOK:	MVI	L,0		;L WAS SAVED IN A ABOVE
	MOV	H,A		;THIS MULTIPLIES BY 256
	DAD	H		;MULTIPLY BY 2
	DAD	H		;MULTIPLY BY 2 AGAIN
	JMP	PUTK		;GO TO NEXT SECTION WITH H=MEMORY SIZE IN BYTES
;
INVAL:	LXI	D,INVMSG
	CALL	MSG		;OUTPUT "INVALID MEMORY SIZE" MESAGE TO CONSOLE
	JMP	BASE		;BASE SYSTEM
;
INVMSG:	DB  0DH,0AH,'INVALID MEMORY SIZE$'
;
;
; COME HERE IF MEMORY SIZE WAS NOT SPECIFIED IN COMMAND LINE
;
UNSPEC:	LXI	H,0		;SET UP TO FIND MEMORY SIZE
NPAGE:	INR	H		;POINT TO 1ST LOCATION OF NEXT PAGE
	JZ	FOUND		;GET OUT IF WE FOUND 256 PAGES OF MEMORY (WHY?)
	MOV	A,M		;GET 1ST BYTE OF PAGE POINTED TO BY H
	CMA			;COMPLEMENT IT
	MOV	M,A		; AND PUT IT BACK
	CMP	M		;NOW READ BACK AND COMPARE
	CMA			;RESTORE MEMORY BEFORE JUMPING
	MOV	M,A
	JZ	NPAGE		;KEEP LOOPING IF MEMORY VALID
FOUND:	MOV	A,H		;L STILL ZERO, SO HL = NO OF BYTES OF MEMORY
	ANI	0FCH		;TO NEAREST PAGE.  NOW ZERO BITS 0,1 OF H TO
	MOV	H,A		;TRUNCATE TO A MULTIPLE OF 1024
PUTK:	PUSH	H		;SAVE TRUNCATED MEMORY SIZE ON STACK
	LHLD	ENTRY+1		;GET STARTING ADDR OF BDOS FROM LOC. 5
	SHLD	BDOS		;SAVE IT FOR LATER USE
	POP	H		;GET MEMORY SIZE AGAIN
	PUSH	H		; BUT LEAVE IT ON STACK TOP
	MOV	A,H		;TAKE NUMBER OF PAGES AND DIVIDE BY 4 (INTEGER)
	RRC			;TO GET NUMBER OF K.
	RRC
	ANI	3FH
	JNZ	L01B8
	MVI	A,40H
L01B8:	MOV	B,A		;SAVE NUMBER OF K IN B
	LXI	H,CPMMSG+15	;POINT TO OF NO OF K IN "CONSTRUCTING" MSG
	MVI	A,'0'		;SET IT TO ASCII 00
	MOV	M,A
	INX	H
	MOV	M,A
CNVRT1:	LXI	H,CPMMSG+16	;LOOP TO CONVERT NO. OF K TO ASCII (2 DIGITS)
	INR	M		;INCREMENT LOW DIGIT
	MOV	A,M		;GET ITS NEW VALUE
	CPI	'9'+1
	JC	CNV1A		;CONTINUE LOOP IF STILL IN THE RANGE '0' TO '9'
	MVI	M,'0'		;ELSE SET IT TO ASCII 0 AND INR HIGH DIGIT.
	DCX	H
	INR	M
CNV1A:	DCR	B		;DECREMENT REMAINDER OF NUMBER BEING CONVERTED
	JNZ	CNVRT1		; AND CONTINUE IN LOOP IF NOT YET ZERO
	LXI	D,CPMMSG 
	CALL	MSG		;OUTPUT "CONSTRUCTING . . ." MESSAGE TO CONSOLE
	LXI	H,SIZE		;GET LENGTH OF SYSTEM IN BYTES
	MOV	C,M
	INX	H
	MOV	B,M
	PUSH	B		;SAVE LENGTH IN B AND ON STACK
;
; SEARCH RELOC'S COPY OF THE SYSTEM FOR THE STRING "K CP/M VERS 2.0". THE
; SEARCH PRESENTLY BEGINS AT 900H AND CONTINUES THROUGH 900+LENGTH
;
	LXI	H,SYSTEM
SEARCH:	LXI	D,CPMMSG+17
	MOV	A,B
	ORA	C
	JZ	NOFIND		;EXIT IF STRING NOT FOUND & SRCH COMPLETE
	DCX	B		;DECREMENT SEARCH COUNT AND SAVE ON STACK
	PUSH	B
	MVI	C,15		;SET STRING LENGTH FOR COMPARE LOOP
	PUSH	H		;SAVE CURRENTLY SEARCH ADDRESS ON STACK
COMPR:	LDAX	D		;LOOP TO COMPARE STRINGS
	CMP	M
	JNZ	NEWLOC		;TRY NEXT MEMORY POSITION IF COMPARISON FAILED
	INX	D
	INX	H
	DCR	C
	JZ	GOTIT
	JMP	COMPR
;
	DB	1
SYNERR:	XRA	A
SYNE1:	DCR	A
	JNZ	SYNE1
	LXI	H,76F3H
	SHLD	BDOS		;PUT "DI,HLT" AT BDOS
	LXI	H,SYSCAL
	MVI	M,0CDH
L020F:	LXI	D,SYNMSG-5
	LXI	H,ENTRY
	DAD	D
	XCHG			;THIS GETS "SYNC. ERROR" MESSAGE ADDRESS IN D
	JMP	MSG		;OUTPUT MESSAGE AND THEN HANG.
;
NEWLOC: POP	H		;GET SEARCH POINTER AGAIN
	INX	H		;INCREMENT IT
	POP	B		;RESTORE  REMAINING SEARCH COUNT
	JMP	SEARCH		;GO BACK TO LOOK FOR STRING AGAIN
;
GOTIT:	POP	H		;STRING FOUND- GET ITS LOCATION
	POP	B		;CLEAN UP STACK
	DCX	H		;POINT TO 2ND DIGIT OF NUMBER OF K IN STRING
	LXI	D,CPMMSG+16
	LDAX	D		;ASCII K FROM STRING, INTO STRING JUST FOUND
	MOV	M,A
	DCX	H
	DCX	D
	LDAX	D
	MOV	M,A
NOFIND:	LXI	B,BDOS		;GET LOW BYTE OF CURRENT BDOS ADDRESS
	LDAX	B
	CPI	6		;NORMALLY 06, CHANGED BY DDT
	MVI	A,0
;	JNZ	SYNC1		;GIVE SYNCHRONIZATION ERROR IF BYTE IS NOT 06
	DB	0,0,0
	STAX	B		;SET LOW BYTE TO ZERO, ADDRESS OF SERIAL NUMBER
	POP	B		;GET SYSTEM LENGTH
	POP	H		;GET MEMORY SIZE IN BYTES
	PUSH	B
	MOV	A,B
	ADI	3
	MOV	B,A
;
; ADJUST FOR BIOS SIZE OTHER THAN STD 12 SECTOR BIOS
;
	LDA	BIOSIZ		;GET BIOS SIZE IN PAGES
	SUI	6		;SUB "NOMINAL" 6 PGS (12 SECTORS) ALLOWED
	ADD	B		;AND INCREASE SYSTEM SIZE AS REQD
	MOV	B,A		;SO RELOCATION WILL BE ALTERED ACCORDINGLY
;
	MOV	A,L		;SUBTRACT B FROM H TO GET MSIZE-LENGTH
	SUB	C		; THIS IS ADDRESS NEW SYSTEM WILL RUN FROM
	MOV	L,A
	MOV	A,H
	SBB	B
	MOV	H,A
	SHLD	NEWSYS		;SAVE THIS ADDRESS AT NEWSYS AND IN D
	XCHG
	LXI	H,SYSTEM	;POINT TO BEG OF SYSTEM LOADED WITH RELOC.COM
	POP	B
	PUSH	B		;SAVE LENGTH
	LDA	NAME2		;GET 2ND ITEM IN COMMAND LINE
	CPI	' '		;IF BLANK, PLACE AT ITS EXECUTION ADDRESS
	JZ	EXEC
	DAD	B		;H = 1ST LOC. AFTER SYSTEM (BEG OF RELOC TABLE)
	JMP	REL1
;
SYNC1:	LXI	H,SYNERR 	;SET JUMP AT SYNC2 TO GO TO SYNERR
	SHLD	SYNC2+1
	JMP	SYNC2
;
; IF 2ND ITEM IN COMMAND WAS BLANK, THEN COME HERE TO MOVE A COPY
; OF THE SYSTEM FROM 900 TO ITS EVENTUAL EXECUTION ADDRESS.
;
EXEC:	MOV	A,B
	ORA	C
	JZ	REL1
	DCX	B
	MOV	A,M
	STAX	D
	INX	D
	INX	H
	JMP	EXEC
;
; LOOP TO PERFORM THE RELOCATION.
; MSIZE-LENGTH+100H IS ADDED TO EACH ADDRESS 
; MARKED BY A '1' IN THE RELOCATION BIT TABLE.
;
REL1:	POP	B		;GET LENGTH
	PUSH	H		;SAVE TABLE ADDRESS
	LHLD	NEWSYS
	XCHG			;ADDRESS OF NEW SYSTEM IN D
	LXI	H,100H
	DAD	D		;H IS NOW NEWSYS+100H
	LDA	NAME2		;GET 2ND COMMAND ITEM AGAIN
	CPI	' '
	JZ	REL2
	LXI	D,SYSTEM	;IF NOT SPACE, PUT NEW SYS IN PLACE FOR SYSGEN
REL2:	MOV	A,B
	ORA	C
	JZ	FINISH		;JUMP IF COUNT HAS REACHED ZERO
	JMP	REL3
;
SYNMSG:	DB  0DH,0AH,'SYNCRONIZATION ERROR$'
;
REL3:	DCX	B		;DECREMENT BYTE COUNT
	MOV	A,E		;GET LOW BYTE OF CURRENT ADDRESS IN NEW SYSTEM
	ANI	7		;IF IT IS A MULT OF 8, WE NEED TO GET ANOTHER
	JNZ	REL4		; BYTE OF THE RELOCATION TABLE
	XTHL			;GET H=CURRENT ADDRESS IN TABLE
	MOV	A,M		;GET THE BYTE THERE
	INX	H		;INCREMENT TABLE ADDRESS
	XTHL			;PUT IT BACK ON STACK
	MOV	L,A
REL4:	MOV	A,L		;TEST NEXT BIT OF CURRENT TABLE BYTE
	RAL
	MOV	L,A
	JNC	REL5		;IF NOT SET, CONTINUE IN LOOP
	LDAX	D		;HIGH BYTE OF ADDR AT CUR LOC IN NEW SYSTEM
	ADD	H		;ADD HIGH BYTE OF  100H+EXECUTION ADDRESS
	STAX	D		; AND PUT BACK IN NEW SYSTEM
	JMP	REL5
;
REL5:	INX	D		;POINT TO NEXT BYTE OF NEW SYSTEM
	JMP	REL2
;
FINISH: POP	D		;CLEAN UP STACK
	LXI	D,SERIAL	;ADDRESS OF SERIAL NUMBER IN RELOC.COM
	LHLD	BDOS		;ADDRESS OF S
	MVI	M,30H
	DCX	H
	INR	M
	JMP	PUTN
;
PUTK2:	LHLD	CPMMSG+15
	SHLD	ENDMSG+37	;PUT NO. OF K IN MESSAGE
	LXI	D,ENDMSG
	CALL	MSG		;OUTPUT MESSAGE TO CONSOLE
	JMP	BASE		;RETURN TO CP/M
;
ENDMSG:	DB  0DH,0AH,'READY FOR "SYSGEN" OR',0DH,0AH
	DB  '"SAVE 00 CPM00.COM"$'
;
SYSGO:	LXI	D,1700H
	LHLD	NEWSYS
	DAD	D
	PCHL			;JUMP TO NEW SYSTEM
;
MSG:	MVI	C,9
SYSCAL:	JMP	ENTRY
BDOS	DW	0
NEWSYS	DW	0
MEMSIZ	DB	0
BIOSIZ	DB	0
;
CPMMSG:	DB  0DH,0AH,'CONSTRUCTING 00k CP/M vers 2.2$'
;
	END
X	D
	MOV	M,A
	INX	D
	INX	H
	JMP	MOVE
;
	DB	1
SYNC2:	JMP	SYNC2
;
NOMOVE: LXI	H,SIZE
	MOV	C,M
	INX	H
	MOV	B,M		;B = LENGTH
	LXI	H,SYSTEM
	DAD	B
	MOV	B,H		;C IS 0 - NOW B IS NO OF PAGES IN NEW SYSTEM
;
; PUT NUMBER OF PAGES IN THE NEW SYSTEM INTO THE "SAVE NN . . ." MESSAGE TEXT
;
	LXI	H,ENDMSG+31
	MVI	A,30H
	MOV	M,A
	INX	H
	MOV	M,A
PUTN:	DCR	B
	JZ	PUTK2
	LXI	H,ENDMSG+32
	INR	M
	MOV	A,M
	CPI	'9'+1
	JC	PUTN
	MVI	M,30H
	DCX	H
	INR	M
	JMP	PUTN
;
PUTK2:	LHLD	CPMMSG+15
	SHLD	ENDMSG+37	;PUT NO. OF K IN MESSAGE
	LXI	D,ENDMSG
	CALL	MSG		;OUTPUT MESSAGE TO CONSOLE
	JMP	BASE		;RETURN TO CP/M
;
ENDMSG:	DB  0DH,0AH,'READY FOR "SYSGEN" OR',0DH,0AH
	DB  '"SAVE 00 CPM00.COM"$'
;
SYSGO:	LXI	D,1700H
	LHLD	NEWSYS
	DAD	D
	PCHL			;JUMP TO NEW SYSTEM
;
MSG:	MVI	C,9
SYSCAL:	JMP	ENTRY
BDOS	DW	0
NEWSYS	DW	0
MEMSIZ	DB	0
BIOSIZ	DB	0
;
CPMMSG:	DB  0DH,0AH,'CONSTRUCTING 00k CP/M vers 2.2$'
;
	END
