[Contents] [Commodore] [New] [Search] [Home]

Commodore CP/M v2.2 for the C64
Custom BIOS

;	CUSTOM BIOS FOR CP/M 2.2 ON COMMODORE-64
;
;	COPYRIGHT (C) 1982
;       COMMODORE INTERNATIONAL
;
;	THIS VERSION HAS THE FOLLOWING ATTRIBUTES:
;
;	1.  MEMORY MAP SET UP FOR 52K RAM SYSTEM
;	    WITH I/O AND DRIVERS BY BOOT65
;
;	2.  DISK TABLES AND VECTORS INCLUDED FOR  
	    2 DRIVES
;
;	3.  THE INTEL I/O BYTE IS NOT IMPLEMENTED
;
;	4.  PUNCH AND READER ARE NULL ROUTINES
;
;	5.  KEYBOARD AND MESSAGE TABLES ARE PART OF
;	    BIOS65
;
;	6.  A 20K TO 48K BYTE CP/M ENVIRONMENT CAN BE
;	    SUPPORTED ON THE COMMODORE-64 (44K WITH IEEE)
;
;       7.  VIRTUAL DRIVE B IS SUPPORTED FOR 1540
;
;	8.  DRIVE B IS NOT VIRTUAL ON IEEE DISK.
;
;
BASE	EQU	0000H	;BEGINNING OF ADDRESSABLE RAM
;
MSIZE	EQU	44	;CP/M VERSION MEMORY SIZE IN KILOBYTES
;
;	"BIAS" IS ADDRESS OFFSET FROM 3400H FOR MEMORY SYSTEMS
;	THAN 20K (REFERRED TO AS "B" THROUGHOUT THE TEXT).
;
BIAS	EQU	(MSIZE-20)*1024
;
;	NOTE: TO CREATE MOVCPM, THE FOLLOWING CCP EQUATES 
;	      ARE USED:
;
;CCP	EQU	0000H		;FOR BIOS0.HEX
;CCP	EQU	0100H		;FOR BIOS1.HEX
;
CCP	EQU	3400H+BIAS	;BASE OF CCP
BDOS	EQU	CCP+806H	;BASE OF BDOS
BIOS	EQU	CCP+1600H	;BASE OF BIOS
CDISK	EQU	BASE+0004H	;CURRENT DISK NUMBER 0=A,...,15=P
IOBYTE	EQU	BASE+0003H	;INTEL I/O BYTE
TRANS	EQU	0000H		;0 IMPLIES NO TRANSLATION
ENTRY	EQU	0005H		;BDOS ENTRY VECTOR
;
;	THE FOLLOWING EQUATES DEFINE THE COMMON MEMORY FOR 
;	PASSING DATA TO AND FROM THE 6510 I/O ROUTINES
;
HSTBUF	EQU	0F800H		;256 BYTE DISK BUFFER
CMD	EQU	0F900H		;COMMAND REGISTER
DATA	EQU	0F901H		;DATA REGISTER
SECTOR	EQU	0F902H		;SECTOR REGISTER
TRACK	EQU	0F903H		;TRACK REGISTER
DISKNO	EQU	0F904H		;DRIVE NUMBER REGISTER
KYCHAR	EQU	0F905H		;KEYBOARD CHARACTER REGISTER
IOTYPE	EQU	0FCFFH	;IO CONFIGURATION BYTE
;
;	THE Z80 SHUTS ITSELF OFF BY WRITING "OFF" TO 
;	THE LOCATION "MODESW"
;
OFF	EQU	1
MODESW	EQU	0CE00H
;
;	THE FOLLOWING ARE THE COMMANDS TO THE 6510 I/O ROUTINES
;
VICRD	EQU	0		;READ SPECIFIED SECTOR
VICWR	EQU	1		;WRITE SPECIFIED SECTOR
VICIN	EQU	2		;DO A KEYBOARD SCAN
VICOUT	EQU	3		;OUTPUT DATA TO SCREEG
VICPST	EQU	4		;GET PRINTER STATUS
VICPRT	EQU	5		;SEND CHARACTER TO PRINTER
VICFMT	EQU	6		;FORMAT DISK COMMAND
AUX1	EQU	7		;JUMP TO $0E00 IN 6510 SPACE
AUX2	EQU	8		;JUMP TO $0F00 IN 6510 SPACE
INDIR	EQU	9	;JUMP INDIRECT VIA 0F906
;
;
	ORG	BIOS	;ORIGIN OF THIS PROGRAM
NSECTS	EQU	($-CCP)/256	;WARM START SECTOR COUNT
;
;	JUMP VECTOR FOR INDIVIDUAL SUBROUTINES
	JMP	BOOT		;COLD START
