;******************************************************** ;* * ;* CUSTOM BIOS FOR CP/M VERSION 1.4 and 2.2 * ;* * ;* Mark Stieglitz * ;* * ;******************************************************** .z80 title Stieglitz's Z80 CBIOS name ('CBIOS') ; cpm14 EQU 1 ;1 for version 1.4 (EQU 0 for 2.2) sovers EQU 'X4' ;version identifier for signon ; if1 if CPM14 .PRINTX /Assembling CBIOS for CPM V1.4/ else .PRINTX /Assembling CBIOS for CPM V2.2/ endif endif ; ; ;Derived heavily from BIOS by Russel Smith ;Modifications: ;X0 1-8-82 Syntax Changes for Microsoft M80 Assembler ; Correct WBOOT to retain selected drive ; Add switch for CP/M 1.4 compatibility ;X1 1-11-82 Add list dev driver (pioa w/ints) ;X2 1-17-82 Mod to defer drive select until actual I/O ;X3 2-09-82 Add conditional assy to ORG address for 2.2 ;X4 2-18-82 Add call to SELNOW in HOME to fix WBOOT problem ; if called when not already on A:. ; PAGE 51 MSIZE EQU 60 ;MEMORY CAPACITY IN KBYTES MONITR EQU 0F000H ;BASE OF SYSTEM MONITOR ; ; CP/M REFERENCE CONSTANTS ; if CPM14 BIAS EQU (MSIZE-20)*1024 CCP EQU 3500H+BIAS BDOS EQU CCP+806H CBIOS EQU CCP+1500H else BIAS EQU (MSIZE-20)*1024-200H ;Which is what DRC is shipping at E800 CCP EQU 3400H+BIAS BDOS EQU CCP+806H CBIOS EQU CCP+1600H endif ; ; ;I/O Constants ŠLF EQU 0AH ;LINE FEED CR EQU 0DH ;CARRIAGE RETURN LSTDAT EQU 8 ;List device, data LSTAC EQU 9 ;List device, control LSTINT EQU 1Ch ;Vector Offset LSVLOC EQU 0FF00h+LSTINT ;Hardware vector location ; page ASEG if CPM14 ORG 1E80h ;sysgen load address else ORG 1F80h endif .PHASE CBIOS ; JP BOOT ;STANDARD JUMP TABLE TO JP WBOOT ;THE SUBROUTINES OF CBIOS JP MONITR+6 ;Monitor console status rtn. IVECTR: JP MONITR+9 ;Monitor console input rtn. OVECTR: JP CONOUT JP LSTOUT ;LIST DEVICE VECTOR JP CONOUT ;PUNCH DEVICE VECTOR JP MONITR+9 ;READER DEVICE VECTOR JP HOME JP SELECT JP SEEK JP SETSEC JP SETPTR JP READ JP WRITE JP LSTST ;LIST DEVICE STATUS VECTOR JP TRANS ; ; ; BOOT: XOR A LD (0003H),A ;RESET IOBYTE TO ZEROS LD (4),A ;Initialize CP/M unit to A: LD HL,SIGNON CALL PMSG ;PRINT SIGNON MESSAGE LD A,0FFh ;Initialize list device LD (LSTRDY),A ; Set flag to "ready" LD A,0Fh ; Select output mode for PIO OUT (LSTAC),A LD A,LSTINT ; Set vector in PIO OUT (LSTAC),A LD BC,LSTIH ; Store handler address LD (LSVLOC),BC ; at vector location LD A,87h ; Enable PIO interrupts OUT (LSTAC),A JR GOCPM ; ; ŠWBOOT: LD SP,STACK LD C,0 CALL SELECT ;SELECT UNIT 0 CALL HOME ;SEEK TRACK ZERO LD HL,CCP ;Start from base of CP/M LD BC,0D02H CALL RDLOOP ;READ EVEN SECTORS ON TRK 0 LD HL,CCP+80h LD BC,0C03H         CALL RDLOOP ;READ ODD SECTORS ON TRK 0 LD C,1 CALL SEEK ;SEEK TO TRACK 1 JR NZ,BOMB LD HL,CCP+0C80h LD BC,0A01H CALL RDLOOP ;READ ODD SECTORS ON TRK 1 LD HL,CCP+0D00h LD BC,0902H CALL RDLOOP ;READ EVEN SECTORS ON TRK 1 ; GOCPM: LD A,0C3H ;STORE JUMP VECTORS IN RAM LD (00H),A LD HL,CBIOS+3 ;JUMP TO CBIOS WARM BOOT AT 00H LD (01H),HL LD (05H),A LD HL,BDOS ;JUMP TO BDOS GOES AT 05H LD (06H),HL LD (38H),A LD HL,MONITR ;JUMP TO MONTR GOES AT 38H LD (39H),HL LD BC,0080H CALL SETPTR ;MAKE DISK BUFFER=0080H LD A,(4) ;Remind CP/M of previously LD C,A ; selected drive JP CCP ; ;Entry: B=Sector Count, C=Starting Sector, HL=Start Address ;Reads every other sector (1 sector interleve) RDLOOP: LD (POINTR),HL ;STORE ADDR. PASSED IN HL LD A,C LD (SECTOR),A ;STORE SECT# PASSED IN C PUSH HL PUSH BC CALL READ ;READ THE SPECIFIED SECTOR POP BC POP HL JR NZ,BOMB INC H ;BUMP LOAD ADDRESS BY 256 INC C INC C ;BUMP SECTOR# BY 2 DJNZ RDLOOP RET ; ; BOMB: LD HL,DEAD Š CALL PMSG LOOP: JR LOOP DEAD: DEFB CR,LF DEFM 'boot er$' page ;******************************************************** ;* * ;* Simple Character I/O Routines * ;* * ;******************************************************** ; CONOUT: LD A,C JP MONITR+12 ;MONITOR CONSOLE OUTPUT RTN. ; ; LSTST: LD A,(LSTRDY) ;Check List device status RET ; A=0 if not ready, else FF ; ; LSTOUT: LD A,(LSTRDY) ;List output routine. OR A ; Wait for device ready JR Z,LSTOUT ; XOR A ; Then set device busy LD (LSTRDY),A LD A,C OUT (LSTDAT),A ; and output the char RET ; ; ;List device interrupt handler. Simply sets "ready" flag. LSTIH: LD (SAVSTK),SP ;Save users stack pointer LD SP,STACK PUSH AF LD A,0FFh ;Set ready code into flag LD (LSTRDY),A POP AF LD SP,(SAVSTK) ;Restore users stack EI RETI PAGE ;******************************************************** ;* * ;* DISK I/O SUBROUTINES FOR CP/M CBIOS * ;* * ;******************************************************** ; ; ; SECTOR TRANSLATE TABLE FOR STANDARD ; 1 IN 6 INTERLEAVE FACTOR ; SECTAB: DEFB 1,7,13,19 DEFB 25,5,11,17 DEFB 23,3,9,15 DEFB 21,2,8,14 Š DEFB 20,26,6,12 DEFB 18,24,4,10 DEFB 16,22 ; ; ; DISK PARAMETER BLOCK FOR STANDARD 8" FLOPPY ; DPBLK: DEFW 26 ;SECTORS PER TRACK DEFB 3 ;BLOCK SHIFT CONST. DEFB 7 ;BLOCK MASK CONST. DEFB 0 ;EXTENT MASK CONST. DEFW 242 ;MAX BLOCK# DEFW 63 ;MAX DIRECTORY ENTRY# DEFB 11000000B ;ALLOCATION MASK MSB DEFB 00000000B ;' ' LSB DEFW 16 ;CHECK SIZE DEFW 2 ;RESERVED TRACKS ; ; ; DISK PARAMETER HEADERS FOR A 4 DISK SYSTEM ; DPHTAB: DEFW SECTAB,0000H ;DPH FOR UNIT 0 DEFW 0000H,0000H DEFW DIRBUF,DPBLK DEFW CHK0,ALL0 DEFW SECTAB,0000H ;DPH FOR UNIT 1 DEFW 0000H,0000H DEFW DIRBUF,DPBLK DEFW CHK1,ALL1 DEFW SECTAB,0000H ;DPH FOR UNIT 2 DEFW 0000H,0000H DEFW DIRBUF,DPBLK DEFW CHK2,ALL2 DEFW SECTAB,0000H ;DPH FOR UNIT 3 DEFW 0000H,0000H DEFW DIRBUF,DPBLK DEFW CHK3,ALL3 ; ; ; ; ; TRANS: EX DE,HL ;ADD TRANSLATION TABLE ADDRESS ADD HL,BC ; PASSED IN DE TO SECTOR# IN BC LD L,(HL) LD H,0 ;LOOKUP PHYSICAL SECTOR NUMBER RET ; AND RETURN IT IN HL ; ; SETSEC: LD A,C LD (SECTOR),A ;STORE SECTOR NUMBER PASSED RET ; VIA BC Š; SETPTR: LD (POINTR),BC ;STORE DATA POINTER PASSED RET ; VIA BC page ;SELECT returns the correct Disk Parameter Block pointer ;immediatly and sets the new unit number in TUNIT for the ;official select call to SELNOW in the read, write, ;and seek routines. ; SELECT: LD HL,0 ;PREP TO CHECK FOR MAX UNIT# LD A,C CP 4 RET NC ;RETURN WITH HL=0 IF C > 3 LD (TUNIT),A ;STORE C AS NEW DRIVE UNIT# LD L,A ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL ;MULTIPLY UNIT# BY 16 LD DE,DPHTAB ADD HL,DE ;ADD START ADDRESS OF DHP BLOCK RET ; SELNOW: LD A,(UNIT) ;Do select now. Retreive LD C,A ; old unit and LD A,(TUNIT) ; check if same as request CP C ; RET Z ; and return if same LD (UNIT),A ;otherwise save new unit as perm. SEL2: LD C,A ; put in C for monitor call LD B,0 ;seek speed (useless??) CALL MONITR+27 ; and do seek thru monitor RET Z ; exiting if no error LD C,1 ;else report error CALL REPORT JR NZ,SELERR ;give up if ^C typed after msg. LD A,(UNIT) ; else retry JR SEL2 ; SELERR: POP HL ;Skip return address and return LÄ  A,±  ; tï CP/Í w/ A=± to RET ; indicate error ; ; ; HOME: CALL SELNOW ;Select drive for home CALL MONITR+30 ;CALL HOME ROUTINE IN MONITOR RET Z ;RETURN IF ALL WENT WELL LD C,2 CALL REPORT JR Z,HOME ;RE-TRY HOME IF ERROR INDICATED RET ; ; SEEK: LD A,C ;GET TRACK # FROM C Š LD (TRACK),A ;Save for possible error CALL SELNOW ;Select drive SEEK1: LD A,(TRACK) ;put back in C for monitor LD C,A CALL MONITR+33 ;CALL SEEK ROUTINE IN MONITOR RET Z ;EXIT IF NO ERRORS INDICATED LD C,2 CALL REPORT ;REPORT SEEK ERROR TO CONSOLE RET NZ ;RETURN PERMANENT ERROR UNLESS JR SEEK1 ; ; ; READ: CALL SELNOW ;drive select LD HL,(POINTR) LD A,(SECTOR) LD C,A CALL MONITR+36 ;CALL READ ROUTINE IN MONITOR RET Z ;RETURN IF NO ERRORS LD C,3 ;INDICATE READ ERROR TO HANDLER CALL REPORT ;REPORT DISK ERROR TO CONSOLE JR Z,READ ;RE-TRY READ IF INDICATED RET ; ; ; WRITE: CALL SELNOW LD HL,(POINTR) LD A,(SECTOR) LD C,A CALL MONITR+39 ;CALL WRITE ROUTINE IN MONITOR RET Z ;RETURN IF NO ERRORS LD C,4 ;INDICATE WRITE ERROR TO HANDLER CALL REPORT ;REPORT DISK ERROR TO CONSOLE JR Z,WRITE ;RE-TRY WRITE IF INDICATED RET ;ELSE RETURN PERMANENT ERROR ; ; REPORT: LD (FLAGS),A ;STORE 1771 I/O STATUS FLAGS LD A,C LD (CLASS),A ;STORE COMMAND CLASS OF ERROR LD HL,DSKMSG CALL PMSG ;PRINT OUT START OF MESSAGE DEC HL LD A,(CLASS) LD B,A REP1: CALL SKIP ;SKIP TO NEXT '$' IN STRING @ HL DJNZ REP1 CALL PMSG ;PRINT STRING NOW POINTED TO BY HL LD HL,ERRMSG CALL PMSG ;PRINT 'error ' AFTER TYPE LD A,(FLAGS) RLA ;TEST FIRST FOR DRIVE-NOT-READY ERROR JR C,REP8 ; AND JUMP IF THAT IS THE PROBLEM LD E,A ;GET REMAINING 1771 ERROR BITS INTO E Š LD HL,RWERRS LD A,(CLASS) CP 3 ;DETERMINE IF SELECT/SEEK OF R/W ERROR JR NC,REP2 LD HL,SKERRS ;POINT HL TO PROPER SET OF MESSAGES REP2: LD B,5 RES 0,D REP4: SLA E ;SHIFT OUT A 1771 STATUS REG BIT JR NC,REP5 LD C,',' BIT 0,D CALL NZ,OVECTR ;PRINT COMMA BETWEEN STRINGS IF D=1 CALL PMSG ;THEN PRINT ERROR MESSAGE @ HL SET 0,D ;FLAG THAT A STRING WAS PRINTED JR REP6 REP5: CALL SKIP ;SKIP TO NEXT STRING @ HL RES 0,D ;FLAG THAT A STRING WAS SKIPPED REP6: DJNZ REP4 ;REPEAT FOR ALL 5 POSSIBLE ERRORS LD HL,TSMSG CALL PMSG ;PRINT TRACK/SECTOR# HEADER LD A,(TRACK) CALL PUT2HX ;PRINT TRACK# IN HEX LD C,'/' CALL OVECTR LD A,(SECTOR) CALL PUT2HX REP7: LD A,1 OR A ;RETURN PERM ERROR INDICATION IN A RET ; REP8: LD HL,RDYMSG CALL PMSG ;PRINT DISK-NOT-READY MESSAGE CALL IVECTR ; AND WAIT FOR CONSOLE INPUT CP 'C'-64 JR Z,REP7 XOR A ;RETURN A=0 IF SOMETHING OTHER THAN RET ; CONTROL-C WAS TYPED AT THE CONSOLE ; SKIP: PUSH BC ;SAVE BC LD B,255 LD A,'$' CPIR ;SCAN MEMORY LOOKING FOR '$' POP BC RET ; ; ; ; CHARACTER STRING OUTPUT ROUTINE. PRINTS ASCII DATA ; POINTED TO BY HL UNTIL A DOLLAR SIGN IS ENCOUNTERED PMSG: LD A,(HL) ;HL POINTS TO ASCII STRING CP '$' INC HL RET Z Š LD C,A ;PRINT CHARACTER IF NOT DOLLAR SIGN CALL OVECTR JR PMSG ; ; PUT2HX: PUSH AF RRA RRA RRA RRA CALL PUTNIB POP AF PUTNIB: AND 00001111B ADD A,90H DAA ADC A,40H DAA LD C,A CALL OVECTR ;PRINT A HEX-ASCII CHARACTER RET ; page DSKMSG: DEFB CR,LF DEFM 'bios $' DEFM 'sel $' DEFM 'seek $' DEFM 'rd $' DEFM 'wr $' ; ERRMSG: DEFM 'error $' ; SKERRS: DEFM '$' DEFM '$' DEFM 'cannot seek$' DEFM 'crc$' DEFM 'no restore$' RDYMSG: DEFM 'not rdy -$' ;drive not ready RWERRS: DEFM 'wp$' ;write protect DEFM 'wf$' ;write fault DEFM 'rnf$' ;record not found DEFM 'crc$' ;bad CRC DEFM 'do$' ;data overrun ; TSMSG: DEFM ' t/s = $' ;track/sector ; SIGNON: DEFB CR,LF DEFB 1Ah ;Clear screen DEFM 'Hi Mark, this is CP/M V' ; if CPM14 DEFM '1.4' else DEFM '2.2' endif Š; DEFM ' (' DEFB (sovers AND 0FF00h) SHR 8 ;sign on version DEFB sovers AND 0FFh DEFM ')' DEFB '$' ; ; LSTRDY: DEFS 1 ;List device ready flag UNIT: DEFS 1 TUNIT: DEFS 1 ;Temp unit number TRACK: DEFS 1 SECTOR: DEFS 1 POINTR: DEFS 1 FLAGS: DEFS 1 CLASS: DEFS 1 DEFS 32 STACK: DEFS 1 ;LOCAL STACK FOR WARM BOOT SAVSTK: DEFS 2 page ;******************************************************** ;* * ;* DISK I/O BUFFERS FOR BDOS FILE HANDLER * ;* * ;******************************************************** ; ; ; DIRBUF: DEFS 128 ;SCRATCH DIRECTORY BUFFER ; ALL0: DEFS 32 ;UNIT 0 ALLOCATION BUFFER CHK0: DEFS 16 ;UNIT 0 CHECK VECTOR ALL1: DEFS 32 ;UNIT 1 ALLOCATION VECTOR CHK1: DEFS 16 ;UNIT 1 CHECK VECTOR ALL2: DEFS 32 ;UNIT 2 ALLOCATION VECTOR CHK2: DEFS 16 ;UNIT 2 CHECK VECTOR ALL3: DEFS 32 ;UNIT 3 ALLOCATION VECTOR CHK3: DEFS 16 ;UNIT 3 CHECK VECTOR ; ; ; ; .DEPHASE ; END