;BIOS65
;6502 portion of BIOS for C64 CP/M
;miscellaneous definitions
CR	=	$0D	carriage return
LF	=	$0A	line feed
;C64 memory
LSTX	=	$C5	current key pressed
QTSW	=	$D4	quote mode flag 0 = no
;C64 KERNAL entry points
KEY	=	$FF9F	scan keyboard
SETLFS	=	$FFBA	set LA, FA, SA
SETNAM	=	$FFBD	set length & file name address
OPEN	=	$FFC0	open logical file
CLOSE	=	$FFC3	close logical file
CHKIN	=	$FFC6	set channel in
CKOUT	=	$FFC9	set channel out
CLRCH	=	$FFCC	restore default channel
BASIN	=	$FFCF	input from channel
BSOUT	=	$FFD2	output to channel
CLALL	=	$FFE7	close all files & channels
;Z80 data area translated to C64 address space
;in Z80 memory these are $1000 lower
HSTBUF	=	$800	256 byte disk buffer
CMD	=	$900	command
DATA	=	$901	data register
SECTOR	=	$902	sector register
TRACK	=	$903	track register
DISKNO	=	$904	drive number register
KYCHAR	=	$905	key character
IOTYPE	=	$CFF	IO configuration byte
MODESW	=	$DE00	1 = Z80 OFF, 0 = Z80 ON
;start of BIOS65 code
*	=	$A00
LA00	LDA	#0	turn Z80 back on
	STA	MODESW 
	NOP		delay only
	JSR	LA0C	execute Z80 command if any
	JMP	LA00	and loop
;get Z80 command from CMD & see if valid
LA0C	LDA	CMD	get saved command
	CMP	#$FF	see if Z80 active
	BNE	LA16	if so try to execute
	JMP	($FFFC)	else RESET the C64
LA16	CMP	#10	see if 0 to 9
	BCC	LA1B	it is so execute else ignore
	RTS
;add command again to get 2 x command
;this code assumes vector table never crosses a page boundary
LA1B	CLD	clear decimal flag
	CLC	and then carry
	ADC	CMD	A was CMD so A now = 2 x CMD
	ADC	#<LA28	add low byte of table
	STA	LA25+1	modify jump vector
LA25	JMP	(LA28)	then go execute
;vector table for functions 0 through 9 from BIOS80
LA28	.wor	LA3F	0 = sector read
	.wor	LA57	1 = sector write
	.wor	LA86	2 = keyboard scan
	.wor	LA8F	3 = output to screen
	.wor	LA99	4 = get printer status
	.wor	LA9F	5 = output to printer
	.wor	LB49	6 = format diskette
	.wor	$E00	7 = jump to addr at $E00
	.wor	$F00	8 = jump to addr at $F00
	.wor	LA3C	9 = jump ($0906)
;function 9 - jump to address saved @ $906
LA3C	JMP	($906)	indirect jump set by Z80
;function 0 - read sector
LA3F	LDA	#"1"	"1" in "U1"
	JSR	LAF2	set up USER 1 mode
	JSR	LBDE	set up read from LA 2
	LDX	#0	do full 256 bytes
LA49	JSR	BASIN	input from channel
	STA	HSTBUF,X	& put in host buffer
	INX		go to next
	BNE	LA49	loop if more
	BEQ	LAB4	exit by restoring default channel
;do sector write but first initialize diskette
LA54	JSR	LB97	initialize diskette
;function 1 - write sector
LA57	JSR	LBF4	set up to write to command channel
	LDY	#8	8 characters
LA5C	LDA	LB80,X	send block command
	JSR	BSOUT	output to channel
	INX
	DEY
	BNE	LA5C
	JSR	CLRCH	restore default channel
	JSR	LBCE	read command results
	BNE	LA54	error so initialize
	JSR	CLRCH	restore default channel
	JSR	LBE9	set up write to channel 2
	LDX	#0
LA76	LDA	HSTBUF,X	get byte from buffer
	JSR	BSOUT	output to channel
	INX
	BNE	LA76	loop until all 256 written
	JSR	CLRCH	restore default channel
	LDA	#"2"	"2" in "U2", block write
	BNE	LAF2	go do block write