WBOOTE:	JMP	WBOOT		;WARM START
	JMP	CONST		;CONSOLE STATUS
	JMP	CONIN		;CONSOLE CHARACTER IN
	JMP	CONOUT		;CONSOLE CHARACTER OUT
	JMP	LIST		;LIST CHARACTER OUT
	JMP	PUNCH		;PUNCH CHARACTER OUT
	JMP	READER		;READER CHARACTER OUT
	JMP	HOME		;MOVE HEAD TO HOME POSITION
	JMP	SELDSK		;SELECT DISK
	JMP	SETTRK		;SET TRACK NUMBER
	JMP	SETSEC		;SET SECTOR NUMBER
	JMP	SETDMA		;SET DMA ADDRESS
	JMP	READ		;READ DISK
	JMP	WRITE		;WRITE DISK
	JMP	LISTST		;RETURN LIST STATUS
	JMP	SECTRAN		;SECTOR TRANSLATE
;
KYBDMD:	DB	00H	;CAPS LOCK FLAG
;
;	FIXED DATA TABLES FOR TWO DRIVES  
;	DISK PARAMETER HEADER FOR DISK 00
DPBASE:	DW	TRANS,0000H
	DW	0000H,0000H
	DW	DIRBF,DPBLK
	DW	CHK00,ALL00
;	DISK PARAMETER HEADER FOR DISK 01
	DW	TRANS,0000H
	DW	0000H,0000H
	DW	DIRBF,DPBLK
	DW	CHK01,ALL01
;
;
DPBLK:	;DISK PARAMETER BLOCK, COMMON TO ALL DISKS
	DW	34		;SECTORS PER TRACK
	DB	3		;BLOCK SHIFT FACTOR
	DB	7		;BLOCK MASK
	DB	0		;NULL MASK
	DW	135		;DISK SIZE-1
	DW	63		;DIRECTORY MAX
	DB	192		;ALLOC 0
	DB	0		;ALLOC 1
	DW	16		;CHECK SIZE
	DW	2		;TRACK OFFSET
;
;	END OF FIXED TABLES
;
;	MEMORY INITIALIZED WHEN BIOS READ IN AT BOOT TIME
;
LASTKY:	DB	40H	;VECTOR OF LAST KEY PRESSED
TOGGLE:	DB	00H	;CAPS LOCK HOUSEKEEPING
CSTAT:	DB	00H	;CHARACTER AVAILABLE FLAG
MSGPTR:	DW	0000H	;MESSAGE POINTER
TBLPTR:	DW	0FD00H	;KEYBOARD CODE TABLE
MSGTBL:	DW	0FC00H	;MESSAGE VECTOR TABLE
;
;	MISC. CONSOLE EQUATES
;
SHFTST	EQU	0F28DH	;CONTROL,COMMODORE,SHIFT KEYS
FLASH	EQU	0F0CCH	;CURSOR FLASH ENABLE
CURSOR	EQU	0F0CFH	;CURSOR CHARACTER
;
;	INDIVIDUAL SUBROUTINES TO PERFORM EACH FUNCTION
BOOT:
	MVI	A,20H		;ASCII SPACE
	STA	CURSOR		;SET UP CURSOR
	XRA	A		;ZERO IN THE ACCUM
	STA	IOBYTE		;CLEAR THE IOBYTE
	STA	CDISK		;SELECT DISK ZERO
	STA	CURDSK		;CLEAR VIRTUAL DISK POINTER
	STA	HSTACT		;HOST BUFFER INACTIVE
	STA	UNACNT		;CLEAR UNALLOC COUNT
	MVI	A,0C3H		;C3 IS JUMP OPCODE
	STA	0+BASE		; FOR JUMP TO WBOOT
	LXI	H,WBOOTE	;WBOOT ENTRY POINT
	SHLD	1+BASE		;SET ADDRESS FIELD
;
	STA	5+BASE		;JUMP TO BDOS OPCODE
	LXI	H,BDOS		;BDOS ENTRY POINT
	SHLD	6+BASE		;SET ADDRESS FIELD
;
	LXI	B,80H+BASE	;DEFAULT DMA ADDRESS
	CALL	SETDMA
;
	LXI	D,SIGNON	;DE POINTS TO SIGNON MSG
	MVI	C,9		;PRINT STRING FUNCTION
	CALL	ENTRY		;GO TO BDOS
	JMP	GOCPM1		;GET READY FOR CCP
;
SIGNON:	DB	0CH,0AH		;CLEAR SCREEN
	DB	'    COMMODORE 64   20k CP/M vers 2.2'
	DB	0DH,0AH,0AH
	DB	'  Copyright (C) 1979, Digital Research',0DH,0AH
	DB	'     Copyright (C) 1982, Commodore',0DH,0AH
	DB	0AH,'$'		;END OF STRING MARKER
;

;
WBOOT:
	LXI	SP,80H+BASE	;USE SPACE BELOW BUFFER FOR STACK
	MVI	C,0		;SELECT DISK 0
	CALL	SELDSK
	XRA	A		;FORCE DRIVE A
	STA	DISKNO		;ABSOLUTY, POSITIVELY
	CALL	CHGDSK		;IF NOT ALREADY SELECTED
	CALL	HOME		;GO TO TRACK 00
	MVI	A,0DH	;CARRIAGE RETURN
	CALL	COUT5	;OUTPUT IT
