
	title	'CP/M 3 ROM loader        13 May 85'


	maclib	z80

	maclib	cpm3

	maclib	cxequ

	maclib	x6502


boot$8502	equ	1100h
lines		equ	24		; number of user lines on screen(s)


rownum	macro	row,col
	db	row+80h,col
    endm



;
;	power on location
;
	org	00h		; RST 0

	mvi	a,3eh
	sta	force$map
	jmp	power$up		; continue init somewhere else


;
;	boot CP/M entry point
;
;	org	08h		; RST 1

	lxi	sp,boot$stack
	mvi	a,3Fh			; MMU enable RAM bank 0 no I/O
	jmp	loader$start

	page
;
;	* TJMP *	user to jmp to a Terminal ROM routine
;		user code:
;			RST	2
;			db	fun#	(0,4,8,C,....,44)
;
;	org	10h		; RST 2

	pop	h
	mov	l,m
	jmp	020h
	nop
	nop
	nop

;
;	* RJMP *	user to jmp to a ROM routine
;		user code:
;			RST	3
;			db	fun#
;
;	org	18h		; RST 3

	pop	h			; get the return address
	mov	l,m			; get user function # (0,2,...,fe)
	jmp	028h			; 
	nop
	nop
	nop

	page
;
;	* TCALL *	used to call a Terminal ROM routine
;		user code:
;			mvi	l,fun#	(0,4,8,C,....,44)
;			RST	4
;
;	org	20h		; RST 4

	lda	fun$offset		; =0 if 80 column, <>0 if 40 column
	ana	a			; is this an 80 column function?
	jrz	28h			; yes, no offset required
	inr	l			; no, advance to next vector
	inr	l


;
;	* RCALL *	used to call a ROM routine
;		user code:
;			mvi	l,fun#	(0,2,4,6,.....,7E)
;			RST	5
;
;	org	28h		; RST 5

	mvi	h,01h			; vectors on page 1
	mov	a,m
	inx	h
	mov	h,m
	mov	l,a
	pchl
	nop

	page
;
;	RST 6 is NOT defined.. this area is used for the ROM date
;	ONLY....
;
;	org	30h		; RST 6

	db	'05/12/85'


;	org	38h		; RST 7 (interrupt mode 1 start adr)
	jmp	0fdfdh

	page
;
;
;
power$up:
	lxi	b,VIC$key$row
	lxi	d,0fffch		; D=ff, E=fc
	outp	d			; set extra 3 scan lines off
	inx	b			; point to clock speed reg
	outp	e			; bits 7-2 unused
					; bit 1  enable test mode (1)
					; bit 0  2 Mhz (1) / 1 MHz (0)  
;
;	continue the check to see if a C64 type chartrage is installed
;	(EXROM or GAME active) if so we enter C64 mode
;
	lxi	b,mode$reg		; get EXROM and GAME bits
	mvi	a,z80$on
	outp	a			; set bit high
	inp	a			; see if they went high
	cma				; make highs low
	ani	30h			; EXROM or GAME enabled?
	jrz	test$key		; no, now test the commodore key

;
;	This is a one way trip, no return flights.
;	Thus we do not have to do the transfer from RAM
;	(as in C128 mode).  We just enable C64 and run. 
;
go$c64:
	mvi	a,enable$c64
	outp	a
					; should never get here
	RST	0			; unless there are hardware problems

	page

test$key:
	lxi	b,0dc0fh		; D1CRB
	mvi	a,8h			; turn off timers
	outp	a
	dcr	c			; D1CRA
	outp	a

	mvi	c,03h			; D1DDRB = inputs
	xra	a			; A=00
	outp	a
	dcr	c			; D1DDRA = outputs
	dcr	a			; A=FF
	outp	a
	dcr	c			; dc01
	dcr	c			; dc00
	mvi	a,01111111b		; bit 7 for commodore key
	outp	a
	inx	b			; dc01 point to key$col
	inp	a
	ani	commodore$key
	lxi	b,mode$reg
	jrz	go$c64

go$c128:
;
;	set MMU registers to a known state
;
	lxi	h,mmu$init$data+11-1	; start at the End
	lxi	b,mmu$start+11-1	; and work forward
	mvi	d,11			; for all 11 bytes