;function 2 - keyboard scan
LA86	JSR	KEY	scan keyboard
	LDA	LSTX	get current key pressed
	STA	KYCHAR	save in register
	RTS
;function 3 - output to screen
LA8F	LDA	#0	set editor to
	STA	QTSW	not in quote mode
	LDA	DATA	get character
	JMP	BSOUT	output to channel
;function 4 - get printer status
LA99	LDA	#0	always
	STA	DATA	OK
	RTS
;function 5 - send character to printer
LA9F	LDA	DATA	get character
	CMP	#LF	see if line feed
	BNE	LAA7	if not actually send
	RTS		if is do nothing
LAA7	LDX	#4	set channel out to 4
	JSR	CKOUT	set channel out
	BCS	LAB7	if error try to fix
	LDA	DATA	if OK get character again
	JSR	BSOUT	output to channel
LAB4	JMP	CLRCH	restore default channel & exit
LAB7	CMP	#3	see if not opened
	BNE	LAC0	some other error so exit
	JSR	LAC6	try to open printer
	BCC	LA9F	successful so try again
LAC0	LDA	#$FF	put error code
	STA	DATA	in data for Z80
LAC5	RTS
;open printer channel
LAC6	LDY	#7	SA =7 prints in upper & lower case
	JSR	LADE	close & open printer channel
	LDA	IOTYPE	get I/O type
	AND	#$02
	BEQ	LAC5	if 1515 then done?
	LDX	#4	set LA as 4
	JSR	CKOUT	set channel out
	LDA	#CR	send a CR
	JSR	BSOUT	output to channel
	LDY	#0	set SA to 0
;close printer and then open
LADE	LDA	#4	logical file 4
	JSR	CLOSE	close logical file
	LDA	#4	now set LA to 4
	LDX	#4	and device FA to 4
	JSR	SETLFS	set LA, FA, SA
	LDA	#0	zero length name
	JSR	SETNAM	set length & file name address
	JMP	OPEN	open logical file
;set up user mode
LAF2	STA	LB62+1	save "1" or "2" for mode
	LDA	DISKNO	get disk number (0 or 1)
;next line must be bad and it has been replaced with
;a call to the binary to ASCII conversion routing
;	JSR	$C98
	JSR	LB89	convert to ASCII
	STA	LB62+5	and store in string
	LDA	TRACK	now get track number
	JSR	LB89	convert to ASCII
	STX	LB62+7	and store in string
	STA	LB62+8
	LDA	SECTOR	once more for sector
	JSR	LB89	convert to ASCII
	STX	LB62+10	and store in string
	STA	LB62+11
;? check for two drives
	LDA	#2	set DATA to 2
	STA	DATA
LB1B	JSR	LBF4	set up command channel
	LDY	#13	string is 13 characters
LB20	LDA	LB62,X	get character and
	JSR	BSOUT	output to channel
	INX
	DEY
	BNE	LB20
	JSR	CLRCH	restore default channel
	JSR	LBCE	read error channel
	BEQ	LB3D	if no error say so & exit
	DEC	DATA	else drop counter
	BEQ	LB45	if everything tested then error
	JSR	LB97	else initialize diskette
	JMP	LB1B	and try again
LB3D	LDA	#0	set flag for no error
LB3F	STA	DATA	in data
	JMP	CLRCH	restore default channel & exit
LB45	LDA	#$FF	set flag for error
	BNE	LB3F	and always save & exit
;format diskette
LB49	JSR	LBF4	set up for command channel write
	LDY	#16	16 characters
LB4E	LDA	LB70,X	Text "NO:CP/M DISK,65"
	JSR	BSOUT	output to channel
	INX
	DEY
	BNE	LB4E	loop until all sent
	JSR	CLRCH	restore default channel
	JSR	LBCE	read error channel
	BNE	LB45	branch if error
	BEQ	LB3D	else say no error