;
	LXI	D,CCP	;START OF LOAD
	MVI	B,NSECTS
	MVI	H,1	;TRACK NUMBER
	MVI	L,6	;SECTOR NUMBER
LOAD1:	MOV	A,H
	STA	TRACK
	MOV	A,L
	STA	SECTOR
	MVI	A,VICRD	;DISK READ COMMAND
	CALL	IO6510
;
	LDA	DATA
	ORA	A
	JNZ	LOAD1	;ERROR IF NOT ZERO
	PUSH	H
	PUSH	B
	LXI	B,256
	LXI	H,HSTBUF ;DISK BUFFER
	DB	0EDH	;LDIR INSTRUCTION
	DB	0B0H
	MVI	C,'*'	;SHOW IT'S LOADING
	CALL	CONOUT
	POP	B
	POP	H
	DCR	B	;DECREMENT SECTOR COUNT
	JZ	GOCPM
	INR	L	;NEXT SECTOR
	MOV	A,L
	CPI	17
	JC	LOAD1
	INR	H
	MVI	L,0
	JMP	LOAD1
;	END OF LOAD OPERATION, SET PARAMETERS AND GO TO CP/M
GOCPM:
	MVI	A,0C3H	;C3 IS A JMP INSTRUCTION
	STA	0+BASE	;FOR JMP TO WBOOT
	LXI	H,WBOOTE	;WBOOT ENTRY POINT
	SHLD	1+BASE	;SET ADDRESS FIELD FOR JMP AT 0
;
	STA	5+BASE	;FOR JMP TO BDOS
	LXI	H,BDOS	;BDOS ENTRY POINT
	SHLD	6+BASE	;ADDRESS FIELD OF JUMP AT 5 TO BDOS
;
	LXI	B,80H+BASE	;DEFAULT DMA ADDRESS IS 80H
	CALL	SETDMA
;
;
GOCPM1:	LDA	CDISK	;GET CURRENT DISK NUMBER
	MOV	C,A	;SEND TO THE CCP
	JMP	CCP	;GO TO CP/M FOR FURTHER PROCESSING
;
;
;	MAIN ROUTINE TO TRANSFER EXECUTION TO 6510
;
IO6510:	STA	CMD	;PUT A IN 6510 COMMAND REGISTER
	MVI	A,OFF
	STA	MODESW	;TURN OFF Z80
	NOP		;REQUIRED BY HARDWARE
	RET
;
;
;
CONST:	;CONSOLE STATUS, RETURN 0FFH IF CHARACTER READY, 00H IF NOT
	LHLD	MSGPTR	;MESSAGE MODE?
	MOV	A,H
	ORA	L
	MVI	A,0FFH	;DATA READY FLAG
	RNZ		;RETURN IF MSGPTR<>0
;
	LDA	CSTAT	;ALREADY A CHAR?
	ANA	A
	RNZ		;YES IF NOT 0
;
	MVI	A,VICIN	;CHECK KEYBOARD COMMAND
	CALL	IO6510
;
	LDA	SHFTST	;GET STATUS OF CONTROL KEYS
	ANI	02H	;CHECK FOR COMMODORE KEY
	JZ	CONST0	;JUMP IF NOT PRESSED
;
	LDA	TOGGLE	;IS THIS AN UPSTROKE?
	ANA	A
	JNZ	CONST0	;NO,WAITING TO RELEASE
;
	LDA	KYBDMD	;GET CAPS MODE FLAG
	XRI	01H	;TOGGLE MODE BIT
	STA	KYBDMD
	MVI	A,1
CONST0:	STA	TOGGLE
;
	LDA	KYCHAR	;GET SCANNED DATA
	CPI	3AH	;BAD CONTROL DATA
	JZ	CONST1
;
	CPI	3DH	;BAD CONTROL DATA
	JZ	CONST1
;
	LXI	H,LASTKY ;COMPARE WITH PREVIOUS
	CMP	M	;   SCAN DATA
	JNZ	CONST2	;IF DIFFERENT, NEW KEY
;
CONST1:	XRA	A	;DATA NOT READY FLAG
	STA	CSTAT	;SAVE FOR LATER
	RET
;
CONST2:	PUSH	PSW
	LXI	B,500
CONST3:	DCX	B	;DELAY FOR KEYBOUNCE
	MOV	A,C
	ORA	B
	JNZ	CONST3
;
	MVI	A,VICIN	;GET CHARACTER AGAIN
	CALL	IO6510
;
	POP	PSW
	LXI	H,KYCHAR
	CMP	M
	JNZ	CONST1	;IF NOT 0, KEY NOT DONE BOUNCING
;
	STA	LASTKY	;UPDATE LAST KEY
	CPI	40H	;IF 40H, NO KEY PRESSED
	JZ	CONST1