init$mmu$next:
	mov	a,m			; get table value
	outp	a			; send to MMU
	dcx	h
	dcr	c
	dcr	d
	jrnz	init$mmu$next


;
;	install 8502 code that will enable C128 mode and 
;	execute at the location pointed to by FFFC (reset vector)
;
	lxi	h,boot$02$code
	lxi	d,boot$8502
	lxi	b,boot$size
	ldir

	lxi	h,swap$code
	lxi	d,enable$z80
	lxi	b,swap$size
	ldir

;
;	Get ready to enter C128 mode.  Install vectors in ram that will
;	force the processor to execute RAM code in low memory.
;	The RAM code in low memory ENABLES the kernal and does
;	an indirect JMP to FFFC (reset vector).
;
	lxi	h,boot$8502		; C128 start adr
	shld	0fffah			; install NMI vector
	shld	0fffch			; install RESET vector
	shld	0fffeh
	shld	return$z80+1
	jmp	enable$6502

	page
;
;	scan buffer for CPM+.SYS file
;
scan$dir:
	call	update$buffer		; returns HL=block$buffer
	lda	block$size		; 32 for 1K block, 64 for 2K block
					; ..number director entries/sector

check$next:
	shld	@dma
	lxi	d,sys$name		; point to system name
	push	psw
	call	name$match
	cz	found
	pop	psw
	lhld	@dma			; get current buffer pointer
	lxi	d,32
	dad	d
	dcr	a
	jrnz	check$next
	ret

	page
;
;	compare the strings (11 bytes each) pointed to by
;	DE and HL. Return with Zero flag set if equal.  
;
name$match:
	mvi	b,12			; number of bytes to match
 	xchg				; [HL]=search name  [DE]=dir entry

match$next:
	ldax	d			; get string 1 character
	ani	7fh			; remove any attr.
	cmp	m			; compare to string 2
	rnz				; exit if they don't match

	inx	h
	inx	d
	djnz	match$next

	lda	block$size		;
	cpi	64			; 2K block?
	ldax	d			; get the dir ext#
	jrnz	ext$1k			; no, ext # ok
					; yes, (carry=0)
	rar				; divide by 2, ext could be 0 or 1
					; ..for the 1st and 2 or 3 for the
ext$1k:					; ..second entry
	sta	ext$num
null$code:
	xra	a			; return with zero flag set 
	ret

	page
;
;
;
sys$name:
		;  12345678901
	db	0,'CPM+    SYS'		; must be in user 0's space

	db	0
;
;
;
;	org	0100h-6
cmp$hl$de:
	mov	a,h
	cmp	d
	rnz
	mov	a,l
	cmp	e
	ret

	page