;text strings for disk operations
LB62	.byt	"U1:2 0 TT SS", CR
LB6F	.byt	"#"	random access
LB70	.byt	"N0:CP/M DISK,65", CR
LB80	.byt	"B-P 2 0", CR
LB88	.byt	"I"	initialize
;convert binary in A to ASCII in X (upper) and A (lower)
;this assumes maximum value of binary is 99
LB89	CLD
	LDX	#"0"	set upper to zero
	SEC
LB8D	SBC	#10	A-10 to A
	BCC	LB94	less than zero so done
	INX		X+1 to X
	BCS	LB8D	and try again
LB94	ADC	#"0"+10	add 10 back & convert
	RTS
;Diskette initialization & set up for direct access
;start by closing command channel
LB97	LDA	#15	logical file (LA) 15
	JSR	CLOSE	close logical file
;now open command channel as logical file 15
	LDA	#15	logical file (LA) 15
	LDX	#8	drive (FA) 8
	LDY	#15	secondary address (SA) 15
	JSR	SETLFS	set LA, FA, SA
;now send initialize command to drive
	LDA	#1	only one character
	LDX	#<LB88	command is "I"
	LDY	#>LB88
	JSR	SETNAM	set length & file name address
;now open
	JSR	OPEN	open logical file
;if logical file 2 is open close it
LBB1	LDA	#2	logical file (LA) = 2
	JSR	CLOSE	close logical file
;now open logical file 2
	LDA	#2	logical file (LA) 2
	LDX	#8	drive (FA) 8
	LDY	#2	secondary address (SA) 2
	JSR	SETLFS	set LA, FA, SA
	LDA	#1	single character
	LDX	#<LB6F	Filename "#"
	LDY	#>LB6F
	JSR	SETNAM	set length & file name address
	JMP	OPEN	open logical file
;initialize and then set input to command channel
LBCB	JSR	LB97	initialize diskette
;set input to command channel
LBCE	LDX	#15	logical address = 15
	JSR	CHKIN	set channel in
	BCS	LBCB	if error try to initialize
	JSR	BASIN	input from channel
	CMP	#"0"	test error code "0"
	RTS
;close and open LA 2 and then
LBDB	JSR	LBB1	set for random access
;set up read from channel 2
LBDE	LDX	#2	channel 2
	JSR	CHKIN	set channel in
	BCS	LBDB	if error try to initialize
	RTS
;close and open LA 2 and then
LBE6	JSR	LBB1	set for random access
;set up write to channel 2
LBE9	LDX	#2	channel 2
	JSR	CKOUT	set channel out
	BCS	LBE6	if error close and open
	RTS 
;initialize diskette then
LBF1	JSR	LB97	initialize disk
;set up for write to command channel
LBF4	LDX	#15	LA 15 for command channel
	JSR	CKOUT	set channel out
	BCS	LBF1	if error initialize
	LDX	#0	x = 0 to start transfer after RTS
	RTS
;Z80 address table in Z80 address space for certain functions.
;In Z80 address space this starts at $FC00
LC00	.wor	LC10+$1000
	.wor	LC20+$1000
	.wor	LC30+$1000
	.wor	LC40+$1000
	.wor	LC50+$1000
	.wor	LC60+$1000
	.wor	LC70+$1000
	.wor	LC80+$1000
LC10	.byt	"DIR",CR,0,0,0,0,0,0,0,0,0,0,0,0
LC20	.byt	"DIR B:",CR,0,CR,0,0,0,0,0,0,0
LC30	.byt	"STAT *.*",CR,0,0,0,0,0,0,0
LC40	.byt	"STAT B:*.*",CR,0,0,0,0,0
LC50	.byt	"COPY",CR,0,"GTHEWATER",0
LC60	.byt	"CONFIG",CR,0,0,0,0,0,0,0,0,0
LC70	.byt	"DDT",CR,0,0,0,0,0,0,0,0,0,0,0,0
LC80	.byt	"DDT ",0,0,CR,0,0,0,0,0,0,0,0,0
;note that this area exists in Z80 address space
;starting at $FC90
	.byt	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	.byt	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	.byt	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	.byt	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	.byt	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	.byt	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	.byt	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
IOTYPE	.byt	1	this is IOTYPE