;
	MVI	A,0FFH	;DATA READY FLAG
	STA	CSTAT	;SAVE FOR LATER
	RET
;
CONIN:	;CONSOLE CHARACTER INTO REGISTER A
	MVI	A,0	;TURN ON CURSOR
	STA	FLASH
;
	LHLD	MSGPTR	;ARE WE IN MESSAGE MODE?
	MOV	A,H
	ORA	L
	JNZ	CONIN5
;
;
CONIN1:	CALL	CONST	;CHECK CONSOLE STATUS
	ORA	A
	JZ	CONIN1	;UNTIL NEW CHARACTER
;
	XRA	A
	STA	CSTAT	;CLEAR CSTAT
CONIN2:	LDA	KYBDMD	;UNSHIFT=0, CAPS=1
	MOV	B,A
	LDA	SHFTST	;GET MODIFIER STATUS
	ANI	01H	;IS A SHIFT KEY DOWN?
	JZ	CONIN3	;JUMP IF NO
;
	MVI	B,2	;SHIFT=2
CONIN3:	LDA	SHFTST	;GET MODIFIER STATUS
	ANI	04H	;IS THE CONTROL KEY DOWN?
	JZ	CONIN4	;JUMP IF NO
;
	MVI	B,3	;CONTROL=3
CONIN4:	LDA	LASTKY	;GET KEY POSITION
	ADD	A	;*2
	ADD	A	;*4
	ADD	B	;ADD IN OFFSET
	LHLD	TBLPTR	;GET BEGINNING OF KEYTBL
	ADD	L	;VECTOR INTO TABLE
	MOV	L,A
	MVI	A,0
	ADC	H
	MOV	H,A
	MOV	A,M	;GET CHARACTER FROM TABLE
	CPI	80H	;MESSAGE IF <7FH
	JC	CONIN7	;JUMP IF ASCII CHARACTER
;
	LHLD	MSGTBL	;GET BEGINNING OF MVTBL
	ANI	7FH	;STRIP OF MESSAGE BIT
	ADD	A	;*2
	ADD	L	;VECTOR INTO TABLE
	MOV	L,A
	MVI	A,0
	ADC	H
	MOV	H,A
	MOV	A,M	;LOW ORDER BYTE
	INX	H
	MOV	H,M	;HIGH ORDER BYTE
	MOV	L,A
CONIN5:	MOV	B,M	;GET CHARACTER
	INX	H	;CHECK NEXT CHARACTER
	MOV	A,M
	ANA	A
	JNZ	CONIN6	;IF 0, B HAS LAST CHAR
;
	LXI	H,0000H	;END OF MESSAGE MODE
CONIN6:	SHLD	MSGPTR	;SAVE MESSAGE POINTER
	MOV	A,B	;CHECK CHARACTER
	ANA	A	;MAYBE 1ST IS 0
	JZ	CONIN1	;IF 0, NOT A CHARACTER
;
CONIN7:	PUSH	PSW	;SAVE CHARACTER
	MVI	A,1
	STA	FLASH	;TURN OFF CURSOR
	MVI	C,' '	;GET SPACE 
	CALL	CONOUT	;PUT IT BACK
	MVI	A,9DH	;CURSOR LEFT COMMAND
	CALL	COUT5	;BYPASS FILTER 
	POP	PSW	;GET CHARACTER
	RET		;DONE
;
CONOUT: ;CONSOLE CHARACTER OUTPUT FROM REGISTER C
	LDA	IOTYPE	;GET CONFIGURATION BYTE
	ANI	10H	;BIT 4 = 1 TO IGNORE FILTER
	MOV	A,C	;GET TO ACCUMULATOR
	JNZ	COUT5	;PRINT AS RECEIVED
;
	CALL	SWAP	;EXCHANGE UPPER AND LOWER CASE
	CPI	0CH	;ASCII CLEAR SCREEN?
	JNZ	COUT1	;JUMP IF NO
;
	MVI	A,93H	;COMMODORE CLEAR SCREEN CMD
	JMP	COUT5
;
COUT1:	CPI	08H	;ASCII BACKSPACE?
	JNZ	COUT2	;JUMP IF NO
;
	MVI	A,14H	;COMMODORE BACKSPACE CMD
	JMP	COUT5
;
COUT2:	CPI	0AH	;LINE FEED?
	JNZ	COUT3	
;
	MVI	A,17	;COMMODORE LINE FEED
	JMP	COUT5
;
COUT3:	CPI	0DH	;CARRIAGE RETURN?
	JNZ	COUT4
;
	CALL	COUT5
	MVI	A,145	;UP 1 LINE TO NEGATE AUTO LF
	JMP	COUT5
;
COUT4:	CPI	20H
	RC		;RETURN IF UNDECODED CONTROL CHAR
	CPI	80H
	RNC		;RETURN IF NOT ASCII CHARACTER
;
COUT5:	STA	DATA	;PUT DATA IN CHARACTER REGISTER
	MVI	A,VICOUT	;SCREEN OUTPUT COMMAND
	JMP	IO6510