;	org	0100h

	dw	wr$char$80		; function # 00
	dw	wr$char$40		; function # 02
	dw	crs$pos$80		; function # 04
	dw	crs$pos$40		; function # 06
	dw	crs$up$80		; function # 08
	dw	crs$up$40		; function # 0A
	dw	crs$down$80		; function # 0C
	dw	crs$down$40		; function # 0E

	dw	crs$left$80		; function # 10
	dw	crs$left$40		; function # 12
	dw	crs$rt$80		; function # 14
	dw	crs$rt$40		; function # 16
	dw	crs$cr$80		; function # 18
	dw	crs$cr$40		; function # 1A
	dw	CEL$80			; function # 1C
	dw	CEL$40			; function # 1E

	dw	CES$80			; function # 20
	dw	CES$40			; function # 22
	dw	char$ins$80		; function # 24
	dw	char$ins$40		; function # 26
	dw	char$del$80		; function # 28
	dw	char$del$40		; function # 2A
	dw	line$ins$80		; function # 2C
	dw	line$ins$40		; function # 2E

	dw	line$del$80		; function # 30
	dw	line$del$40		; function # 32
	dw	set$color$80		; function # 34
	dw	set$color$40		; function # 36
	dw	set$attr$80		; function # 38
	dw	set$attr$40		; function # 3A
	dw	rd$chr$80		; function # 3C
	dw	rd$chr$40		; function # 3E

	page

	dw	wr$chr$80		; function # 40
	dw	wr$chr$40		; function # 42
	dw	rd$color$80		; function # 44
	dw	rd$color$40		; function # 46
	dw	null$code		; function # 48
	dw	null$code		; function # 4A
	dw	null$code		; function # 4C
	dw	null$code		; function # 4E

	dw	convert$record		; function # 50
	dw	check$cbm		; function # 52
	dw	bell			; function # 54
	dw	null$code		; function # 56
	dw	null$code		; function # 58
	dw	null$code		; function # 5A
	dw	null$code		; function # 5C
	dw	null$code		; function # 5E

	dw	trk$40			; function # 60
	dw	set$cursor$40		; function # 62
	dw	line$paint		; function # 64
	dw	screen$paint		; function # 66
	dw	prt$msg$both		; function # 68
	dw	prt$de$both		; function # 6A
	dw	update$it		; function # 6C
	dw	null$code		; function # 6E

	dw	ASCII$to$petASCII	; function # 70
	dw	cur$adr$40$hl$sz$a	; function # 72
	dw	cur$adr$80$hl$sz$a	; function # 74
	dw	lookup$color		; function # 76
	dw	null$code		; function # 78

	dw	blk$fill		; function # 7A  ret adr, HL on stack
	dw	blk$move		; function # 7C  ret adr, HL on stack
	dw	char$install$gp		; function # 7E  ret adr, HL on stack

;	the last 3 function are called by 1st pushing HL on the stack
;	and then doing the call
;		user code as follows:
;			lxi	h,xyz		; value to be passed in HL 
;			push	h		; extra value on stack
;			RCALL	....
;						; stack clean

	page
;
;	org	180h
;
	jmp	write$memory
	jmp	read$memory
	jmp	set$update$adr
	jmp	wait

;
;
;
loader$start:
;
;	setup the MMU for booting CP/M
;
	sta	force$map

;
;	clear bank 0 RAM 3000h to feffh. This is the system area. 
;
	lxi	h,3000h
	lxi	d,3001h
	lxi	b,0ff00h-3000h-1
	mov	m,l
	ldir

;
;	move bios and swap code into ram
;
	lxi	h,bios$65$code
	lxi	d,bios$02
	lxi	b,bios$size
	ldir

	lxi	h,swap$code
	lxi	d,enable$z80
	lxi	b,swap$size
	ldir

	mvi	a,RET			; get z80 return adr
	sta	return$6502		; store the RET

;
;	initilize the 8502 bios
;
; xra	a				; cleared by memory fill
; sta	vic$cmd
	call	enable$6502

	page
;
;	set MMU registers to a known state (for CP/M to use)
;
	lxi	h,mmu$init$data+11-1	; start at the End
	lxi	b,mmu$start+11-1	; and work forward
	mvi	d,11			; for all 11 bytes

init$mmu$cpm:
	mov	a,m			; get table value
	outp	a			; send to MMU
	dcx	h
	dcr	c
	dcr	d
	jrnz	init$mmu$cpm
					; re-enabled RAM bank 0 (no I/O)
;
;	Clear the work area
;
	lxi	h,1000h
	lxi	d,1000h+1
	lxi	b,3000h-1000h-1		; number of bytes to clear
	mov	m,l			; clear the 1st one
	ldir				; copy 1st to all

	page
;
;	set 80 column colors and set up Video memory with ASCII char set
;
	mvi	a,26
	call	wait
	mvi	a,90h			; foreground red background black
	outp	a
	mvi	a,83h			; set attr and color (lt. blue)
	sta	current$atr		; ..for 80 column display
	mvi	a,0eh			; set color (lt. blue)
	sta	attr$40			; ..for 40 column display
	call	install$ASCII		; convert char set to true ASCII

	mvi	a,25			; number of lines on the 40 col display
	sta	paint$size
;
;	Let the user know we are booting CP/M
;
	call	prt$msg$both
	db	-1			; clear both screens
	rownum	1,10
	db	'BOOTING CP/M PLUS',0

