; ; ; *************************************** ; * * ; * MAPBIOS3 FOR THE CMD * ; * 02-05-81 * ; * * ; *************************************** ; ; THIS BIOS IS SET UP FOR IMSAI SIO, TARBELL FLOPPIES ; AS DRIVES M AND N, AND A CDC PHOENIX AS ; DRIVES A THRU L. ; BLOCKING AND DEBLOCKING HAVE BEEN INCORPORATED!! ; TRACK MAPPING ADDED ; REQUIRES USE OF A "NORMAL BOOT ROM", NOT A CMD ROM. ; THIS IS BECAUSE THE LSB OF HEAD IS NOT INVERTED. MSIZE EQU 48 ;CP/M VERSION MEMORY SIZE IN KILOBYTES ; CPM IS GENERATED BY MOVCPM 45 * ; "BIAS" IS ADDRESS OFFSET FROM 3400H FOR MEMORY SYSTEMS ; THAN 16K (REFERRED TO AS "B" THROUGHOUT THE TEXT). ; CSTAT EQU 3 ;CONSOLE STATUS PORT CDATA EQU 2 ;CONSOLE DATA PORT CKBR EQU 2 ;KEYBOARD READY BIT CPTR EQU 1 ;DISPLAY READY BIT ; LPSTAT EQU 5 ;LIST DEVICE STATUS PORT LDATA EQU 4 ;LIST DEVICE DATA PORT LRBIT EQU 4H ;LIST READY BITS LRPOL EQU 0 ;LIST POLARITY BITS LPST2 EQU 8 ;LIST DEV. STAT.PORT 2 LPRB2 EQU 80H ;LIST DEV. READY BIT 2 ; FALSE EQU 0 TRUE EQU NOT FALSE I8251 EQU TRUE ;TRUE IF CONSOLE & PRINTER USE 8251 SIO INTRP EQU FALSE ;TRUE IF INTERRUPTS IN SYSTEM PERSCI EQU FALSE ;TRUE IF FLOPPY IS FAST SEEK DUAL EQU FALSE ;RUE IF FLOPPY HAS 2 DRIVES/SPINDLE HLOPT EQU FALSE ;TRUE IF HEADLOAD OPTION CODE DMA EQU FALSE ;SET TRUE ONLY IF YOU CAN RUN DMA ; NUMDSK EQU 14 ;NO.OF LOGICAL DISKS NUMHRD EQU 12 ;NO.OF LOGICAL HARD DISKS FLP1ST EQU FALSE ;FALSE IF FLOPS LAST, TRUE IF 1ST HEADQ EQU 6 MAXTRK EQU 803 CMD EQU TRUE ; BIAS EQU (MSIZE-23)*1024 ;USES CPM45.COM!!! CCP EQU 3400H+BIAS-200H ;BASE OF CCP (-200 NEEDED FOR SOME 2.2) BDOS EQU CCP+806H ;BASE OF BDOS BIOS EQU CCP+1600H ;BASE OF BIOS CDISK EQU 0004H ;CURRENT DISK NUMBER 0=A,...,15=P IOBYTE EQU 0003H ;INTEL I/O BYTE WRALL EQU 0 ;WRITE TO ALOCATED WRDIR EQU 1 ;WRITE TO DIRECTORY WRUAL EQU 2 ;WRITE TO UNALLOCATED BLKSIZE EQU 16384 ; HSTSIZ EQU 512 ;HARD DISK SECTOR SIZE HSTSPT EQU 36 ;SECTORS PER TRACK ON HARD DISK HSTBLK EQU HSTSIZ/128 ;CPM SECTORS PER HARD DISK SECTOR SECMSK EQU HSTBLK-1 ;SECTOR MASK CPMSPT EQU HSTBLK*HSTSPT SECSHF EQU 2 MAPEN EQU TRUE ;DISABLE MAPPING BY SETTING FALSE ; ORG BIOS ;ORIGIN OF THIS PROGRAM NSECTS EQU ($-CCP)/128 ;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 ; ; TABLES FOR TWO FLOPPIES AND ONE CMD DRIVE ; DISK PARAMETER TABLE FOR HARD DISK,TOP PLATTER,OUTSIDE TRACKS DPBASE: DW 0000H,0000H DW 0000H,0000H DW DIRBF,DPBLK2 DW CHK02,ALL02 ; DISK PARAMETER TABLE FOR HARD DISK,TOP PLATTER,INSIDE TRACKS DW 0000H,0000H DW 0000H,0000H DW DIRBF,DPBLK2 DW CHK03,ALL03 ; DISK PARAMETER TABLE FOR HARD DISK,BOTTOM SIDE,OUTSIDE TRACKS. DW 0000H,0000H DW 0000H,0000H DW DIRBF,DPBLK3 DW CHK04,ALL04 ; DISK PARAMETER TABLE FOR HARD DISK,BOTTOM SIDE,INSIDE TRACKS DW 0000H,0000H DW 0000H,0000H DW DIRBF,DPBLK3 DW CHK05,ALL05 ; DW 0000H,0000H DW 0000H,0000H DW DIRBF,DPBLK3 DW CHK06,ALL06 ; DW 0000H,0000H DW 0000H,0000H DW DIRBF,DPBLK3 DW CHK07,ALL07 ; DW 0000H,0000H DW 0000H,0000H DW DIRBF,DPBLK3 DW CHK08,ALL08 ; DW 0000H,0000H DW 0000H,0000H DW DIRBF,DPBLK3 DW CHK09,ALL09 ; DW 0000H,0000H DW 0000H,0000H DW DIRBF,DPBLK3 DW CHK10,ALL10 ; DW 0000H,0000H DW 0000H,0000H DW DIRBF,DPBLK3 DW CHK11,ALL11 ; DW 0000H,0000H DW 0000H,0000H DW DIRBF,DPBLK3 DW CHK12,ALL12 ; DW 0000H,0000H DW 0000H,0000H DW DIRBF,DPBLK3 DW CHK13,ALL13 ; ; DISK PARAMETER TABLES FOR FLOPPIES DW TRANS,0000H DW 0000H,0000H DW DIRBF,DPBLK DW CHK00,ALL00 DW TRANS,000H DW 0000H,0000H DW DIRBF,DPBLK DW CHK01,ALL01 ; ; SECTOR TRANSLATE TABLE, FOR FLOPPIES ONLY TRANS: DB 1,7,13,19 ;SECTORS 1,2,3,4 DB 25,5,11,17 ;SECTORS 5,6,7,8 DB 23,3,9,15 ;SECTORS 9,10,11,12 DB 21,2,8,14 ;SECTORS 13,14,15,16 DB 20,26,6,12 ;SECTORS 17,18,19,20 DB 18,24,4,10 ;SECTORS 21,22,23,24 DB 16,22 ;SECTORS 25,26 ; DPBLK: ;DISK PARAMETER BLOCK, FLOPPIES DW 26 ;SECTORS PER TRACK DB 3 ;BLOCK SHIFT FACTOR DB 7 ;BLOCK MASK DB 0 ;NULL MASK DW 242 ;DISK SIZE-1 DW 63 ;DIRECTORY MAX DB 192 ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;CHECK SIZE DW 2 ;TRACK OFFSET DPBLK2 DW 144 ;SECTORS PER TRACK DB 6 ;BLOCK SHIFT FACTOR FOR BLS=8,192 DB 63 ;BLM DB 3 ;EXM DW 899 ;DISK SIZE-1 DW 511 ;DIRECTORY MAX DB 0C0H ;ALLOC0 DB 00H ;ALLOC1 DW 128 ;CHECK SIZE DW 2 ;OFFSET DPBLK3 DW 144 DB 6 DB 63 DB 3 DW 899 DW 511 ;DIRECTORY MAX,(FIXED REQUIRES NO CHECK ; SO THE DIRECTOR IS LARGER, = BLS 8K) DB 0C0H DB 00H DW 0 ;0 FOR FIXED DW 2 ;OFFSET ; ; END OF FIXED TABLES ; ; INDIVIDUAL SUBROUTINES TO PERFORM EACH FUNCTION BOOT: ;SIMPLEST CASE IS TO JUST PERFORM PARAMETER INITIALIZATION LXI SP,CCP-2 ;SET STACK TO TPA TOP -2 IF I8251 MVI A,0CAH ;USED TO BE 0CEH & 27 BELOW WAS 37 OUT CSTAT OUT LPSTAT MVI A,027H OUT CSTAT OUT LPSTAT ENDIF IF MAPEN ;IF TRACK MAP OPTION IS ENABLED, MAKE MAP CALL SMAPPER ENDIF XRA A ;ZERO IN THE ACCUM STA IOBYTE ;CLEAR THE IOBYTE STA CDISK ;SELECT DISK ZERO LXI H,SINGMES ;PRINT THE SIGN ON MESSAGE CALL PRMSG JMP WBOOT ;INITIALIZE AND GO TO CP/M SINGMES DB 0DH,0AH DB 'CPM 2.2 , USING KONAN MAPBIOS3 ' DB 0 ; WBOOT: ;SIMPLEST CASE IS TO READ THE DISK UNTIL ALL SECTORS LOADED XRA A STA HSTACT ;HOST BUFFER INACTIVE STA UNACNT ;CLEAR UNALLOCATED COUNT LXI SP,80H ;USE SPACE BELOW BUFFER FOR STACK MVI C,0 ;SELECT DISK 0 CALL SELDSK CALL HOME ;GO TO TRACK 00 ; MVI B,NSECTS ;B COUNTS # OF SECTORS TO LOAD MVI C,0 ;C HAS THE CURRENT TRACK NUMBER MVI D,4 ;D HAS THE NEXT SECTOR TO READ ; NOTE THAT WE BEGIN WITH CPM SECTOR 4, THE SECOND PHYSICAL ; SECTOR ON THE HARD DISK LXI H,CCP ;BASE OF CP/M (INITIAL LOAD POINT) LOAD1: ;LOAD ONE MORE SECTOR PUSH B ;SAVE SECTOR COUNT, CURRENT TRACK PUSH D ;SAVE NEXT SECTOR TO READ PUSH H ;SAVE DMA ADDRESS MOV C,D ;GET SECTOR ADDRESS TO REGISTER C CALL SETSEC ;SET SECTOR ADDRESS FROM REGISTER C POP B ;RECALL DMA ADDRESS TO B,C PUSH B ;REPLACE ON STACK FOR LATER RECALL CALL SETDMA ;SET DMA ADDRESS FROM B,C ; ; DRIVE SET TO 0, TRACK SET, SECTOR SET, DMA ADDRESS SET CALL READ CPI 00H ;ANY ERRORS? JNZ WBOOT ;RETRY THE ENTIRE BOOT IF AN ERROR OCCURS ; ; NO ERROR, MOVE TO NEXT SECTOR POP H ;RECALL DMA ADDRESS LXI D,128 ;DMA=DMA+128 DAD D ;NEW DMA ADDRESS IS IN H,L POP D ;RECALL SECTOR ADDRESS POP B ;RECALL NUMBER OF SECTORS REMAINING, AND CURRENT TRK DCR B ;SECTORS=SECTORS-1 JZ GOCPM ;TRANSFER TO CP/M IF ALL HAVE BEEN LOADED ; ; MORE SECTORS REMAIN TO LOAD, CHECK FOR TRACK CHANGE INR D MOV A,D ;SECTOR=27?, IF SO, CHANGE TRACKS CPI 27 ; REMOVE FOLLOWING TO BOOT OFF FLOPPY JMP LOAD1 JC LOAD1 ;CARRY GENERATED IF SECTOR<27 ; ; END OF CURRENT TRACK, GO TO NEXT TRACK MVI D,1 ;BEGIN WITH FIRST SECTOR OF NEXT TRACK INR C ;TRACK=TRACK+1 ; ; SAVE REGISTER STATE, AND CHANGE TRACKS PUSH B PUSH D PUSH H CALL SETTRK ;TRACK ADDRESS SET FROM REGISTER C POP H POP D POP B JMP LOAD1 ;FOR ANOTHER SECTOR ; ; END OF LOAD OPERATION, SET PARAMETERS AND GO TO CP/M GOCPM: MVI A,0C3H ;C3 IS A JMP INSTRUCTION STA 0 ;FOR JMP TO WBOOT LXI H,WBOOTE ;WBOOT ENTRY POINT SHLD 1 ;SET ADDRESS FIELD FOR JMP AT 0 ; STA 5 ;FOR JMP TO BDOS LXI H,BDOS ;BDOS ENTRY POINT SHLD 6 ;ADDRESS FIELD OF JUMP AT 5 TO BDOS ; LXI B,80H ;DEFAULT DMA ADDRESS IS 80H CALL SETDMA ; ;EI ;ENABLE THE INTERRUPT SYSTEM LDA CDISK ;GET CURRENT DISK NUMBER MOV C,A ;SEND TO THE CCP MVI B,0 ;SEE IF THIS FIXES BUG JMP CCP ;GO TO CP/M FOR FURTHER PROCESSING ; ; ; PHYSICAL DEVICE I/O DRIVERS FOLLOW. ; CONST: ;CONSOLE STATUS, RETURN 0FFH IF CHARACTER READY, 00H IF NOT IN CSTAT ;READ CONSOLE STATUS ANI CKBR ;LOOK AT READY BIT JNZ CDAV MVI A,0 ;IF NOT READY A=0 RET CDAV: MVI A,0FFH ;IF READY A=0FF RET ; CONIN: ;CONSOLE CHARACTER INTO REGISTER A IN CSTAT ;READ CONSOLE STATUS PORT ANI CKBR ;WAIT UNTIL READY JZ CONIN IN CDATA ;READ DATA PORT ANI 7FH ;CLEAR BIT 7 RET ; CONOUT: ;CONSOLE CHARACTER OUTPUT FROM REGISTER C IN CSTAT ;READ CONSOLE STATUS ANI CPTR ;WAIT IF NOT READY JZ CONOUT MOV A,C ;GET DATA CHARACTER OUT CDATA ;OUTPUT IT RET ; LIST: ;LIST CHARACTER FROM REGISTER C IN LPSTAT ;READ LIST STATUS ANI LRBIT ;LOOK AT READY BITS JZ LIST ;THIS & NEXT 3 LINES REPLACE LIST2 IN LPST2 ;FOLLOWING 2 LINES (XRI & JNZ) ANI LPRB2 JNZ LIST2 ; XRI LRPOL ;SELECT READY POLARITYS ; JNZ LIST ;WAIT UNTIL NOT BUSY MOV A,C ;GET DATA BYTE OUT LDATA ;PRINT IT RET ; LISTST: ;RETURN LIST STATUS (0 IF NOT READY, 1 IF READY) IN LPSTAT ;READ LIST STATUS ANI LRBIT ;SELECT READY BITS XRI LRPOL ;SELECT READY POLARITY JZ LISRDY XRA A ;RETURN 0 IF NOT READY RET LISRDY: MVI A,1 ;RETURN 1 IF READY RET ; PUNCH: ;PUNCH CHARACTER FROM REGISTER C MOV A,C ;CHARACTER TO REGISTER A 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 ; ; ; I/O DRIVERS FOR THE DISK FOLLOW ; FOR NOW, WE WILL SIMPLY STORE THE PARAMETERS AWAY FOR USE ; IN THE READ AND WRITE SUBROUTINES ; HOME: ;MOVE TO THE TRACK 00 POSITION OF CURRENT DRIVE ; TRANSLATE THIS CALL INTO A SETTRK CALL WITH PARAMETER 00 LXI B,0 ;SET TRACK TO ZERO CALL SETTRK RET ;WE WILL MOVE TO 00 ON FIRST READ/WRITE ; SELDSK: ;SELECT DISK GIVEN BY REGISTER C LXI H,0000H ;ERROR RETURN CODE MOV A,C STA DISKNO STA SEKDSK ;FOR BLOCK/DEBLOCK CPI NUMDSK ;MUST BE BETWEEN 0 AND NUMDSK-1 RNC ;NO CARRY IF 4,5,... ; DISK NUMBER IS IN THE PROPER RANGE ; COMPUTE PROPER DISK PARAMETER HEADER ADDRESS LDA DISKNO MOV L,A ;L=DISK NUMBER 0,1,2,3 MVI H,0 ;HIGH ORDER ZERO DAD H ;*2 DAD H ;*4 DAD H ;*8 DAD H ;*16 (SIZE OF EACH HEADER) LXI D,DPBASE DAD D ;HL=.DPBASE(DISKNO*16) RET ; SETTRK: ;SET TRACK GIVEN BY REGISTER C MOV H,B MOV L,C SHLD SEKTRK ;FOR BLOCK/DEBLOCK SHLD TRACK ;FOR FLOPPY RET ; SETSEC: ;SET SECTOR GIVEN BY REGISTER C MOV A,C STA SECTOR STA SEKSEC ;FOR BLOCK/DEBLOCK RET ; SECTRAN: ;TRANSLATE THE SECTOR GIVEN BY BC USING THE ;TRANSLATE TABLE GIVEN BY DE MOV A,D ORA E MOV H,B MOV L,C RZ XCHG ;HL=.TRANS DAD B ;HL=.TRANS(SECTOR) MOV L,M ;L = TRANS(SECTOR) MVI H,0 ;HL= TRANS(SECTOR) RET ;WITH VALUE IN HL ; SETDMA: ;SET DMA ADDRESS GIVEN BY REGISTERS B AND C MOV L,C ;LOW ORDER ADDRESS MOV H,B ;HIGH ORDER ADDRESS SHLD DMAAD ;SAVE THE ADDRESS RET ; READ: ;PERFORM READ OPERATION (USUALLY THIS IS SIMILAR TO WRITE ; SO WE WILL ALLOW SPACE TO SET UP READ COMMAND, THEN USE ; COMMON CODE IN WRITE) PUSH PSW MVI A,0FFH ;READ JMP WAITIO ; WRITE: ;PERFORM A WRITE OPERATION PUSH PSW MOV A,C STA WRTYPE XRA A ;WRITE ; WAITIO: ;ENTER HERE FROM READ AND WRITE TO PERFORM THE ACTUAL I/O ; OPERATION. RETURN A 00H IN REGISTER A IF THE OPERATION COMPLETES ; PROPERLY, AND 01H IF AN ERROR OCCURS DURING THE READ OR WRITE ; ; NOTE ABOUT THE STATE SAVE: ; SOME SOFTWARE (NOTEABLY MICROSOFT, AND WORD PROCESSORS) ; LEAVE VERY LITTLE ROOM ON THE STACK. TO INSURE A MAX ; STACK USAGE OF 2 WORDS (CALL AND PSW SAVE) AND ALLOW I/O ; DRIVERS TO USE SUBROUTINES, A STACK SWITCH AND STATE ; SAVE IS USED, TO PROTECT FOOLS FROM THEMSELVES. ; SHLD HLSAV ;SAVE HL REGISTER LXI H,0 ;GET OLD STACK ADDRESS DAD SP SHLD OLDSP LXI SP,NSTACK ;SETUP NEW STACK PUSH B PUSH D STA RORW ;READ OR WRITE SWITCH XRA A ;DEFAULT I/O OK STA DIOST JMP DSEL ; ; ; ; IN THIS CASE, WE HAVE SAVED THE DISK NUMBER IN 'DISKNO' (0-3) ; THE TRACK NUMBER IN 'TRACK' (0-76) ; THE SECTOR NUMBER IN 'SECTOR' (1-26) ; THE DMA ADDRESS IN 'DMAAD' (0-65535) ; THE READ (0FF) OR WRITE (0) CODE ; IN 'RORW' ; THE DEFAULT I/O STATUS OF OK ; IN 'DIOST' ; ; THE CURRENT SELECTED DISK NR IS IN 'CURDSK' (0-3) ; THE CURRENT DISK'S CURRENT TRACK IS IN 'CURTRK' ; ; ; DISK CONTROLLER PROCEDURE FOR THE TARBELL FLOPPY DISK CONTROLLER ; DVSEL: EQU 0FCH ;DRIVE SELECT PORT DCOM: EQU 0F8H ;COMMAND PORT DSTAT: EQU 0F8H ;DEVICE STATUS DWAIT: EQU 0FCH ;I/O WAIT READ PORT DDATA: EQU 0FBH ;FDC DATA PORT DTRACK: EQU 0F9H ;TRACK PORT DSECT: EQU 0FAH ;SECTOR PORT STPRAT: EQU 3 ;0,1,2, OR 3 STEP RATE (SEE 1771 D.S.) CLRCMD: EQU 0D0H ;CLEAR 1771 COMMAND RSTCMD: EQU 0+STPRAT ;RESTORE COMMAND SEKCMD: EQU 18H+STPRAT ;SEEK COMMAND (SLOW) SICMD: EQU 48H ;STEP IN COMMAND SOCMD: EQU 68H ;STEP OUT COMMAND ; CCODE: DB 0 ;CURRENT SELECT CODE LATCH CONTENTS SELCODE: DB 0F2H,0E2H,0D2H,0C2H ; ; ; SELECT DESIRED DISK DRIVE ; DSEL: LDA DISKNO ;DESIRED DRIVE NR TO DE IF NOT FLP1ST CPI NUMHRD JC HRDDSK ;HARDDISK IS 0-3, OTHERS FLOPPIES SBI NUMHRD ENDIF IF FLP1ST CPI NUMDSK-NUMHRD JNC HRDDSK ENDIF MOV E,A XRA A MOV D,A LDA CURDSK ;CURRENT DRIVE NR TO A CMP E ;SAME DRIVE? JZ TSEEK ;YES - SKIP SELECT MVI A,4 ;FORCE HEADLOAD STA HDLD LDA DISKNO ;SET SELECTED DRIVE NR IF NOT FLP1ST SBI NUMHRD ENDIF STA CURDSK LXI H,SELCODE ;LOOKUP SELECT CODE DAD D MOV A,M OUT DVSEL ;SELECT THE DRIVE STA CCODE ;SAVE LATCH CONTENTS LDA CURTRK ;SAVE CURRENT DRIVES LHLD CTADR ;CURRENT TRACK INDICATOR MOV M,A LXI H,DK0CT ;LOOKUP CURRENT TRACK IF DUAL MOV A,E ;FOR DUAL DRIVES USE ANI 0FEH ; DRIVE 0 AND 2 MOV E,A ;CURRENT TRACK STORAGE ENDIF DAD D SHLD CTADR ;SAVE THIS DRIVES CURRENT TRACK POINTER MOV A,M ;AND ITS CURRENT TRACK STA CURTRK ; ; ; SEEK DESIRED TRACK ; TSEEK: LDA TRACK ;IS THE DESIRED TRACK MOV E,A LDA CURTRK ;THE SAME AS THE CMP E ;CURRENT TRACK? JZ DOIO ;YES. GO DO I/O CPI 0FFH ;HOME DISK NEEDED? JNZ DOSEEK ;NO - DO SEEK ; IF NOT PERSCI HBSY: IN DSTAT ;WAIT FOR NOT BUSY RRC JC HBSY MVI A,RSTCMD ;RESTORE COMMAND OUT DCOM IN DWAIT ;WAIT FOR INTRQ (OPCOMP) NOP IN DSTAT ANI 4 ;LOOK AT STATUS JZ HBSY ;RETRY RESTORE IF ERROR XRA A STA CURTRK ;SET CURRENT TRACK TO ZERO JMP TSEEK ;GO CHECK FOR SEEK DOSEEK: MOV A,E ;SEND DESIRED TRACK OUT DDATA SBSY: IN DSTAT ;WAIT FOR NOT BUSY RRC JC SBSY MVI A,SEKCMD ;SEEK WITH VERIFY COMMAND OUT DCOM IN DWAIT ;WAIT FOR INTRQ (OPCOMP) NOP ENDIF ; IF PERSCI HBSY: MVI A,CLRCMD ;CLEAR ANY CURRENT OPN OUT DCOM IWT: IN DSTAT ;WAIT NOT BUSY ANI 1 JNZ IWT LDA CCODE ;ISSUE PERSCI RESTORE ANI 0BFH OUT DVSEL MVI A,RSTCMD ;ISSUE 1771 RESTORE OUT DCOM IN DWAIT ;WAIT FOR COMPLETION LDA CCODE ;RE-SELECT DRIVE OUT DVSEL XRA A ;SET CURRENT TRACK 0 STA CURTRK JMP TSEEK ;NOW DO TRACK SEEK DOSEEK: SUB E ;CURRENT-DESIRED TRACK MOV B,A ;NR STEPS TO B JP STPOUT ;POSITIVE - STEP OUT B TRACKS CMA ;-A TO A INR A MOV B,A ;NR STEPS TO B MVI A,SICMD ;SELECT STEP IN JMP GOSEEK STPOUT: MVI A,SOCMD ;SELECT STEP OUT GOSEEK: OUT DCOM ;ISSUE STEP COMMAND STA LSTSEK ;SAVE LAST SEEK COMMAND MOV A,B ;SAVE NR OF STEPS STA STPS MVI C,20H ;WAIT FOR DIRECTION LINE STLUP: DCR C ;TO SETTLE JNZ STLUP MVI A,1 SPLUP: OUT DVSEL ;ISSUE STEP PULSES DCR B JNZ SPLUP IN DWAIT ;CLEAR 1771 MOV A,E OUT DTRACK ;UPDATE 1771 TRACK REGISTER LDA CCODE ;ISSUE WAIT FOR SEEK COMPLETE ANI 72H ;CODE OUT DVSEL IN DWAIT ;WAIT FOR SEEK COMPLETE LDA CCODE OUT DVSEL ;NOW RESELECT DISK DRIVE ENDIF ; SDONE: IN DSTAT ;IF ERROR STA SSTAT ANI 091H JNZ HBSY ;GO RE-HOME DRIVE IN DTRACK STA CURTRK ;SAVE NEW CURRENT TRACK ; ; NOW DO THE READ OR WRITE SECTOR ; DOIO: MVI A,11 ;RETRY COUNT +1 MOV B,A JMP TRY1 RETRY: DCR B ;DECREMENT RETRY JZ ERROR ;EXIT IF HARD ERROR MVI A,04H ;REQUIRE HEADLOAD ON ALL RETRYS STA HDLD TRY1: LDA SECTOR OUT DSECT ;ISSUE SECTOR DESIRED LHLD DMAAD ;AND SET I/O BUFFER ADDRESS LDA RORW ;SELECT READ OR WRITE CPI 0 JZ DWRITE ;GO WRITE SECTOR ; IF INTRP DI ;DISABLE INTERRUPTS ENDIF LDA HDLD ;SELECT HEADLOAD OPTION ORI 088H ;READ COMMAND OUT DCOM RLOOP: IN DWAIT ;WAIT FOR DRQ ORA A ;CHECK FOR INTRQ (OPCOMP) JP RDONE IN DDATA ;GET BYTE MOV M,A ;STORE IT INX H ;BUMP POINTER JMP RLOOP ;GO GET NEXT BYTE RDONE: IN DSTAT ;READ STATUS IF INTRP ;EI ;RE-ENABLE INTERRUPTS ENDIF STA LSTAT ANI 09DH ;RETRY IF ERROR JNZ RETRY JMP DDONE ;READ COMPLETE ; DWRITE: ; IF INTRP DI ;DISABLE INTERRUPTS ENDIF LDA HDLD ;SELECT HEADLOAD OPTION ORI 0A8H ;WRITE COMMAND OUT DCOM WLOOP: IN DWAIT ;CHECK DRQ ORA A JP WDONE ;END IF INTRQ (ENDOP) MOV A,M ;GET DATA OUT DDATA ;AND SEND IT INX H ;BUMP POINTER JMP WLOOP ;GO FOR NEXT BYTE WDONE: IN DSTAT ;WRITE OP STATUS IF INTRP ;EI ;RE-ENABLE INTERRUPTS ENDIF STA LSTAT ANI 0FDH ;RETRY IF ERROR JNZ RETRY JMP DDONE ;WRITE COMPLETE ERROR: MVI A,1 ;DISK I/O ERROR STA DIOST JMP EDONE ; ; ; ; I/O COMPLETE. DDONE: ; DISK I/O DONE IF HLOPT XRA A ;CLEAR HEADLOAD REQUIRED STA HDLD ENDIF EDONE: POP D ;RESTORE DE AND BC FROM NSTACK POP B LHLD OLDSP ;RESTORE OLD STACK SPHL LHLD HLSAV ;RESTORE HL POP PSW LDA DIOST ;0 I/O OK, ELSE FAIL RET ; CURDSK: DB 0FFH ;CURRENT DISK (FF TO INITIALIZE) CURTRK: DB 0FFH ;CURRENT DISKS CURRENT TRACK DK0CT: DB 0FFH ;DRIVE 0 CURRENT TRACK DK1CT: DB 0FFH ;DRIVE 1 CURRENT TRACK DK2CT: DB 0FFH ;DRIVE 2 CURRENT TRACK DK3CT: DB 0FFH ;DRIVE 3 CURRENT TRACK LSTAT DB 0FFH ;LAST R/W STATUS SSTAT: DB 0FFH ;LAST SEEK STATUS LSTSEK: DB 0 ;LAST SEEK COMMAND STPS: DB 0FFH ;NR STEPS LAST SEEK CTADR: DW DK0CT ;CURRENT TRACK RESTORE ADDRESS ; HRDDSK LDA RORW CPI 0 JZ WRITEH ;IF RORW IS ZERO THEN WRITE THE HARD DISK READH: ;READ THE SELECTED CP/M SECTOR XRA A STA UNACNT ;UNACNT = 0 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 WRITEH: ;WRITE THE SELECTED CP/M SECTOR XRA A STA READOP ;NOT A READ OPERATION LDA WRTYPE CPI WRUAL ;WRITE UNALLOCATED? JNZ CHKUNA ;CHECK FOR UNALLOC ; WRITE TO UNALLOCATED, SET PARAMETERS MVI A,128 ;NEXT UNALLOC RECS STA UNACNT LDA SEKDSK ;UNADSK = SEKDSK STA UNADSK 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 STA UNACNT LDA SEKDSK ;SAME DISK? LXI H,UNADSK CMP M ;SEKDSK = UNADSK JNZ ALLOC ; DISK ARE THE SAME LXI H,UNATRK CALL SEKTRKCMP ;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 CPM SECTORA 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 JMP RWOPER ;TO PERFORM THE WRITE ALLOC: ;NOT AN UNALLOCATED RECORD, REQUIRES PRE-READ XRA A ;0 TO ACCUMULATOR STA UNACNT ;UNACNT = 0 INR A ;1 TO ACCUM STA RSFLAG ;RSFLAG = 1 ; ;********************************************************* ;* * ;* COMMON CODE FOR READ AD WRITE FOLLOWS ;* * ;********************************************************* ; RWOPER: ;ENTER HERE TO PERFORM THE READ/WRITE XRA A ;ZERO TO ACCUM STA DIOST ;NO ERRORS (YET) LDA SEKSEC ORA A ;CARRY = 0 RAR ;SHIFT RIGHT ORA A RAR 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,SAVE AS SEEK BUFFER? LDA SEKDSK LXI H,HSTDSK CMP M ;SEKDSK = HSTDSK? JNZ NOMATCH ; SAME DISK, SAME TRACK? LXI H,HSTTRK CALL SEKTRKCMP JNZ NOMATCH ; SAME DISK,SAME TRACK, SAME BUFFER? LDA SEKHST LXI H,HSTSEC ;SEKHST = HSTSEC? CMP M JZ MATCH ;SKIP IF MATCH NOMATCH: ;PROPER DSK, BUT NOT CORRECT SECTOR LDA HSTWRT ;HOST WRITTEN? ORA A CNZ WRITEHST ;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 READHST ;YES, IF 1 XRA A ;ZERO TO ACCUMULATOR 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 MVI H,0 ;DOUBLE COUNT DAD H 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 LHLD DMAAD ;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 SWITHC DIRECTION MVI A,1 STA HSTWRT ;HSTWRT = 1 XCHG RWMOVE: ;C INITIALLY 128, DE IS SOURCE, HL IS DEST LDAX D ;SOURCE CHARACTER INX D MOV M,A INX H DCR C ;LOOP 128 TIMES JNZ RWMOVE ;SKIP IF READ ; DATA HAS BEEN MOVED TO/FROM HOST BUFFER LDA WRTYPE ;WRITE TYPE CPI WRDIR ;TO DIRECTORY? LDA DIOST ;IN CASE OF ERRORS JNZ EDONE ;NO FURTHER PROCESSING ; CLEAR HOST BUFFER FOR DIRECTORY WRITE ORA A ;ERRORS? RNZ ;SKIP IF SO XRA A ;0TO ACCUMULATOR STA HSTWRT ;BUFFER WRITEN CALL WRITEHST LDA DIOST JMP EDONE ; SEKTRKCMP: ;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 BYTES INX D INX H LDAX D CMP M ;SET FLAGS RET ; THE KONAN HARD DISK DRIVER FOLLOWS. ; IOBASE EQU 90H BUSU EQU IOBASE BUSL EQU IOBASE+1 CMND EQU IOBASE+2 SCTAD EQU IOBASE+3 SCTBU EQU IOBASE+4 DMACL EQU IOBASE+5 DMACU EQU IOBASE+6 STATU EQU IOBASE+7 WRITEHST: ;ENTRY INTO THE WRITE PROGRAM CALL KCOMMON ;SETS SECTOR,DMA,HEAD,TRACK,UNIT RC ;ERROR RETURN XRA A ;CLEAR BUS OUT BUSL OUT BUSU ;BUS IS NOW CLEARED OUT STATU ;SECTOR BUFFER NOW ZEROED ; WRITE THE HEADER NOW (TRACK MSB,TRACK LSB,HEAD,SECTOR) LXI H,PTRK ;POINT TO THE TRACK MVI B,4 ;HEADER BYTE COUNT HEADWT MOV A,M ;GET BYTE IN ACUMULATOR OUT SCTBU ;SEND IT INX H DCR B ;DECREMENT COUNT JNZ HEADWT ;IF NOT DONE JMP TO HEADER WRITE IF DMA ;*************************** MVI A,02 ;DMA WRITE COMMAND OUT CMND ;DO THE WRITE ENDIF ;*************************** IF NOT DMA ;*************************** LXI H,HSTBUF;IO WRITE LOOP LXI D,HSTSIZ NXIOW MOV A,M OUT SCTBU INX H DCR E JNZ NXIOW DCR D JNZ NXIOW ENDIF ;************************** OUT STATU MVI A,1 ;DISK WRITE COMMAND OUT CMND ;DO THE WRITE CALL WT ;WAIT FOR IT TO FINISH MVI A,'A' ;ERROR A IS A TIMEOUT JC ERREPORT ;IF TIMEOUT, PRINT A IN STATU ;GET STATU ANI 20H ;IS FAULT ON? MVI A,'B' JNZ ERREPORT ;PRINT B IF WRITE FAULT ;REPORT END STATUS RET ;DONE WITH WRITE READHST: ;READ SUBROUTINE. READS VIA READINT THEN DOES DMA CALL READINT ;PLACE DATA INTO THE SECTOR BUFFER IF DMA ;**************************** MVI A,04H ;DMA READ COMMAND OUT CMND ;DO THE READ ENDIF IF NOT DMA ;**************************** LXI H,HSTBUF;IO READ LOOP LXI D,HSTSIZ NXIOR IN SCTBU MOV M,A INX H DCR E JNZ NXIOR DCR D JNZ NXIOR ENDIF ;**************************** RET ;RETURN READINT: ;READ TO SECTOR BUFFER CALL KCOMMON ;SET SECTOR,DMA,TRACK,HEAD,AND UNIT RC ;ERROR RETURN XRA A ;GENERATE A ZERO OUT BUSL ;CLEAN UP LOWER BUS OUT BUSU ;CLEAN UP UPPER BUS STA CERRC ;ZERO THE ERROR COUNT RDKON OUT STATU ;SET BUFFER TO ZERO MVI A,88H ;DISK READ COMMAND OUT CMND ;DO THE READ CALL WT ;WAIT FOR DONE MVI A,'C' CC ERREPORT ;PRINT C IF TIMEOUT ERROR JC RCOVRE ;GO ATTEMPT TO RECOVER THE TIMEOUT IN STATU ;GET ENDING STATUS ANI 4H ;IS CHECKSUM ON? JNZ CHKRECOV ;GO REPORT/RECOVER ; WE WILL NOW TEST THE HEADER LXI H,PTRK ;POINT TO THE TRACK MVI B,4 ;NUMBER OF HEADER BYTES OUT STATU ;ZERO BUFFER ADDRESS HDRTST IN SCTBU ;GET HEADER READ CMP M JNZ FRMTRCV ;RECOVER IF DIFFERENT DCR B INX H JNZ HDRTST ;IF HEADER COUNT IS NON ZERO TEST ONE MORE ; WHEN WE ARIVE HERE THE READ IS DONE. RET ; ; ; READ RECOVERY PROGRAM FOLLOWS CHKRECOV: MVI A,'D' CALL ERREPORT ;PRINT A D IF CHECKSUM ERROR JMP RCOVRE FRMTRCV MVI A,'E' CALL ERREPORT ;PRINT A E IF FORMAT ERROR RCOVRE: LDA CERRC INR A ;INCREMENT THE COUNT STA CERRC ;SAVE THE NEW COUNT MOV C,A ;SAVE THE ERROR COUNT ANI 3 ;GET LAST 2 BITS,STROBE EARLY AND LATE CPI 3 ;NOT LEGAL TO HAVE BOTH ON JZ RCOVRE ;IF ILLEGAL, GO TO NEXT CERRC MOV A,C ;GET THE ERROR COUNT ANI 18H ;GET THE OFFSET MINUS AND PLUS BITS CPI 18H ;ARE THE BOTH ON? JZ RCOVRE ;IF SO GO TO THE NEXT COUNT MOV A,C ;RESTORE THE ERROR COUNT CPI 20H ;IS THIS THE START OF THE SECOND PASS? CZ PANIC ;IF 20H WE WILL RETRY SEL,SEEK,MAPPER ETC. LDA CERRC ;RESTORE THE ERROR COUNT MOV C,A ;PLACE IT IN C FOR FUTURE RECALL ADI 0DCH ;TIME TO GIVE UP? JC HARDRDER ;IF CARRY WE HAVE A HARD READ ERROR ; IF WE GET HERE WE ARE READY TO SET RECOVERY BITS AND TRY AGAIN MOV A,C ;RESTORE ERROR COUNT RRC ;POSITION BITS ANI 8CH ;GET OFFSETS PLUS STROBE EARLY OUT BUSL ;SET THE BITS MOV A,C ;RESTORE ERROR COUNT RRC ;POSITION BITS ANI 1 ;STROBE LATE BIT OUT BUSU ;BUS NOW COMPLETE JMP RDKON ;GO DO THE READ RECOVERY HARDRDER: ;HARD DISK READ ERROR IN STATU ;SET THE READ BUFFER TO ADDRESS 4 IN SCTBU IN SCTBU IN SCTBU IN SCTBU MVI A,'F' ;HARD ERROR JMP ERREPORT ; ; KONAN DISK READ AND WRITE COMMON ROUTINE ; SETS THE SECTOR, DMA, UNIT, HEAD, AND TRACK ; ADDRESSES. NOTE THAT EVERY HEAD SELECT IS ; FOLLOWED BY A SEEK TO MAINTAIN COMPATIBILITY ; WITH CMD DRIVES. ; RETURNS WITH CARRY SET IF ERROR, RESET IF NOT ; KCOMMON: XRA A ;MAKE A ZERO STA DIOST ;SET ERROR FLAG TO ZERO LXI H,HSTBUF ;PLACE DMA ADDRESS IN H&L MOV A,L ;GET LSB OF DMA ADDRESS OUT DMACL ;SET LSB OF DMA ADDRESS MOV A,H ;GET MSB OF DMA ADDRESS OUT DMACU ;SET MSB OF DMA ADDRESS XRA A ;MAKE A ZERO OUT BUSL ;CLEAR THE LOWER BUS OUT BUSU ;CLEAR THE UPPER BUS CALL HSTPHY JMP COMCON HSTPHY ;CALCULATE THE PHYSICAL ADDRESS LHLD HSTTRK LXI D,-402 ;402 IS MAX TRACK PER UNIT DAD D ;IF CARRY TRACK IS ILLEGAL MVI A,'N' ;ERROR N IS ILLEGAL TRACK CC ERREPORT RC LXI D,402 ;OFFSET FOR INNER TRACKS LHLD HSTTRK ;CPM TRACK LDA HSTDSK ;0 FOR A, 1 FOR B, ETC IF FLP1ST SUI NUMDSK-NUMHRD ENDIF RRC ;PLACE LSB IN CARRY JNC INNER ;DO NOT ADD 402 IF INNER DAD D ;ADD 402 IF OUTER INNER ANI 0FH ;REMOVE END AROUND CARRY MVI B,0 ;B=UNIT, INITIALLY 0 NUNIT CPI HEADQ ;IS HEADQ LARGER THEN HSTDSK? JC UNDONE ;B IS UNIT, A IS HEAD SBI HEADQ ;DECREMENT BY THE NUMBER OF HEADS PER UNIT INR B ;INCREMENT THE UNIT UNDONE STA PHEAD ;REMAINDER IS THE PHYSICAL HEAD MOV A,B STA PUNIT ;UNIT IS THE QUOTIENT MOV A,H ;MSB OF TRACK STA PTRK ;STORE IT IN PHYSICAL UPPER TRACK MOV A,L ;LSB OF TRACK; STA PTRK+1 ;STORE IT IN PHYSICAL LOWER TRACK LDA HSTSEC OUT SCTAD STA PSECTOR RET ; PHYSICAL ADDRESS IS NOW SET ; ;WE WILL NOW CHECK TO SEE IF SELECT IS TRUE, AND IF THE TRACK ;, HEAD, AND UNIT ADDRESSES ARE THE SAME AS THE LAST TRANSFER, ;STORED IN OLDUNIT, OLDTRK, AND OLDHEAD. ; COMCON IN STATU ;GET THE STATUS RRC ;PLACE SELECTED BIT INTO CARRY JNC NEWADD ;IF NOT SELECT FORCE NEW ADDRESS ; TEST NEW VS OLD ADDRESS LXI H,OLDUNIT ;H,L POINT TO OLD ADDRESS LXI D,PUNIT ;D&E POINT TO NEW ADDRESS MVI B,4 ;NUMBER OF BYTES TO CHECK ADCMP LDAX D ;GET NEW ADDRESS BYTE CMP M ;COMPARE IT TO OLD JNZ NEWADD ;IF DIFERENT GO TO NEW ADDRESS DCR B INX H ;INCREMENT THE POINTER TO CURRENT ADDRESS INX D ;INCREMENT THE POINTER TO DESIRED ADDRESS JNZ ADCMP ;IF LOOP IS NOT DONE COMPARE ONE MORE ; RETURN WITHOUT ERROR, SAME ADDRESS XRA A ;CLEAR CARRY RET NEWADD: ; SET OLD TO PHYSICAL LXI D,OLDUNIT LXI H,PUNIT MVI B,4 ;COUNT UPDATE MOV A,M ;GET NEW STAX D ;UPDATE OLD INX D INX H DCR B JNZ UPDATE LDA PUNIT ;GET THE PHYSICAL UNIT RRC ;UNIT IS UPPER HALF OF BYTE RRC RRC RRC OUT BUSU ;PLACE IT ON THE BUS MVI A,10H ;SELECT COMMAND OUT CMND ;SELECT I IN STATU ;GET STATUS RRC ;PLACE SELECT IN CARRY CMC ;CARRY 1 IF NOT SELECTED MVI A,'G' ;SELECT ERROR JC ERREPORT ;PRINT IT LDA PHEAD ; IF CMD CPI 0 JZ HDJUST ;IS HEAD ZERO LEAVE ALLONE ADI 15 ;ADD 15 TO SET LOLUME TAG ENDIF HDJUST OUT BUSL ;SET IT ON THE BUS MVI A,40H ;SET HEAD COMMAND OUT CMND ;DO THE HEAD SELECT IN STATU ;GET THE STATUS ANI 20H ;TEST DISK FAULT BUT MVI A,'H' JNZ ERREPORT ;IF FAULT IS ONE, REPORT IT ; ; ; SEEK ROUTINE ; TRACK SUBSTITUTION INCLUDED ; SEEK: CALL GSEEK ;GO PERFORM THE SEEK RNC ;RETURN IF SEEK WAS GOOD(NO CARRY) ; IF HERE, FIRST SEEK ATTEMPT FAILED CALL RECAL ;RECAL DRIVE TO ATTEMMPT TO CLEAR ERROR CALL GSEEK ;GIVE IT ONE MORE TRY RNC ;IF NO ERROR IT RECOVERED ; IF HERE, HARD SEEK ERROR OCCURED MVI A,0FFH ;SET A TO ALL ONES STA OLDUNIT ;THIS WILL CAUSE A SELECT AND SEEK UPON ; NEXT ACCESS MVI A,'I' JMP ERREPORT ;REPORT THE SEEK ERROR GSEEK: ; COMPRIZE COMMPOSITE ADDRESS TO SEARCH TRACK TABLE FOR LDA PTRK MOV D,A LDA PTRK+1 MOV E,A IF MAPEN ;MAP THE TRACK IF MAP IS ENABLED LDA PHEAD ;GET THE HEAD NUMBER RLC RLC ;PLACE HEAD IN BITS 5-2 ANI 1CH ;STRIP ANY ENTRA JUNK ORA D ;OR IN MSB OF TRACK MOV D,A LDA PUNIT ;GET UNIT NUMBER RRC RRC RRC ;UNIT NOW IN 6-4 ANI 60H ORA D ;OR HEAD TO UNIT/TRACK MOV D,A ;D IS NOW HEAD,UNIT,TRACKMSB MVI C,0 ;SET B,C,TABLE ENTRY PIONTER, TO ZERO FINDT LXI H,SUBTBL ;H&L NOW POINT TO THE TABLE FINDN MOV A,M ;GET BYTE FORM THE TABLE, FIRST HALF ADI 80H ;ADD MSB TO SEE IF IT WAS ON JC SUBDONE ;IF CARRY THE SUBSTITUTION IS DONE MOV A,D ;LSB OF DESIRED CMP M ;IS IT THE SAME? INX H ;INCREMENT THE POINTER JNZ NOCMP ;JMP NO COMPARE IF DIFFERENT MOV A,E ;MSB OF DESIRED CMP M ;IS IT THE SAME JZ SUBT ;IF ZERO GO DO THE SUBSTITUTION NOCMP INX H ;INCREMENT THE POINTER INR C ;INCREMENT THE LOCATION IN THE TABLE MOV A,C ;GET TABLE POSITION CPI MAXMAP+1 ;CAUSE CARRY IF MAXMAP OR LESS CMC ;INVERT CARRY, MVI A,'M' ;M IS MAP OVERRUN ERROR CC ERREPORT ;PRINT M IF CARRY JMP FINDN ;GO TEST THE NEXT ENTRY SUBT: MVI B,0 ;B,C=THE TABLE ENTRY WHERE THE MATCH OCCURED LXI H,MAXTRK+1 ;THE BEGIN OF THE SUBSTITUTION TRACKS DAD B ;H&L NOW EQUAL THE NEW TRACK XCHG ;D&E NOW EQUAL THE NEW TRACK JMP FINDT ;GO SEE IF THE SPARE IS MAPPED ENDIF ; ;SUBSTITUTION IS DONE, DO THE SEEK TO THE TRACK IN D&E SUBDONE MOV A,E ;LSB OF TRACK OUT BUSL MOV A,D ;MSB OF TRACK ANI 3 ;STRIP ALL BUT TRACK OUT BUSU ;BUS NOW SET TO TRACK MVI A,20H ;SEEK COMMAND OUT CMND ;DO THE SEEK CALL WT ;WAIT FOR DONE MVI A,'J' JC ERREPORT ;PRINT J IF SEEK TIMEOUT RET ; WAIT FOR DONE, RETURN WITH CARRY OFF WHEN DONE, ; AND CARRY SET IF TIMEOUT. WT MVI H,0FFH ;H&L WILL BE DECREMENTED FOR A GROSS TIMEOUT WZ DCX H ;DECREMENT COUNT MOV A,H ;PLACE MSB OF COUNT INTO A ORA L ;OR IN LSB TO SEE IF ANY BIT IS NON-ZERO JZ TIMEOUT ;TIMEOUT IF HL ZERO BEFOR DONE IN STATU ;GET STATUS ANI 80H ;IS DONE ON? JZ WZ ;IF NOT DONE WAIT RET ;GOOD RETURN, CARRY OFF FROM THE ANI 80H TIMEOUT STC ;SET CARRY RET ;ERROR RETURN ; ; PANIC ROUTINE FOLLOWS ; DO FAULT RESET, RECALL, KILL OLDUNIT, CALL KCOMMON PANIC CALL RECAL ;RECAL UNIT MVI A,0FFH STA OLDUNIT ;KILL OLD UNIT TO FORCE A SEEK AND SELECT CALL KCOMMON RET RECAL XRA A ;MAKE A ZERO OUT BUSU ;ZERO UPPER BUS MVI A,50H ;FAULT CLEAR AND RECAL BITS OUT BUSL ;SET ONTO BUS MVI A,80H ;FAULT RECOVERY COMMAND OUT CMND ;START FAULT RECOVERY XRA A ;MAKE ANOTHER ZERO OUT CMND ;TURN OFF THE FAULT COMMAND CALL WT ;WAIT FOR DONE MVI A,'K' CC ERREPORT ;PRINT A K IF RECAL TIMEOUT RET ; ; HARD DISK ERROR PRINT ; ERREPORT: STA DIOST ;SET ERROR FLAG LXI H,ERRORMES CALL PRMSG LDA DIOST ;GET ERROR LETTER MOV C,A ;PLACE ASCII CHARACTER IN C CALL CONOUT ; PRINT THE ERROR LETTER CALL SPACE ;PRINT THE ADDRESS NX8 LXI H,CERRC MVI C,6 NX8N CALL X8 INX H DCR C JNZ NX8N STC RET X8 MOV A,M ANI 0F0H RRC RRC RRC RRC CALL HEXOUT MOV A,M ANI 0FH CALL HEXOUT CALL SPACE STC RET HEXOUT ORI 30H CPI 3AH JC GOODNUM ADI 7 GOODNUM PUSH H PUSH B MOV C,A CALL CONOUT POP B POP H RET SPACE MVI A,' ' JMP GOODNUM ; ERRORS INCLUDE; ; A WRITE TIMEOUT ERROR ; B WRITE FAULT ; C READ TIMEOUT ; D CHECKWORD ; E FORMAT ; F HARD READ ERROR ; G UNIT SELECT ERROR ; H HEAD SELECT ERROR ; I HARD SEEK ERROR ; J SEEK TIMEOUT ; K RECAL TIMEOUT ; L MAPPER ERROR ; M MAP OVERRUN PRMSG: MOV A,M ;PRINT MESSAGE AT H&L TO 0 ORA A RZ ; MORE TO PRINT PUSH H MOV C,A CALL CONOUT POP H INX H JMP PRMSG ERRORMES: DB 0DH,0AH DB 'HARD DISK ERROR ' DB 0 ; ; MAPPER ROUTINE ; GETS THE MAPS OFF EACH DISK AND MAKES A SYSTEM WIDE ; MAP OF ALL BAD TRACKS MAXMAP EQU 65 ;20 ENTRIES ALLOWED MAXUNIT EQU 1 ;NUMBER OF DISK UNITS IF MAPEN ;ASSEMBLE ONLY IF MAP IS ENABLED SMAPPER ; SET PHYSICAL ADDRESS TO FIRST XRA A ;MAKE A ZERO STA HSTTRK STA HSTTRK+1 STA HSTDSK LXI H,SUBTBL SHLD SUBPNT MVI A,HSTSPT-1 ;LAST SECTOR NUMBER STA HSTSEC ;SET IT FOR KCOMMON ; CLEAR THE MAP MVI A,0E5H MVI B,2*MAXMAP+1 CLRMAP MOV M,A INX H DCR B JNZ CLRMAP GETMAP ;SEE IF SURFACE IS PRESENT CALL HSTPHY LDA PUNIT RLC RLC RLC RLC OUT BUSU MVI A,10H ;SELECT UNIT COMMAND OUT CMND IN STATU ;CHECK UNIT STATUS ANI 1 JZ NEXTMAP ;IF NOT SELECTED GO TO NEXTMAP LDA PHEAD IF CMD CPI 0 JZ CARTH ;IF CARTRIDGE THE HEAD ADDRESS IS GOOD ADI 15 ;OTHERWISE SET VOLUMN BIT ENDIF CARTH OUT BUSL MVI A,40H OUT CMND ;SELECT HEAD IN STATU ANI 20H JNZ NEXTMAP CALL READINT ;READ WITHOUT DMA JC NEXTMAP RDMAPBUF: LHLD SUBPNT ;SET H<O MAP ADDRESS NBADTRK IN SCTBU ;GET FIRST BYTW CPI 0E5H ;IS IT THE END JZ NEXTMAP ;IF END DO THE NEXT SURFACE MOV B,A ;PUT BYTE IN B (TRACK MSB) LDA PUNIT ;GET THE UNIT NUMBER RRC ;POISITION UNIT BITS RRC RRC ANI 60H ;GET RID OF ANY OTHER JUNK ORA B MOV B,A ;PUT TRACK AND UNIT IN B LDA PHEAD ;GET HEAD RLC ;POISITION BITS RLC ANI 1CH ORA B ;OR WITH TRACK AND UNIT MOV M,A ;PLACE INTO TABLE INX H ;POINT TO NEXT BYTE IN TABLE IN SCTBU ;GET SECOND BYTE OF TABLE MOV M,A ;ENTRY IS COMPLETE INX H ;POINT TO NEXT MVI M,0E5H ;SET END OF TABLE ; TEST FOR FULL LXI D,SUBTBL+2*MAXMAP MOV A,H CMP D JNZ NBADTRK MOV A,L CMP E JNZ NBADTRK MVI A,'M' CALL ERREPORT JMP NBADTRK ;GO GET ADDRESS OF NEXT BAD TRACK NEXTMAP: SHLD SUBPNT LDA HSTDSK INR A INR A STA HSTDSK CPI 2*HEADQ ;ARE WE DONE ? RZ ;IF SO, RETURN JMP GETMAP ENDIF ; IF HERE WE ARE DONE! ; DO NOT CHANGE THE ORDER OF THE NEXT 9 BYTES CERRC DB 0 ;ERROR COUNTER PUNIT DS 1 ;DESIRED PHYSICAL UNIT PTRK DS 2 ;DESIRED REAL TRACK ADDRESS PHEAD DS 1 ;DESIRED HEAD PSECTOR DS 1 ;DESIRED SECTOR,512 BYTE OLDUNIT DB 0FFH ;LAST HEAD SELECTED, FF TO CAUSE INITIAL SEL. OLDTRK DW 0FFFFH ;LAST TRACK SEEKED OLDHEAD DB 0FFH ;LAST HEAD ACCESSED ; ; LASTLD: EQU BIOS+(7*128)-1 ;LAST RAM LOADED FROM DISK ; ; THE REMAINDER OF THE CBIOS IS RESERVED UNINITIALIZED ; DATA AREA, AND DOES NOT NEED TO BE A PART OF THE ; SYSTEM MEMORY IMAGE (THE SPACE MUST BE AVAILABLE, ; HOWEVER, BETWEEN "BEGDAT" AND "ENDDAT"). ; TRACK: DS 2 ;TWO BYTES FOR EXPANSION SECTOR: DS 2 ;TWO BYTES FOR EXPANSION DMAAD: DS 2 ;DIRECT MEMORY ADDRESS DISKNO: DS 1 ;DISK NUMBER 0-15 RORW: DS 1 ;READ OR WRITE SELECTED DIOST: DS 1 ;I/O RETURN STATUS 0 OK HDLD: DS 1 ;HEADLOAD FLAG BIT ; ; ; 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 ALL02: DS 114 ;ALLOCATION VECTOR 2 ALL04: DS 114 ;ALLOCATION VECTOR 4 ALL05: DS 114 ;ALLOCATION VECTOR 5 ALL03: DS 114 ;ALLOCATION VECTOR 3 ALL06 DS 114 ALL07 DS 114 ALL08 DS 114 ALL09 DS 114 ALL10 DS 114 ALL11 DS 114 ALL12 DS 114 ALL13 DS 114 CHK00: DS 16 ;CHECK VECTOR 0 CHK01: DS 16 ;CHECK VECTOR 1 CHK02: DS 128 ;CHECK VECTOR 2 CHK03: DS 128 ;CHECK VECTOR 3 CHK04 EQU $ ;NO STORAGE REQUIRED CHK05 EQU $ ;NO STORAGE REQUIRED CHK06 EQU $ CHK07 EQU $ CHK08 EQU $ CHK09 EQU $ CHK10 EQU $ CHK11 EQU $ CHK12 EQU $ CHK13 EQU $ 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 ; RSFLAG: DS 1 ;READ SECTOR FLAG READOP: DS 1 ;1 IF READ OPERATION WRTYPE: DS 1 ;WRITE OPERATION TYPE HSTBUF: DS HSTSIZ ;HOST BUFFER SUBTBL: DS 2*MAXMAP+1 SUBPNT DS 2 ; ENDDAT EQU $ ;END OF DATA AREA DATSIZ EQU $-BEGDAT;SIZE OF DATA AREA ; ; READ/WRITE STACK SAVE AREA ; OLDSP: DW 0 HLSAV: DW 0 DS 30 NSTACK: DS 2 ; ; THE ADDRESS OF NSTACK MUST FALL WITHIN ; THE AVAILABLE RAM STORAGE. END