;
LIST:	;LIST CHARACTER FROM REGISTER C
	LDA	IOTYPE	;WHAT KIND OF PRINTER?
	ANI	04H	;0 IF 1515, 1 IF 4022
	MOV	A,C	;CHARACTER TO REGISTER A
	JNZ	LIST2	;JUMP IF NO SWAP
;
	LDA	IOTYPE
	ANI	08H	;WHICH TYPE OF SWAP?
	MOV	A,C	;GET CHARACTER
	JNZ	LIST1
;
	CALL	SWAP	;SWAP UPPER AND LOWER CASE
	JMP	LIST2
;
LIST1:	CALL	SWAP2	;4022 SWAP ROUTINE
LIST2:	STA	DATA	;PUT DATA IN REGISTER
	MVI	A,VICPRT	;ASSUME 1540
LIST3:	JMP	IO6510
;
LISTST:	;RETURN LIST STATUS (0 IF NOT READY, 1 IF READY)
	MVI	A,VICPST	;PRINTER STATUS COMMAND
	CALL	IO6510
	LDA	DATA	;DATA IS STATUS
	RET
;
SWAP:	;SWAP UPPER AND LOWER CASE FOR COMMODORE-64
	CPI	41H	;LESS THAN UC 'A'?
	RC		;RETURN IF SO
;
	CPI	5BH	;UC LETTER?
	JC	SWAP1	;JUMP IF SO
;
	CPI	61H	;LESS THAT LC 'A'
	RC		;RETURN IF SO
;
	CPI	7BH	;LC LETTER?
	RNC		;RETURN IF NO
;
	ANI	5FH	;TURN OFF BIT 5
	RET
;
SWAP1:	ORI	20H	;TURN ON BIT 5
	RET
;
SWAP2:	CPI	41H	;CY IF LESS THAN UC 'A'
	RC
	CPI	60H	;CY IF 40H < A < 60H
	JNC	SWAP3
;
	ORI	80H
	RET
;
SWAP3:	ANI	5FH
	RET
;
PUNCH:	;PUNCH CHARACTER FROM REGISTER C
	MOV	A,C	;CHARACTER TO REGISTER A
	NOP
	RET		;NULL SUBROUTINE
;
;
READER: ;READ CHARACTER INTO REGISTER A FROM READER DEVICE
	MVI	A,1AH	;ENTER END OF FILE FOR NOW (REPLACE LATER)
	ANI	7FH	;REMEMBER TO STRIP PARITY BIT
	RET
;
;
;*****************************************************
;*                                                   *
;*         CP/M TO HOST DISK CONSTANTS               *
;*                                                   *
;*****************************************************
BLKSIZ	EQU	1024		;CP/M ALLOCATION SIZE
HSTSIZ	EQU	256		;HOST DISK SECTOR SIZE
HSTSPT	EQU	17		;HOST DISK SECTORS/TRK
HSTBLK	EQU	HSTSIZ/128	;CP/M SECTS/HOST BUFF
CPMSPT	EQU	HSTBLK * HSTSPT	;CP/M SECTORS/TRACK
SECMSK	EQU	HSTBLK-1	;SECTOR MASK
SECSHF	EQU	1 		;LOG2(HSTBLK)
;
;*****************************************************
;*                                                   *
;*        BDOS CONSTANTS ON ENTRY TO WRITE           *
;*                                                   *
;*****************************************************
WRALL	EQU	0		;WRITE TO ALLOCATED
WRDIR	EQU	1		;WRITE TO DIRECTORY
WRUAL	EQU	2		;WRITE TO UNALLOCATED
;
;	HOME THE SELECTED DISK
HOME:
	LDA	HSTWRT		;CHECK FOR PENDING WRITE
	ORA	A
	JNZ	HOMED
	STA	HSTACT		;CLEAR HOST ACTIVE FLAG
HOMED:
	RET
;
SELDSK:
	;SELECT DISK
	LXI	H,0000H		;ERROR RETURN CODE
	MOV	A,C		;SELECTED DISK NUMBER
	STA	SEKDSK		;SEEK DISK NUMBER
	CPI	2		;MUST BE 0-1
	RNC			;NO CARRY IF 2,3,...
	MOV	L,A		;DISK NUMBER TO HL
	DAD	H		;MULTIPLY BY 16
	DAD	H
	DAD	H
	DAD	H
	LXI	D,DPBASE	;BASE OF PARM BLOCK
	DAD	D		;HL=.DPB(CURDSK)
	RET
;
SETTRK:
	;SET TRACK GIVEN BY REGISTERS BC
	MOV	H,B
	MOV	L,C
	SHLD	SEKTRK		;TRACK TO SEEK
	RET
;
SETSEC:
	;SET SECTOR GIVEN BY REGISTER C 
	MOV	A,C
	STA	SEKSEC		;SECTOR TO SEEK
	RET
