	title	'Add bios8502 to CPM3.SYS file      2 June 85'

	maclib	seqio

	lxi	sp,stack
	call	disp$sign$on

	FILE	outfile,CPM,,CPM+,SYS,16*1024
	FILE	infile,CPM3,,CPM3,SYS,4*1024
	FILE	infile,BIOS8502,,1,HEX,1024
	FILE	infile,KEYS,,CXKYCODE,HEX,1024

	lxi	h,load$bios$msg
	call	disp$loop
	call	load$bios$8502		; load hex file to buffer

	lxi	h,load$key$msg
	call	disp$loop
	call	load$keys		; load hex file to buffer

	lxi	h,add$vect$msg
	call	disp$loop
	call	add$vectors		; add the new vector pointers

	lxi	h,inst$key$msg
	call	disp$loop
	call	insert$key$defs		; add FUNCTION KEYS and KEY definition

	lxi	h,inst$cpm$msg
	call	disp$loop
	call	finish$rest		; transfer rest of system over

	lxi	h,inst$bios$msg
	call	disp$loop
	call	add$bios$8502		; save bios8502 to CP/M file

	lxi	h,closing$msg
	call	disp$loop
	finis	CPM

	jmp	0			; exit back to CP/M

	page
load$bios$msg:
	db	'Loading 8502 BIOS .HEX file',cr,lf,0

load$key$msg:
	db	'Loading Key definition .HEX file',cr,lf,0

add$vect$msg:
	db	'Adding new vectors to CPM+.SYS',cr,lf,0

inst$key$msg:
	db	'Adding Key def. to CPM+.SYS',cr,lf,0

inst$cpm$msg:
	db	'Adding CPM3.SYS to CPM+.SYS',cr,lf,0

inst$bios$msg:
	db	'Adding BIOS8502 to CPM+.SYS',cr,lf,0

closing$msg:
	db	'Closing CPM+.SYS file',cr,lf,lf,lf,0

	page
;;
;;
;;
load$bios$8502:
	xra	a
	sta	file$num		; use bios8502 file for HEX input

	call	read$header		; get BIOS8502 start adr
	mov	a,l			; LSB should be zero
	ora	a
	jnz	adr$error
	push	h
	mov	a,h
	sta	bios$addr
	cma
	mov	h,a
	inr	h			; two's comp of start adr
	lxi	d,buffer$bios$8502
	dad	d
	shld	bias
	pop	h
	call	finish$load
hex$load:
	jc	done$bios8502		; done when carry set
	call	load$record
	jmp	hex$load

done$bios$8502:
	lhld	hex$addr		; get last address
	lxi	d,buffer$bios$8502
	mov	a,l
	sub	e
	mov	l,a
	mov	a,h
	sbb	d
	mov	h,a

	mov	a,l
	ora	a
	jz	size$ok
	inr	h
size$ok:
	mov	a,h
	sta	bios$size
	cpi	4096/256
	jnc	size$error
	ret

	page

load$keys:
	mvi	a,-1
	sta	file$num		; use KEYS file for HEX input

	call	read$header		; get KEYS start adr
	mov	a,l			; LSB should be zero
	ora	a
	jnz	adr$error
	push	h
	mov	a,h
	sta	keys$addr
	cma
	mov	h,a
	inr	h			; two's comp of start adr
	lxi	d,buffer$keys
	dad	d
	shld	bias
	pop	h
	call	finish$load
hex$load$keys:
	jc	done$keys		; done when carry set
	call	load$record
	jmp	hex$load$keys

done$keys:
	lhld	hex$addr		; get last address
	dcx	h
	dcx	h			; two byte header for key def adr 
	lxi	d,buffer$keys
	mov	a,l
	sub	e
	mov	l,a
	mov	a,h
	sbb	d
	mov	h,a

	mov	a,l
	ora	a
	jz	keys$size$ok
	inr	h
keys$size$ok:
	mov	a,h
	sta	keys$size
	cpi	(1024/256)+1
	jnc	size$error
	ret

	page

;;
;;
;;
add$vectors:
	mvi	b,6			; use first 6 bytes of old header
get$1st:
	push	b			; read in the header info
	GET	CPM3
	PUT	CPM
	pop	b
	dcr	b
	jnz	get$1st

;			remove next six bytes from old header 
	get	CPM3			; bios8502 top page #
	get	CPM3			; bios8502 # of blocks (256 bytes)
	get	CPM3			; KEYS bottom page # (function key adr)
	get	CPM3			; KEYS # of blocks (256 bytes)
	get	CPM3			; key definition adr (low)			
	get	CPM3			; key definition adr (high)

	lda	bios$size		; install load info into header
	mov	b,a
	lda	bios$addr
	add	b
	put	CPM			; bios8502 top page #
	mov	a,b
	put	CPM			; bios8502 # of (256 byte) blocks

;
;	install MSG tbl and FUN tbl pointers
;
	lda	keys$addr
	put	CPM			; function key start adr (high only)
	lda	keys$size
	put	CPM			; KEYS # of (256 byte) blocks

	lhld	buffer$keys
	mov	a,l
	push	h
	put	CPM			; key definition adr (low)
	pop	h
	mov	a,h
	put	CPM			; Key definition adr (high)


;
;	only move 256 bytes total  (128 bytes info, 128 message)
;
	mvi	b,256-6-6		; number of bytes left to move
get$2nd:
	push	b			; read in the header info
	GET	CPM3
	PUT	CPM
	pop	b

	dcr	b
	jnz	get$2nd
	ret

	page

