; 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 ;NOERRORS (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