;
SETDMA:
	;SET DMA ADDRESS GIVEN BY BC
	MOV	H,B
	MOV	L,C
	SHLD	DMAADR
	RET
;
SECTRAN:
	;TRANSLATE SECTOR NUMBER BC
	MOV	H,B
	MOV	L,C
	RET
;
;*****************************************************
;*                                                   *
;*	THE READ ENTRY POINT TAKES THE PLACE OF      *
;*	THE PREVIOUS BIOS DEFINTION FOR READ.        *
;*                                                   *
;*****************************************************
READ:
	;READ THE SELECTED CP/M SECTOR
	XRA	A
	STA	UNACNT
	MVI	A,1
	STA	READOP		;READ OPERATION
	STA	RSFLAG		;MUST READ DATA
	MVI	A,WRUAL
	STA	WRTYPE		;TREAT AS UNALLOC
	JMP	RWOPER		;TO PERFORM THE READ
;
;*****************************************************
;*                                                   *
;*	THE WRITE ENTRY POINT TAKES THE PLACE OF     *
;*	THE PREVIOUS BIOS DEFINTION FOR WRITE.       *
;*                                                   *
;*****************************************************
WRITE:
	;WRITE THE SELECTED CP/M SECTOR
	XRA	A		;0 TO ACCUMULATOR
	STA	READOP		;NOT A READ OPERATION
	MOV	A,C		;WRITE TYPE IN C
	STA	WRTYPE
	CPI	WRUAL		;WRITE UNALLOCATED?
	JNZ	CHKUNA		;CHECK FOR UNALLOC
;
;	WRITE TO UNALLOCATED, SET PARAMETERS
	MVI	A,BLKSIZ/128	;NEXT UNALLOC RECS
	STA	UNACNT
	LDA	SEKDSK		;DISK TO SEEK
	STA	UNADSK		;UNADSK = SEKDSK
	LHLD	SEKTRK
	SHLD	UNATRK		;UNATRK = SECTRK
	LDA	SEKSEC
	STA	UNASEC		;UNASEC = SEKSEC
;
CHKUNA:
	;CHECK FOR WRITE TO UNALLOCATED SECTOR
	LDA	UNACNT		;ANY UNALLOC REMAIN?
	ORA	A
	JZ	ALLOC		;SKIP IF NOT
;
;	MORE UNALLOCATED RECORDS REMAIN
	DCR	A		;UNACNT = UNACNT-1
	STA	UNACNT
	LDA	SEKDSK		;SAME DISK?
	LXI	H,UNADSK
	CMP	M		;SEKDSK = UNADSK?
	JNZ	ALLOC		;SKIP IF NOT
;
;	DISKS ARE THE SAME
	LXI	H,UNATRK
	CALL	TRKCMP		;SEKTRK = UNATRK?
	JNZ	ALLOC		;SKIP IF NOT
;
;	TRACKS ARE THE SAME
	LDA	SEKSEC		;SAME SECTOR?
	LXI	H,UNASEC
	CMP	M		;SEKSEC = UNASEC?
	JNZ	ALLOC		;SKIP IF NOT
;
;	MATCH, MOVE TO NEXT SECTOR FOR FUTURE REF
	INR	M		;UNASEC = UNASEC+1
	MOV	A,M		;END OF TRACK?
	CPI	CPMSPT		;COUNT CP/M SECTORS
	JC	NOOVF		;SKIP IF NO OVERFLOW
;
;	OVERFLOW TO NEXT TRACK
	MVI	M,0		;UNASEC = 0
	LHLD	UNATRK
	INX	H
	SHLD	UNATRK		;UNATRK = UNATRK+1
;
NOOVF:
	;MATCH FOUND, MARK AS UNNECESSARY READ
	XRA	A		;0 TO ACCUMULATOR
	STA	RSFLAG		;RSFLAG = 0
	JMP	RWOPER		;TO PERFORM THE WRITE
;
ALLOC:
	;NOT AN UNALLOCATED RECORD, REQUIRES PRE-READ
	XRA	A		;0 TO ACCUM
	STA	UNACNT		;UNACNT = 0
	INR	A		;1 TO ACCUM
	STA	RSFLAG		;RSFLAG = 1
;
;*****************************************************
;*                                                   *
;*	COMMON CODE FOR READ AND DRITE FOLLOWS       *
;*                                                   *
;*****************************************************
RWOPER:
	;ENTER HERE TO PERFORM THE READ/WRITE
	XRA	A		;ZERO TO ACCUM
        STA     ERFLAG          ;NO ERRORS (YET)
	LDA	SEKSEC		;COMPUTE HOST SECTOR
	ORA	A		;CARRY = 0
	RAR			;SHIFT RIGHT
	STA	SEKHST		;HOST SECTOR TO SEEK
;
;	ACTIVE HOST SECTOR?
	LXI	H,HSTACT	;HOST ACTIVE FLAG
	MOV	A,M
	MVI	M,1		;ALWAYS BECOMES 1
	ORA	A		;WAS IT ALREADY?
	JZ	FILHST		;FILL HOST IF NOT