;;
;;	add FUNCTION KEYS and KEY definition
;;
insert$key$defs:
	lxi	h,buffer$keys+2		; 1st two bytes point to the
					; ..key definition
insert$keys$loop:
	mvi	c,0			; save 256 bytes
	call	save$loop
	lda	keys$size
	dcr	a
	sta	keys$size
	jnz	insert$keys$loop
	ret




;;
;;	transfer rest of system over
;;
finish$rest:
	get	CPM3			; save CPM3.SYS to CPM.SYS
	rz
	put	CPM
	jmp	finish$rest

	page
;;
;;
;;
add$bios$8502:
	lda	bios$size
	mov	h,a
	mvi	l,0
	lxi	d,buffer$bios$8502
	xchg
	dad	d			; HL=next free address DE=size
	mov	a,d			; number of 256 byte blocks
	add	a			; number of 128 byte blocks
	mov	d,a			; save count in D
save$next:
	lxi	b,-128
	dad	b			; back up the pointer
	push	h
	push	d
	call	save$128$bytes
	pop	d
	pop	h
	dcr	d
	jnz	save$next
	ret

;
;
;
save$128$bytes:
	mvi	c,128
save$loop
	mov	a,m
	push	h
	put	CPM
	pop	h
	inx	h
	dcr	c
	jnz	save$loop
	ret


	page
;
;
;
load$record:
	call	read$header		; record adr in HL
finish$load:
	xchg
	lda	hex$count
	cpi	0+1			; see if length=0
	stc				; set END OF FILE
	rz				; null record marks the end
	lhld	bias
	dad	d
	shld	hex$addr
	call	read$byte		; this byte should be a zero
	ana	a
	jnz	hex$error

hex$record$read:
	lda	hex$count
	dcr	a
	sta	hex$count
	jz	hex$record$done
	call	read$byte
	lhld	hex$addr
	mov	m,a
	inx	h
	shld	hex$addr
	jmp	hex$record$read


hex$record$done:
	call	read$byte
	lda	hex$sum
	ana	a			; clears carry (marks end of record)
	jnz	hex$error
	ret




read$header:
	xra	a
	sta	hex$sum
	call	read$hex$byte		; get input character
	jz	hex$error		; missing char is a problem
	cpi	':'
	jnz	read$header
	call	read$byte		; get record length
	inr	a
	sta	hex$count

	call	read$byte		; get high address
	mov	h,a
	push	h
	call	read$byte		; get low address
	pop	h
	mov	l,a
	ret

read$byte:
	call	read$hex$val		; get a hexadecimal value
	rlc
	rlc
	rlc
	rlc				; move to upper 4 bits
	push	psw
	call	read$hex$val		; get a hexadecimal value
	mov	b,a
	pop	psw
	ora	b			; make a data byte from two hex digits
	mov	b,a
	lda	hex$sum			; add to sum
	add	b
	sta	hex$sum
	mov	a,b			; return byte value
	ret

read$hex$val:
	call	get$upper		; force to upper case
	mov	b,a
	sui	'0'			; remove number bias
	jm	hex$error
	cpi	9+1			; return if a number
	rc
	sui	'A'-'0'			; remover extra if A to F
	jm	hex$error
	adi	10
	cpi	0fh+1
	rc				; return if valid hex number (0-F)
hex$error:
	lxi	h,hex$mess
	jmp	dsp$and$exit


get$upper:
	call	read$hex$byte
	jz	hex$error
	cpi	'a'
	rc
	ani	5fh
	ret

read$hex$byte:
	lda	file$num
	ora	a
	jz	read$hex$fst
	get	KEYS
	ret

read$hex$fst:
	get	BIOS8502
	ret



adr$error:
	lxi	h,adr$mess
	jmp	dsp$and$exit

size$error:
	lxi	h,size$mess
dsp$and$exit:
	call	disp$loop
	jmp	0



	page

disp$sign$on:
	lxi	h,message
disp$loop:
	mov	a,m
	ora	a
	rz
	inx	h
	push	h
	PUT	CON
	pop	h
	jmp	disp$loop



message:
	db	cr,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf,lf
	db	'     This program will create a CPM+.SYS file from',cr,lf
	db	'      The CPM3.SYS file (created by GENCPM) and',cr,lf
	db	'      The 6502 BIOS File supplied in Intel HEX format',cr,lf
	db	'      And CXKYCODE File supplied in Intel HEX format',cr,lf
	db	'        (1st HEX address is FUNCTION table address)',cr,lf
	db	'        (1st two bytes point to ASCII table)',cr,lf
	db	lf,lf
	db	'     The ROM boot code will load the CPM+.SYS file',cr,lf,lf
	db	0

hex$mess:
	db	'HEX file error -  first record must be start adr and',cr,lf
	db	'                  last record must contain the last adr'
	db	cr,lf
	db	'                  All other address must be between',cr,lf
	db	'                  the start and end adr',cr,lf
	db	' also HEX file must be ended with a NULL record',cr,lf,lf
	db	' and '
adr$mess:
	db	'Start address must be on a page boundary',cr,lf,lf
	db	' and '
size$mess:
	db	'File can NOT be larger than 4K',cr,lf,0


keys$size:	ds	1
keys$addr:	ds	1

bios$size:	ds	1
bios$addr:	ds	1

bias:		ds	2
hex$count:	ds	1
hex$addr:	ds	2
hex$sum:	ds	1
file$num:	ds	1

buffer$bios$8502:
		ds	4096
buffer$keys:
		ds	1024+2
		ds	60
stack:
buffers		equ	stack

	end