;
;	point 40 column screen to CP/M screen area
;
	lxi	b,VIC+24
	mvi	a,vic$screen*4/256+6	; upper and lower case set (+6)
	outp	a

	page

	call	check$dsk		; is this a C128 disk ?
	jnz	tell$user		; no, tell the user
;
;
;
	lxi	h,dir$ptrs
	shld	ld$blk$ptr
	call	scan$dir		; check 1st block
	call	scan$dir		; check 2nd block (1K or 2K)

	lhld	block$ptrs		; 1st pointer <>0 if file
	mov	a,h			; name exist
	ora	l			; pointer = 0
	jz	tell$user		; yes, inform user there is a error
					; no, file found, process it
	page
;	*************************************************
;	*						*
;	*	load 1st group to 1K buffer		*
;	*						*
;	*************************************************

;
;
;
file$found:
	lxi	h,block$ptrs
	shld	ld$blk$ptr
	call	update$buffer


;	*************************************************
;	*						*
;	*	extract boot info			*
;	*						*
;	*************************************************

;
;
;
get$boot$info:
	lxi	h,block$buffer
	lxi	d,info$buffer
	lxi	b,12
	ldir

	call	prt$msg$both
	rownum	10,0
	db	0			; end of string marker
	lxi	h,block$buffer+80h
	call	prt$hl$both

	lxi	h,block$buffer+256	; set scan pointer
	shld	blk$unld$ptr

	page
;	*************************************************
;	*						*
;	*	load keyboard data to system RAM	*
;	*						*
;	*************************************************

	call	prt$msg$both
	rownum	3,12
;	db	'LOADING DATA TABLES',0
	db	'DATA TABLES',0
	lhld	info$buffer+10
	shld	key$tbl			; install keyboard translation pointer

	lxi	h,info$buffer+9
	call	get$size$adr		; HL=adr DE=# (128 btye) records 
	shld	fun$tbl

load$next$forward:
	call	load$record		; HL =load address (in and out)
	lxi	d,128			; move pointer back to buf start
	dad	d
	jrnz	load$next$forward


	page
;	*************************************************
;	*						*
;	*	transfer CP/M code to load address	*
;	*						*
;	*************************************************
;
;
;
load$common:
	call	prt$msg$both
	rownum	4,12
;	db	'LOADING COMMON CODE',0
	db	'COMMON CODE',0
	lxi	h,info$buffer+1		; load common code
	call	load$reverse


	call	prt$msg$both
	rownum	5,12
;	db	'LOADING BANKED CODE',0
	db	'BANKED CODE',0
	lxi	h,info$buffer+3		; load banked code
	call	load$reverse

	page
;	*************************************************
;	*						*
;	*	now load the bios8502 code		*
;	*						*
;	*************************************************

	call	prt$msg$both
	rownum	6,12
;	db	'LOADING BIOS8502 CODE',0
	db	'BIOS8502 CODE',0
	lxi	h,info$buffer+7		; load banked code
	call	load$reverse

	lda	info$buffer+7		; get code size (in 256 byte blocks)
	mov	b,a
	lda	info$buffer+6		; get page pointer (pointer to end)
	sub	b			; find the start

					; install jmp adr to BIOS02
	sta	return$z80+2		; (jmp) (low) (high)
	xra	a
	sta	return$z80+1		; (jmp) (low) (high)


;	*************************************************
;	*						*
;	*	now let's start executing CP/M Plus	*
;	*						*
;	*************************************************

	lhld	info$buffer+4		; get start address
	pchl				; transfer control to CP/M

	page
;	*********************************
;	-				-
;	-	   SUBROUTINES		-
;	-				-
;	*********************************

;
;	returns with zero flag set if bootable disk in drive
;
check$dsk:
	lxi	h,@buffer
	shld	@dma
	xra	a
	sta	vic$sect		; set track 1 sector 0 (1st sector
	inr	a			; on the disk)
	sta	vic$trk
	call	read$sector		; a=0 if no errors
	call	check$cbm		; disk have CBM in first sector ?
	rnz				; no, exit
	inr	a			; yes, is it double sided?
	lxi	h,block$buffer+1024	;   buffer end address (1K blocks)
	mvi	a,32			;   number of dir entries per block
	jrnz	set$block$size		;  yes, set it
					;  no, set 2K block parameters
	mvi	h,high(block$buffer+2048)
	add	a			; 64 dir entries