;
;	HOST BUFFER ACTIVE, SAME AS SEEK BUFFER?
	LDA	SEKDSK
	LXI	H,HSTDSK	;SAME DISK?
	CMP	M		;SEKDSK = HSTDSK?
	JNZ	NOMTCH
;
;	SAME DISK, SAME TRACK?
	LXI	H,HSTTRK
	CALL	TRKCMP		;SEKTRK = HSTTRK?
	JNZ	NOMTCH
;
;	SAME DISK, SAME TRACK, SAME BUFFER?
	LDA	SEKHST
	LXI	H,HSTSEC	;SEKHST = HSTSEC?
	CMP	M
	JZ	MATCH		;SKIP IF MATCH
;
NOMTCH:
	;PROPER DISK, BUT NOT CORRECT SECTOR
	LDA	HSTWRT		;HOST WRITTEN?
	ORA	A
	CNZ	WRHST		;CLEAR HOST BUFF
;
FILHST:
	;MAY HAVE TO FILL THE HOST BUFFER
	LDA	SEKDSK
	STA	HSTDSK
	LHLD	SEKTRK
	SHLD	HSTTRK
	LDA	SEKHST
	STA	HSTSEC
	LDA	RSFLAG		;NEED TO READ?
	ORA	A
	CNZ	RDHST		;YES, IN 1
	XRA	A		;0 TO ACCUM
	STA	HSTWRT		;NO PENDING WRITE
;
MATCH:
	;COPY DATA TO OR FROM BUFFER
	LDA	SEKSEC		;MASK BUFFER NUMBER
	ANI	SECMSK		;LEAST SIGNIF BITS
	MOV	L,A		;READY TO SHIFT
	MVI	H,0		;DOUBLE COUNT
	DAD	H		;SHIFT LEFT 7
	DAD	H
	DAD	H
	DAD	H
	DAD	H
	DAD	H
	DAD	H
;	HL HAS RELATIVE HOST BUFFER ADDRESS
	LXI	D,HSTBUF
	DAD	D		;HL = HOST ADDRESS
	XCHG			;NOW IN DE
	LHLD	DMAADR		;GET/PUT CP/M DATA
	MVI	C,128		;LENGTH OF MOVE
	LDA	READOP		;WHICH WAY?
	ORA	A
	JNZ	RWMOVE		;SKIP IF READ
;
;	WRITE OPERATION, MARK AND SWITCH DIRECTION
	MVI	A,1
	STA	HSTWRT		;HSTWRT = 1
	XCHG			;SOURCE/DEST SWAP
;
RWMOVE:
	;C INITIALLY 128, DE IS SOURCE, HL IS DEST
	LDAX	D		;SOURCE CHARACTER
	INX	D
	MOV	M,A		;TO DEST
	INX	H
	DCR	C		;LOOP 128 TIMES
	JNZ	RWMOVE
;
;	DATA HAS BEEN MOVED TO/FROM HOST BUFFER
	LDA	WRTYPE		;WRITE TYPE
	CPI	WRDIR		;TO DIRECTORY?
	LDA	ERFLAG		;IN CASE OF ERRORS
	RNZ			;NO FURTHER PROCESSING
;
;	CLEAR HOST BUFFER FOR DIRECTORY WRITE
	ORA	A		;ERRORS?
	RNZ			;SKIP IF SO
	XRA	A		;0 TO ACCUM
	STA	HSTWRT		;BUFFER WRITTEN
	CALL	WRHST
	LDA	ERFLAG
	RET
;
;*****************************************************
;*                                                   *
;*	UTILITY SUBROUTINE FOR 16-BIT COMPARE        *
;*                                                   *
;*****************************************************
TRKCMP:
	;HL = .UNATRK OR .HSTTRK, COMPARE WITH SEKTRK
	XCHG
	LXI	H,SEKTRK
	LDAX	D		;LOW BYTE COMPARE
	CMP	M		;SAME?
	RNZ			;RETURN IF NOT
;	LOW BYTES EQUAL, TEST HIGH 1S
	INX	D
	INX	H
	LDAX	D
	CMP	M		;SETS FLAGS
	RET
;
;*****************************************************
;*                                                   *
;*	WRHST PERFORMS THE PHYSICAL WRITE TO         *
;*	THE HOST DISK, RDHST READS THE PHYSICAL      *
;*	DISK.					     *
;*                                                   *
;*****************************************************
WRHST:
	;HSTDSK = HOST DISK #, HSTTRK = HOST TRACK #,
	;HSTSEC = HOST SECT #. WRITE "HSTSIZ" BYTES
	;FROM HSTBUF AND RETURN ERROR FLAG IN ERFLAG.
	;RETURN ERFLAG NON-ZERO IF ERROR
	MVI	A,VICWR		;LOAD DISK WRITE COMMAND