set$block$size
	shld	block$end
	sta	block$size		; 32=1K,  64=2K (# dir entries/block)
	xra	a			; set zero flag (is CP/M disk)
	ret

	page
;	*************************************************
;	-						-
;	-	save CPM+.SYS group numbers		-
;	-						-
;	*************************************************
;
;	found a dir entry that has the right name
;	add block pointers to list
;
found:
	lxi	d,block$ptrs		; point to start of block pointers
	lda	ext$num
	ora	a
	jrz	ext$num$0

	lxi	d,block$ptrs+16
	dcr	a
	jnz	ext$error

ext$num$0:
	lhld	@dma			; get current pointer

	lxi	b,16			; number of bytes to move
	dad	b			; also advance to block pointers
	ldir

	lda	block$ptrs
	ora	a			; 1st block present ?
	rz				; no, read more dir.

	lhld	block$ptrs+15		; extent full?
	xra	a			; get a zero
	cmp	l			; cmp to block$prt+15
	jrz	go$boot$it		; no, this is it then

	cmp	h			; cmp to block$prt+16
					; 2nd block present ?
	rz				; no, read more dir.

go$boot$it:
	jmp	file$found		; two parms are still on the stack
					; but at this point who cares

	page
;
;
;
load$reverse:
	call	get$size$adr		; HL=adr DE=# records (128 byte)

load$next:
	lxi	d,-128			; move pointer back to buf start
	dad	d
	call	load$record
	jrnz	load$next
	ret

;
;
;
get$size$adr:
	mov	e,m
	mvi	d,0			; get buffer size (#256 byte)
	mov	a,e			; get size to A
	ora	a
	jz	table$error		; exit if count=0

	xchg
	dad	h			; HL=#128 byte blocks
	shld	load$count
	xchg
	dcx	h
	mov	h,m
	mvi	l,0
	ret

	page
;
;
;
load$record:
	push	h			; save to address
	lhld	block$end		; get buffer end adr	
	xchg
	lhld	blk$unld$ptr
	call	cmp$hl$de
	cz	update$buffer
	xchg
	lxi	h,128
	dad	d
	shld	blk$unld$ptr
	pop	h			; recover save address
	push	h
	xchg				; HL=source  DE=dest.
	lxi	b,128			; size of move
	ldir
	lhld	load$count
	dcx	h
	shld	load$count
	mov	a,l
	ora	h
	pop	h
	ret

	page
;
;
;
update$buffer:
	lxi	h,block$buffer
	shld	@dma
	push	h			; save block buffer adr for ret
	lhld	ld$blk$ptr		; get the current block pointer
	mvi	d,0			; zero MSB of block pointer
	mov	e,m			; get LSB of block pointer
	inx	h			; advance pointer
	shld	ld$blk$ptr
	xchg				; get block number to HL
;
;	read the block pointed to by the HL
;	into the data buffer
;
	dad	h			; 2x
	dad	h			; 4x 256=1K
	lda	block$size		; =32 for 1K, =64 for 2K
	rrc
	rrc
	rrc				; 32/8=4,  64/8=8
	cpi	32/8			; 1K block size?
	jrz	is$1K$block
	dad	h			; 8x 256=2K
is$1K$block:
	shld	@trk
next$block:
	dcr	a			; 3 or 7 sectors left to read
	sta	vic$count		; ..1st sector is read anyway
	push	psw
	mvi	a,1
	sta	F$rd$count+BB		; 

	call	convert$record		; set track, sector (adjust for offset)
	lhld	@trk
	inx	h
	shld	@trk			; save for later
	pop	psw
	jrz	rd$1541

	lda	fast
	ana	a			; 0=1541,  0<>1571
	jrz	rd$1541

	lhld	vic$trk			; get track and sector #
	push	h			; save on stack
check$next$trk:
	call	convert$record		; convert next track and sector
	pop	h			; recover 1st trk and sector #

	lda	vic$trk			; get trk$number
	cmp	l			; same trk as 1st sector
	jrnz	not$same$trk

	push	h			; resave 1st trk and sect
	lhld	@trk
	inx	h
	shld	@trk
	lxi	h,F$rd$count+BB
	inr	m
	lxi	h,vic$count
	dcr	m
	jrnz	check$next$trk
	pop	h

not$same$trk:
	shld	vic$trk			; save the 1st track sector #
rd$1541:
	call	read$sector		; read the sector to the buffer
	lxi	h,@dma+1		; point to dma high byte
	lda	F$rd$count+BB
	add	m
	mov	m,a			; adjust for next read
	lda	vic$count
	ana	a			; test if all sectors read?
	jrnz	next$block		; no loop back

	pop	h			; recover block buffer adr
	ret

	page
;
;	convert block number to sector and track
;
convert$record:
	mvi	a,35
	sta	temp$1			; store a track offset of 35
	lhld	@trk			; get start block #
	lxi	d,680			; 0 to 680 sectors per side
	ora	a			; clear the carry
	dsbc	d			; negative if <680
	jrnc	side$1			; jump if still positive >=680
	xra	a			;
	sta	temp$1			; store a track offset of 0
	dad	d			; add it back

side$1:
	inx	h			; skip 1st sector (both sides)
	inx	h			; skip 2nd sector (both sides)
	lxi	d,357			; get first value to subtract
	lxi	b,21*256+1-1		; b=sectors/track c=track offset-1
	ora	a			; clear the carry bit
	dsbc	d			; 
	jrc	too$much		; 
	inx	h			; add 1 to skip track 18 sector 0
	lxi	d,490-357		; get first value to subtract
	lxi	b,19*256+18-1		; b=sectors/track c=track offset-1
	dsbc	d			; 
	jrc	too$much		; 
	lxi	d,598-490		; get first value to subtract
	lxi	b,18*256+25-1		; b=sectors/track c=track offset-1
	dsbc	d			; 
	jrc	too$much		; 
	lxi	d,0
	lxi	b,17*256+31-1		; b=sectors/track c=track offset-1

	page
;
;	at this point B= number of sectors/track and C=track offset
;	after DE is added back to HL (1st inst), HL is the number of
;	sector past the current track (in C).
;
too$much:
	dad	d			; add back what made sum go negitive
	mvi	d,0			; number of sectors/track in DE
	mov	e,b
	ora	a			; clear the carry bit
sect$pos:
	inr	c			; add one to the current track (1-35)
	dsbc	d			; remove a track's worth of sectors
	jrnc	sect$pos		; less then one?, no jmp
	dad	d			; make HL positive again
;
;	at this point HL has the remainder (sector # 0-20) and
;	C has the track number (1-35), DE and B still has the
;	# sectors/track	for the current track.
;
	lda	temp$1			; get track offset
	add	c			; add to current track
	sta	vic$trk			; save it
	push	h
	lxi	h,special$skew
	lxi	b,21			; number of sectors in 1st region
	mov	a,e
	cmp	c
	jrz	correct$region
	dad	b			; move past current region
	dcx	b
	dcx	b			; 19
adjust$loop:
	cmp	c
	jrz	correct$region
	dad	b
	dcx	b
	jr	adjust$loop
;
;
;
correct$region:
	pop	b			; get logical sector # in BC
	dad	b
	mov	a,m			; get translated sector number to A
	sta	vic$sect		; value from 0 to 20 will be returned
	inr	a			; A is required to be non-zero on ret 
	ret

	page
;
;
;
read$sector:
	mvi	a,3
	sta	retry

read$again:
	mvi	a,vicrd		; read a sector of data
	sta	vic$cmd
	call	disp$dsk$info
	call	enable$6502
	mvi	a,3fh		; mmu ram bank 0 (no I/O)
	sta	force$map
	lda	vic$data
	ora	a		; problems?
	jrnz	read$error	; yes, check for disk error or media change
				; no, go move buffer to DMA address
	ret

	page
;
;
;
check$cbm:
	lxi	h,@buffer
	mov	a,m
	cpi	'C'			; C ?
	rnz				; no, return

	inr	l			; @buffer+1
	mov	a,m
	cpi	'B'			; B ?
	rnz				; no, return

	inr	l			; @buffer+0
	mov	a,m
	cpi	'M'			; M ?
	rnz

	mvi	l,0ffh			; @buffer+0ffh
					; point to the double sided flag
	mov	a,m			; read it, 0FFh if double sided
	ret

	page
;
;
;
ext$error:
	call	prt$msg$both
	rownum	19,5
	db	'32K MAX CPM+.SYS SIZE',0

try$again:
	rst	1

;
;
;
read$error:
	inr	a		; test for -1
	jrz	try$again

	lda	retry
	dcr	a
	sta	retry
	jrnz	read$again



	call	prt$msg$both
	rownum	19,5
	db	'READ ERROR',0
error$2:
	call	prt$msg$both
	db	' - HIT RETURN TO RETRY'
	rownum	20,15
	db	'DEL TO ENTER C128 MODE',0

;
;
;
wait$key:
	lxi	b,key$row
	mvi	a,11111110b		; bit 0 for RETURN key
	outp	a
	inr	c			; point to key$col
	inp	a
	ani	2			; on bit 1 (0-7)
	jrz	try$again

	inp	a
	ani	1			; delete key down
	jrnz	wait$key		; no, wait for RETURN key

	rst	0			; yes, reboot C128-mode


	page
;
;	CPM+.SYS file not on this disk test user to install
;	a system disk and wait for a CR to continue
;
tell$user:
	call	prt$msg$both
	rownum	19,5
	db	'NO',0
error$1:
	call	prt$msg$both
	db	' CPM+.SYS FILE',0
	jr	error$2

;
;
;
table$error:
	call	prt$msg$both
	rownum	19,5
	db	'BAD',0
	jr	error$1

	page

;
;
;
prt$msg$both:
	xthl
	call	prt$hl$both
	xthl
	ret

update$it:
	lxi	h,-1
	shld	old$offset		; force an update
;
;
;
prt$de$both:
	push	d
;
;
;
prt$hl$both$loop:
	pop	h
;
;
;
prt$hl$both:
	mov	d,m
	inx	h		; advance the pointer
	lda	prt$flg
	ana	a
	jrz	no$flag
	xra	d
	sta	prt$flg
	mov	d,a
no$flag:
	mov	a,d
	ora	a
	rz

	cpi	'$'
	rz			; yes, return

	push	h
	lxi	h,prt$hl$both$loop
	push	h	
	cpi	LF
	rz

	page
;
;
;
check$both$CR:
	cpi	CR
	jrnz	check$erase$both
;
;
do$crlf$both:
	call	crs$cr$40
	call	crs$cr$80
	call	crs$down$40
	RJMP	FR$cursor$down		; cursor down 80

;
;
;
check$erase$both:
	cpi	-1
	jrnz	check$both$CUR$$POS
;
;	Erase both screens
;
	lxi	d,24*256		; erase the status line 1st
	call	curpos$BC$both
	call	CEL$40
	call	CEL$80
	lxi	d,0			; erase main screen
	call	curpos$BC$both
	call	CES$40
	RJMP	FR$CES


check$both$CUR$POS:
	ani	80h
	jrz	out$d$both
;
curpos$D$both:
	pop	b			; get return adr in BC
	pop	h			; get pointer in HL
	mov	e,m			; E=column #
	inx	h
	push	h			; save new pointer
	push	b			; save return adr
	res	7,d			; D=row #

curpos$BC$both:
	push	d			; save cursor address 
	call	crs$pos$40
	pop	d
	RJMP	FR$cursor$pos		; 80 column


	page
;
;
;
disp$dsk$info:
	lxi	d,24*256+80-6
	call	crs$pos$80
	lxi	d,24*256+40-6
	call	crs$pos$40


	lda	vic$trk
	call	disp$dec
	mvi	d,' '
	call	out$d$both
	lda	vic$sect

disp$dec:
	mvi	b,'0'-1

conv$loop:
	inr	b
	sui	10
	jrnc	conv$loop

	adi	'0'+10
	push	psw
	mov	a,b
	call	disp$A
	pop	psw

disp$A:
	mov	d,a
;
;
;
out$d$both:
	push	d
	call	wr$char$40
	pop	d
	RJMP	FR$wr$char