WRHST0:	STA	RW		;PUT COMMAND IN REGISTER
	LDA	HSTDSK		;GET HOST DISK NUMBER
	STA	DISKNO		;  AND PUT IN COMMON AREA
	CALL	CHGDSK		;CORRECT VIRTUAL DISK?
WRHST2:	LDA	HSTTRK		;GET HOST TRACK NUMBER
	INR	A		;ADD 1 FOR VIC OFFSET
	CPI	18		;WE WANT TO SKIP TRACK 18
	JC	WRHST3		;CARRY IF TRACK<18
	INR	A
WRHST3:	STA	TRACK		;PUT IN COMMON AREA
	LDA	HSTSEC		;GET HOST SECTOR NUMBER
	STA	SECTOR		;PUT IN COMMON AREA
	LDA	RW		;GET DISK COMMAND
	CALL	IO6510
	LDA	DATA		;GET DISK STATUS
	STA	ERFLAG		;  AND STORE IN ERFLAG
	RET
;
CHGDSK:	MOV	H,A		;SAVE DISK NUMBER
	LDA	IOTYPE		;BIT 0=0 FOR VIRTUAL
	ANI	01
	RNZ			;NOT ZERO IF 2 DRIVES
	STA	DISKNO		;FORCE DRIVE A
	MOV	A,H		;RESTORE DISK NUMBER
;
	LXI	H,CURDSK	;IS THIS OUR CURRENT DISK?
	CMP	M
	RZ			;RETURN IF OK
;
	MOV	M,A		;SET UP NEW DISK
	ADI	'A'		;FORM ASCII DRIVE LETTER
	STA	DSKMNT		;PUT IN MESSAGE
;
	LXI	H,MNTMSG	;INSERT DISK MESSAGE
	CALL	PMSG		;GO PRINT IT
CHGD1:	CALL	CONIN		;WAIT FOR RETURN
	CPI	0DH
	JNZ	CHGD1
	RET
;
RDHST:
	;HSTDSK = HOST DISK #, HSTTRK = HOST TRACK #,
	;HSTSEC = HOST SECT #. READ "HSHSIZ" BYTES
	;INTO HSTBUF AND RETURN ERROR FLAG IN ERFLAG.
	MVI	A,VICRD		;DISK READ COMMAND
	JMP	WRHST0		;REST IS SAME AS DISK WRITE
;
MNTMSG:	DB	0DH,0AH,'Insert disk '
DSKMNT:	DB	'A'
	DB	' into drive 0, press return'
	DB	00H
;
PMSG:	MOV	A,M
	ANA	A
	RZ
	PUSH	H
	MOV	C,A
	CALL	CONOUT
	POP	H
	INX	H
	JMP	PMSG
;
;*****************************************************
;*                                                   *
;*	UNITIALIZED RAM DATA AREAS		     *
;*                                                   *
;*****************************************************
;
SEKDSK:	DS	1		;SEEK DISK NUMBER
SEKTRK:	DS	2		;SEEK TRACK NUMBER
SEKSEC:	DS	1		;SEEK SECTOR NUMBER
;
HSTDSK:	DS	1		;HOST DISK NUMBER
HSTTRK:	DS	2		;HOST TRACK NUMBER
HSTSEC:	DS	1		;HOST SECTOR NUMBER
;
SEKHST:	DS	1		;SEEK SHR SECSHF
HSTACT:	DS	1		;HOST ACTIVE FLAG
HSTWRT:	DS	1		;HOST WRITTEN FLAG
;
UNACNT:	DS	1		;UNALLOC REC CNT
UNADSK:	DS	1		;LAST UNALLOC DISK
UNATRK:	DS	2		;LAST UNALLOC TRACK
UNASEC:	DS	1		;LAST UNALLOC SECTOR
;
ERFLAG:	DS	1		;ERROR REPORTING
RSFLAG:	DS	1		;READ SECTOR FLAG
READOP:	DS	1		;1 IF READ OPERATION
WRTYPE:	DS	1		;WRITE OPERATION TYPE
DMAADR:	DS	2		;LAST DMA ADDRESS
RW:	DS	1		;TEMPORARY COMMAND REGISTER
CURDSK:	DS	1		;VIRTUAL DISK POINTER
;
;	SCRATCH RAM AREA FOR BDOS USE
BEGDAT	EQU	$	;BEGINNING OF DATA AREA
DIRBF:	DS	128	;SCRATCH DIRECTORY AREA
ALL00:	DS	31	;ALLOCATION VECTOR 0
ALL01:	DS	31	;ALLOCATION VECTOR 1
CHK00:	DS	16	;CHECK VECTOR 0
CHK01:	DS	16	;CHECK VECTOR 1
;
ENDDAT	EQU	$	;END OF DATA AREA
DATSIZ	EQU	$-BEGDAT;SIZE OF DATA AREA
	END

[Contents] [Commodore] [New] [Search] [Home]
This page has been created by Sami Rautiainen.
Read the small print. Last updated September 05, 2020.