; ; 17 JUL 80 ; ; MODIFIED FOR HEAD LOAD DELAY 16 DEC 80 ; MODIFIED FOR PROPER UNIT/STPRAT CORRELATION 9 DEC 80 ; MODIFIED FOR SEEK ERROR TRAPPING 10 DEC 80 ; MODIFIED FOR NOT READY TRAPPING 11 DEC 80 ; MODIFIED FOR MINI/MAXI CONDITIONALS 11 DEC 80 ; MODIFIED FOR UNALLOCATED WRITE CORRECTIONS 8 SEP 80 ; MODIFIED FOR AUTO-BOOT OPERATION 7 SEP 80 ; MODIFIED FOR COMPUTED SKEW FACTORS 7 SEP 80 ; MODIFIED FOR WARM BOOTS FROM MINIS 14 AUG 80 ; MODIFIED FOR PROPER DEFAULT DISK RESTORAL ON WARM BOOT 12 AUG 80 ; MODIFIED FOR 2 MHZ 8080 OPERATION 12 AUG 80 ; TITLE 'CCS 2422 DEBLOCKED BIOS WITH TUART FOR CP/M 2.2' PAGE 56 ; ; ; THIS BIOS IS SET UP FOR AUTO SELECT OF DISK CHAR ; ;"BIAS" IS ADDRESS OFFSET FROM 2C00H FOR MEMORY SYSTEMS ;THAN 20K (REFERRED TO AS "B" THROUGHOUT THE TEXT). ; VERS: EQU 22 ;CP/M VERSION NUMBER MSIZE: EQU 64 ;CP/M VERSION MEMORY SIZE IN KILOBYTES BIAS: EQU (MSIZE-20)*1024 CCP: EQU 2C00H+BIAS ;BASE OF CCP BDOS: EQU CCP+806H ;BASE OF BDOS BIOS: EQU CCP+1600H ;BASE OF BIOS WBOOTV: EQU 0 IOBYTE: EQU 3 ;INTEL IOBYTE LOCATION CDISK: EQU 4 BDOSV: EQU 5 ; TRUE: EQU 0FFFFH FALSE: EQU NOT TRUE ; MINI: EQU TRUE MAXI: EQU TRUE ;CONDITIONAL FLAG FOR 8" DRIVE SUPPORT BOTH: EQU MINI AND MAXI ; SDATA: EQU 21H ;SERIAL DATA PORT SINTEN: EQU SDATA+1 ;SERIAL INTERRUPT ENABLE PORT SIDENT: EQU SDATA+2 ;SERIAL INTERRUPT IDENTIFICATION PORT SLCTRL: EQU SDATA+3 ;SERIAL LINE CONTROL PORT SMDMCT: EQU SDATA+4 ;SERIAL MODEM CONTROL PORT SLSTAT: EQU SDATA-1 ;SERIAL LINE STATUS PORT SMDMST: EQU SDATA+6 ;SERIAL MODEM STATUS PORT LPOUT: EQU 51H ; LPSTS: EQU 50H ; ; BAUDB: EQU 088H ;TUART CHANNEL B 1200 1 STOP BIT BAUDA: EQU 0C0H ;TUART CHANNEL A 9600 1 STOP BIT MASKB: EQU 0H ;NO INT FROM PORT B MASKA: EQU 0H ;NO INT FROM PORT A RESET: EQU 09H ; BCMD: EQU LPSTS+2 ;TUART CHANNEL B CMD PORT ACMD: EQU SLSTAT+2 ;TUART CHANNEL A CMD PORT BMSK: EQU LPSTS+3 ;TUART CHANNEL B INT MASK AMSK: EQU SLSTAT+3 ;TUART CHANNEL A INT MASK ; RXRDY: EQU 01000000B ;RECEIVE DATA AVAILABLE BIT TXMTY: EQU 10000000B ;TRANSMIT BUFFER EMPTY BIT ; ; WHEN THE AUTO-BOOT JUMPER IS ENABLED, THE 2810 ; SERIAL PORT WILL BE INITIALIZED TO 9600 BAUD. ; TO SELECT A DIFFERENT BAUD RATE, CHANGE SBAUD ; TO ONE OF THE FOLLOWING VALUES: ; ; BAUD RATE SBAUD ; 50 2304 ; 75 1536 ; 110 1047 ; 134.5 857 ; 150 768 ; 300 384 ; 600 192 ; 1200 96 ; 1800 64 ; 2000 58 ; 2400 48 ; 3600 32 ; 4800 24 ; 7200 16 ; 9600 12 ; 19200 6 ; 38400 3 ; 56000 2 ; SBAUD: EQU 12 ;9600 BAUD DIVISOR FOR 2810 ; DSTAT EQU 30H ;DISK STATUS PORT DCMMD EQU DSTAT ;DISK COMMAND PORT DTRCK EQU DSTAT+1 ;DISK TRACK PORT DSCTR EQU DSTAT+2 ;DISK SECTOR PORT DDATA EQU DSTAT+3 ;DISK DATA PORT DFLAG EQU DSTAT+4 ;DISK FLAF PORT DCTRL EQU DSTAT+4 ;DISK CONTROL PORT BCTRL: EQU 4 ;DISK STATUS 2 PORT ; RSTR: EQU 8 ;BASIS OF RESTORE COMMAND SEEKV: EQU 1CH ;BASIS OF SEEK COMMAND STEPI: EQU 58H ;BASIS OF STEP IN COMMAND RDSEC: EQU 88H ;BASIS OF READ SECTOR COMMAND RDADD: EQU 0C4H ;READ ADDRESS COMMAND ; ; STEP RATES MAY BE TAILORED TO MEET INDIVIDUAL DRIVE REQUIREMENTS. ; TO DO SO, DETERMINE THE PROPER TRACK-TO-TRACK STEP RATES FROM ; YOUR DISK DRIVE'S TECHNICAL MANUAL, AND SET THE STEP5 (FOR MINI ; DRIVES) AND/OR STEP8 (FOR 8" DRIVES) TO THE VALUE SHOWN IN ; THE FOLLOWING TABLE: ; ; VALUE MINI DISKS 8" DISKS ; 0 6 MS 3 MS ; 1 12 MS 6 MS ; 2 20 MS 10 MS ; 3 30 MS 15 MS ; STEP5: EQU 0 ;MINI DISK STEP RATE STEP8: EQU 0 ;8" DISK STEP RATE ; IF MINI HLWAIT: EQU 3000H ;HEAD LOAD WAIT FOR MINI DRIVES ENDIF IF NOT MINI HLWAIT: EQU 1600H ;HEAD LOAD WAIT FOR 8" DRIVES ENDIF ; TRIES: EQU 10 ;NUMBER OF ATTEMPTS ; ;DEBLOCK PARAMETERS WRALL: EQU 0 WRDIR: EQU 1 WRUAL: EQU 2 ; ; CTRLC: EQU 3 ;ASCII ETX BELL: EQU 7 ;ASCII BELL CHARACTER CR: EQU 0DH ;ASCII CARRIAGE RETURN LF: EQU 0AH ;ASCII LINE FEED ; DISKNO: EQU 40H ;ACTIVE DISK NUMBER TRACK: EQU DISKNO+1 SECTOR: EQU TRACK+1 SIDE: EQU SECTOR+1 ;SIDE SELECT HOLD AREA SPT: EQU SIDE+1 ;SECTORS PER TRACK HOLD TWOSID: EQU SPT+1 ;SINGLE/DOUBLE SIDED SWITCH HOLD STPRAT: EQU 46H ;STEP RATE SAVE AREA STATUS: EQU 47H CMND: EQU STATUS+1 LUNIT: EQU 49H ;LAST USED DRIVE CUNIT: EQU LUNIT+1 ;CURRENT DRIVE RWFLG: EQU 4BH HSTBUF: EQU 4CH ;HOST BUFFER ADDRESS IDSV: EQU 4EH ;SECTOR ID SAVE AREA TBUF: EQU 80H TPA: EQU 100H ; ORG BIOS ;ORIGIN OF THIS PROGRAM ; ;JUMP VECTOR FOR INDIVIDUAL SUBROUTINES JMP BOOT ;COLD START WBOOTE: JMP WBOOT ;WARM START CSTAT: JMP CONST ;CONSOLE STATUS CONIN: JMP CONI ;CONSOLE CHARACTER IN CONO: 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 ; ;INDIVIDUAL SUBROUTINES TO PERFORM EACH FUNCTION ; ; RETRY: DCR C JNZ LOAD1 LXI H,BOTMSG CALL PRTRD CALL PRTWA WBOOT: LXI SP,TBUF MVI C,TRIES ;# OF RETRIES LOAD1: XRA A MOV H,A ;SET THE UNIT AND TRACK MOV L,A SHLD DISKNO LXI H,0D002H ;SET THE SIDE AND SECTOR SHLD SECTOR MVI B,12 ;ZERO OUT PRMTBL LXI H,PRMTBL LOAD1A: MOV M,A INX H DCR B JNZ LOAD1A PUSH B MOV C,A MOV E,A ;SET NEW UNIT INDICATOR CALL SELDSKA POP B LDA PRMTBL+1 STA CUNIT LXI H,CCP SHLD HSTBUF IF MAXI MVI B,26 ;HOLD THE SPT IN (B) ENDIF IF BOTH IN BCTRL ;SET # OF SECTORS FOR TRK00 ANI 2 ;ISOLATE MINI/MAXI BIT JZ LOAD2 ;JUMP IF 8" ENDIF IF MINI MVI B,18 ;SET MINI SPT ENDIF LOAD2: PUSH B CALL DREAD POP B ORA A JNZ RETRY SHLD HSTBUF MOV D,H ;SAVE THE PAGE ADDRESS LXI H,SECTOR ;POINT TO THE SECTOR HOLD MOV A,M ;SEE IF READY FOR NEXT TRACK SUB B JC LOAD3 MOV M,A ;RESET THE SECTOR COUNT DCX H ;POINT TO TRACK INR M ;ADVANCE IT INX H ;POINT BACK TO SECTOR IF BOTH IN BCTRL ;SET THE NEW SPT VALUE ANI 2 ;SEE IF MINI OR MAXI JZ LOAD3 ;CURRENT VALUE GOOD FOR MAXI, JUMP ENDIF IF MINI LDA CUNIT ;SEE IF DOUBLE DENSITY ANI 40H JNZ LOAD3 ;CURRENT VALUE OK IF DDEN SET LDA IDSV+3 ;GET SECTOR SIZE INDICATOR DCR A ;SEE WHICH SIZE JM LOAD3 ;JUMP IF 128 BYTE SECTORS MVI B,10 ;SPT FOR 256 BYTE SECTORS JZ LOAD3 MVI B,5 ;SPT FOR 512 BYTE SECTORS ENDIF LOAD3: INR M LDA IDSV+3 ;SEE IF ENOUGH LOADED IN ADD D SUI BIOS/256 JC LOAD2 ;JUMP IF MORE NEEDED ; ;END OF LOAD OPERATION, SET PARAMETERS AND GO TO CP/M BOOT0: MVI A,JMP ;GET A JUMP OP CODE STA WBOOTV ;RESET THE JUMP VECTORS STA BDOSV LXI H,WBOOTE SHLD WBOOTV+1 LXI H,BDOS SHLD BDOSV+1 LXI H,DBUF ;SET UP BUFFER ADDRESS SHLD HSTBUF LXI H,TBUF ;DEFAULT DMA ADDRESS IS 80H SHLD DMAAD SHLD HSTACT ;HOST NOT ACTIVE MVI A,RESET OUT BCMD MVI A,MASKB OUT BMSK MVI A,BAUDB OUT LPSTS MVI A,1BH OUT LPOUT MVI A,0DH OUT LPOUT MVI A,50H OUT LPOUT LDA CDISK MOV C,A JMP CCP ;GO TO CPM ; ; ;SELECT DISK GIVEN BY REGISTER C SELDSK: MOV A,C STA SEKDSK SELDSKA: LXI H,0 ;ERROR RETURN CODE CPI 4 ;MUST BE BETWEEN 0 AND 3 RNC ;NO CARRY IF 4,5,... ;DISK NUMBER IS IN THE PROPER RANGE ;COMPUTE PROPER DISK PARAMETER HEADER ADDRESS SELDSK1: MOV L,A ;L=DISK NUMBER 0,1,2,3 DAD H ;*2 DAD H ;*4 DAD H ;*8 DAD H ;*16 (SIZE OF EACH HEADER) MOV A,E ;GET THE NEW UNIT INDICATOR BIT LXI D,DPBASE DAD D ;HL=.DPBASE(DISKNO*16) RAR ;TEST THE NEW UNIT BIT PUSH PSW PUSH H MOV A,C CALL FDSB0 STA SEKSEL POP H POP PSW MOV A,C ;RETURN THE DISKNO RC ;RETURN IF NOT NEW UNIT ; CKSET: PUSH H ;SAVE (H,L) CKSET0: LHLD LUNIT ;FIRST, SAVE CURRENT DISK ASSIGNMENTS PUSH H STA CUNIT ;FORCE THE READ ADDRESS LHLD DISKNO LDA SIDE MOV H,A PUSH H MOV A,C ;REGET DESIRED UNIT STA DISKNO ;SET NEW DISK NUMBER MVI A,0D0H ;SELECT SIDE 0 OF NEW DISK STA SIDE PUSH B CALL IDRD1 ;FIND OUT WHAT IS OUT THERE JNZ SELERR MOV C,A ;GET THE SECTOR SIZE DCX H ;POINT TO THE SELBITS MOV B,M ;GET THEM LXI D,4 ;ADDRESS TABLE ENTRY OFFSET IF MINI LXI H,MSELTBL-4 ;MINI TABLE ADDRESS ENDIF IF BOTH MOV A,B ;REGET THE SELBITS ANI 10H ;ISOLATE THE MINI DRIVE BIT JZ SETUP1 ;JUMP IF MINI ENDIF IF MAXI LXI H,SELTBL-4 ; ELSE, SET THE 8" TABLE ADDRESS IN BCTRL ;CHECK FOR DOUBLE SIDED DISK ANI 40H ;ISOLATE TWO-SIDED BIT JNZ SETUP1 ;JUMP IF SINGLE-SIDED LXI H,SELTBLA-4 ENDIF SETUP1: MOV A,B ;CHECK FOR DOUBLE DENSITY STA SEKSEL ANI 40H ;ISOLATE THE BIT JZ SETUP3 ;JUMP IF SINGLE-DENSITY DAD D ;OFFSET TO DOUBLE DENSITY ENTRIES DAD D DAD D DAD D SETUP3: DAD D ;OFFSET TABLE ADDRESS DCR C JP SETUP3 SET3: XCHG ;SAVE THE POINTER CMP A ;ZERO OUT FLAGS SELERR: POP B ;RESTORE REGISTERS POP H ;RESTORE THE CURRENT DRIVE MOV A,H ;RESTORE THE SIDE STA SIDE MOV A,L ; AND THE DISKNO STA DISKNO POP H SHLD LUNIT POP H JNZ SELERRA ;JUMP IF A SELECT ERROR PUSH H ;GET, RESAVE DP BLOCK POINTER LDAX D ;MOVE THE TABLE ENTRIES MOV M,A INX D INX H LDAX D MOV M,A INX D PUSH D ;SAVE IT FOR A MOMENT LXI D,9 DAD D ;OFFSET THE POINTER POP D ;REGET TABLE ADDRESS LDAX D ;MOVE THE TABLE ENTRIES MOV M,A INX D INX H LDAX D MOV M,A SET4: POP H MOV A,C RET SELERRA: LXI H,0 MOV A,C RET ; ;SET TRACK GIVEN BY REGISTER C SETTRK: MOV A,C STA SEKTRK RET ; ;SET SECTOR GIVEN BY REGISTER C SETSEC: MOV A,C ANI 7FH ;STRIP OFF SIDE INDICATOR DCR A STA SEKSEC MOV A,C ;REGET SECTOR NUMBER RAL ;ISOLATE SIDE BIT MVI A,0D0H ;SET UP SIDE SELECT BITS JNC SETSEC1 MVI A,90H ;SELECT SIDE 1 SETSEC1: STA SEKSID ;SET THE SIDE SELECT BITS RET ; ;TRANSLATE THE SECTOR GIVEN BY BC USING THE ;TRANSLATE TABLE GIVEN BY DE SECTRAN: PUSH D ;SAVE THE TABLE ADDRESS LDA SEKDSK CALL FDSB0 ;GET THE PARAMETER TABLE ADDRESS INX H ;POINT TO THE SECTOR SIZE ENTRY MOV D,M ;SECTOR SIZE NOW IN (D) PUSH D ;SAVE FOR LATER USE MOV A,C ;GET THE DESIRED SECTOR STA CPMSEC RAL SECT0: ORA A ;CONVERT TO PHYSICAL SECTOR NUMBER RAR DCR D JP SECT0 POP D POP H ;REGET TABLE ADDRESS CMP M ;SEE IF SIDE 1 MVI B,0 ;SET FOR SIDE 0 JC SECT1 ;JUMP IF SIDE 0 MVI B,80H ;FLAG BIT FOR SIDE 1 SUB M SECT1: PUSH B MOV B,D ;SAVE SECTOR SIZE IN (B) MOV E,A ;SET UP TO BUILD SKEW MOV D,M ;GET THE SKEW FACTOR INX H MVI C,0FFH ;GET A -1 SECT2: INR C ;BUILD SECTOR OFFSET IN (C) SUB M JNC SECT2 ;LOOP TIL OFFSET IS BUILT INX H ;POINT TO SKEW FACTOR XRA A ; AND GET A ZERO SECT3: ADD M ;BUILD THE SKEWED SECTOR NUMBER DCR E JP SECT3 SUB M ADD C ;ADD ON THE OFFSET SECT4: SUB D ;INSURE NUMBER IS IN RANGE JNC SECT4 ADD D SECT5: MOV L,A ;MOVE SKEWED NUMBER OVER TO (L) INR A ;SET PYHS SECTOR FOR ANTIC. LOGIC STA NXTSCT XRA A ;CONVERT PHYSICAL TO LOGICAL SECTOR MOV H,A SECT6: DCR B JM SECT7 ;JUMP IF DONE STC ADC A ;BUILD THE MASK DAD H ;OFFSET THE SECTOR NUMBER JMP SECT6 SECT7: POP B ANA C ;STRIP OUT THE SUB-SECTOR ORA L ;ADD IT TO THE SKEWED SECTOR INR A ORA B ;ADD ON THE SIDE SELECT BIT MOV L,A RET ; ; ;SET DMA ADDRESS GIVEN BY REGISTERS B AND C SETDMA: MOV L,C ;LOW ORDER ADDRESS MOV H,B ;HIGH ORDER ADDRESS SHLD DMAAD ;SAVE THE ADDRESS RET ; ;MOVE TO THE TRACK 00 POSITION OF CURRENT DRIVE HOME: SUB A STA SEKTRK RET ; ;DEBLOCK ROUTINES ; READ: MVI A,WRUAL ;TREAT READ AS UNALLOCATED STA WRTYPE STA READOP ;SET A READ OPERATION JMP ALLOC ;GO DO THE READ ; WRITE: XRA A ;FLAG AS A WRITE OPERATION STA READOP MOV A,C ;WRITE TYPE FROM CP/M STA WRTYPE CPI WRUAL ;SEE IF UNALLOCATED JNZ CHKUNA ;JUMP IF NOT ; ; UNALLOCATED WRITE, SET PARAMETERS CALL PHYSEC ;CONVERT TO PHYSICAL SECTOR LHLD SEKHST ;SET PHYSICAL SECTOR AND SIDE SHLD UNASEC LHLD SEKDSK ;GET THE DISK NUMBER SHLD UNADSK ;SAVE IT FOR UNALLOCATED WRITE MOV A,L CALL DPFND ;GET DP TABLE ADDRESS INX D ;OFFSET TO THE BLOCK MASK INX D INX D LDAX D ;GET THE BLOCK MASK INR A ;(A) = LOGICAL SECTORS PER BLOCK STA UNACNT ;SAVE THE SECTOR COUNT ; CHKUNA: LXI H,UNACNT ;SEE IF ANY UNALLOCATED SPACE AVAILABLE XRA A CMP M JZ ALLOC1 ;JUMP IF NOT DCR M ;ELSE, USE SOME OF IT CALL PHYSEC ;SET THE PHYSICAL SECTOR NUMBER LXI D,UNADSK CALL COMP ;COMPARE THE UNITS JZ NXTSEC ;GO DO THE WRITE ; ALLOC: XRA A ;ALLOCATED WRITE REQUIRES PREREAD STA UNACNT ALLOC1: INR A ALLOC2: STA RSFLAG ; RWOPER: XRA A ;GET A ZERO STA ERFLAG ;RESET THE ERROR FLAG ; LXI H,HSTACT ;SEE IF HOST ACTIVE ORA M MVI M,1 ;MARK IT ACTIVE FOR NEXT TIME JZ FILHST ;FILL THE HOST BUFFER IF EMPTY ; CALL PHYSEC ;SET THE PHYSICAL SECTOR NUMBER LXI D,DISKNO CALL COMP ;COMPARE THE UNITS JZ MATCH ; NOMATCH: LDA HSTWRT ;SEE IF HOST WRITTEN ORA A CNZ DWRITA ;PURGE THE BUFFER IF NEED BE FILHST: CALL PHYSEC MOV A,D STA IDSV+3 LHLD SEKDSK ;SET UP TO FILL THE BUFFER SHLD DISKNO LHLD SEKHST ;GET THE SECTOR, SIDE SELECT SHLD SECTOR ;SET THEM LDA SEKSEL STA CUNIT LDA RSFLAG ORA A CNZ DREAD ;FILL IT IF NEED BE LXI H,ERFLAG ORA M MOV M,A XRA A ;RESET PENDING WRITE FLAG STA HSTWRT ; MATCH: LHLD IDSV+2 ;GET SECTOR SIZE XRA A ;GET A ZERO MATCH1: ADC A ;BUILD SECTOR MASK DCR H STC JP MATCH1 ;LOOP TIL MASK IS BUILT LHLD SEKSEC ANA L ;FIND THE RELATIVE SECTOR LXI H,DBUF-80H ;BUILD ADDRESS FOR CPM SECTOR LXI B,80H ;# BYTES IN LOGICAL SECTOR MATCH2: DAD B DCR A JP MATCH2 XCHG ;BUFFER ADDRESS TO (D,E) LHLD DMAAD ;GET DMA ADDRESS LDA READOP ;SEE IF READ OR WRITE ORA A JNZ RWMOVE ;POINTERS OK IF READ ; XCHG ;ELSE, SWAP THEM INR A ; AND MARK WRITE OPERATION STA HSTWRT ; RWMOVE: LDAX D ;GET A BYTE MOV M,A ;PUT IT INX D INX H DCR C ;LOOP CONTROL JNZ RWMOVE ; LDA WRTYPE ;GET WRITE TYPE DCR A ;SEE IF DIRECTORY ENTRY LDA ERFLAG ;GET THE ERROR FLAG RNZ ;DONE IF NOT DIRECTORY ENTRY ; ORA A ;SEE IF ANY ERRORS RNZ ;RETURN IF SO STA HSTWRT ;RESET HOST WRITTEN DWRITA: CALL DWRITE ;UPDATE THE DIRECTORY LXI H,ERFLAG ORA M ;GET THE ERROR INDICATIONS MOV M,A ;STORE THE ERROR FLAGS RET ; ; UNALLOCATED WRITE NEXT SECTOR ANTICIPATION LOGIC ; NXTSEC: LDA SEKDSK ;FIND ADDRESS OF DP TABLE CALL DPFND LDA CPMSEC ;GET LAST LOGICAL SECTOR NUMBER INR A XCHG ;DP TABLE ADDRESS TO (H,L) CMP M ;SEE IF OVERFLOW JNC NXTSC2 ;JUMP IF SO LXI H,-11 ;SAME TRACK, NOW SEE WHICH SIDE/SECTOR DAD D MOV E,M ;GET ADDRESS OF SKEW TABLE INX H MOV D,M MOV C,A ;SET UP TO CALL SECTRAN MVI B,0 CALL SECTRAN ;TRANSLATE THE SECTOR MVI H,0D0H ;SIDE 0 SELECT JP NXTSC1 ;JUMP IF SIDE 0 MVI H,090H ;ELSE, SET SIDE 1 NXTSC1: LDA NXTSCT ;GET THE NEXT PHYSICAL SECTOR MOV L,A ;SET THE SECTOR JMP NXTSC3 ; NXTSC2: LXI H,UNATRK ;SET FOR NEXT TRACK INR M LXI H,0D001H ;SIDE 0 SECTOR 1 NXTSC3: SHLD UNASEC ;SET THE NEXT SIDE, SECTOR XRA A ;GET A ZERO JMP ALLOC2 ;GO BACK TO MAINSTREAM ; ; FIND ADDRESS OF DISK PARAMETER TABLE ; DPFND: LXI H,DPBASE-6 ;DEVELOP ADDRESS OF DPTABLE LXI D,16 DPFND1: DAD D DCR A JP DPFND1 MOV E,M ;PULL UP THE ADDRESS INX H MOV D,M RET ; ; LOGICAL TO PHYSICAL SECTOR TRANSLATION ROUTINE PHYSEC: LDA SEKDSK ;GET THE DESIRED UNIT NUMBER CALL FDSB0 ;GET PRMTBL POINTER INX H ;POINT TO SECTOR SIZE MOV D,M ;GET THE SECTOR SIZE PUSH D LDA SEKSEC ;GET THE LOGICAL SECTOR NUMBER RAL PHYSC1: ORA A ;RESET THE CARRY BIT RAR ;CONVERT TO PHYSICAL SECTOR DCR D JP PHYSC1 INR A ;(A) NOW HAS PHYSICAL SECTOR # STA SEKHST ;SET IT POP D RET ; ;COMPARE THE UNITS COMP: LXI H,SEKDSK MVI B,4 COMP1: LDAX D SUB M RNZ ;DONE IF NO COMPARE INX H ;POINT TO NEXT ENTRY INX D DCR B JNZ COMP1 RET ; ; ; THE FOLLOWING ROUTINES DO THE PRIMITIVE DISK ACCESSES. ; IN ALL CASES, ONE SECTOR OF DATA IS TRANSFERRED. ; IF THE DISK HAS NOT BEEN PREVIOUSLY ACCESSED, ; THESE ROUTINES WILL AUTOMATICALLY DETERMINE THE ; DISK TYPE (8" OR 5"), SINGLE OR DOUBLE DENSITY, ; AND SECTOR SIZE. ; ; BEFORE THE DESIRED DATA IS TRANSFERRED, THE DESIRED ; TRACK IS SEEKED OUT, THE DESIRED SECTOR AND SIDE IS ; SET, THEN THE ACTUAL DATA TRANSFER. ; ; UP TO TEN TRIES WILL BE ATTEMPTED BEFORE THE DATA ; TRANSFER IS ABORTED. ON RETURN TO THE CALLING ; ROUTINE, THE A REGISTER WILL CONTAIN A ZERO IF THE ; OPERATION WAS SUCCESSFUL, OR NON-ZERO IF NOT ; SUCCESSFUL. THE FLAG REGISTER WILL NOT NECESSARILY ; CORRESPOND WITH THE A REGISTER CONTENT. ; ; DREAD: DB 3EH ;SIM. MVI A INSTR DWRITE: XRA A ;SET WRITE FLAG STA RWFLG ;SAVE IT FOR LATER USE MVI C,TRIES ;NUMBER OF RETRIES AGN: PUSH B CALL SEEK CZ RDWR READ3: POP B RZ DCR C ;SEE IF ALL TRIES DONE RZ ;YES, ERROR RETURN ANI 10H ;SEE IF RNF OR SEEK ERROR CNZ EOJB ;RESTORE DRIVE IF SO JMP AGN ; RDWR: MOV E,A ;SAVE COMMAND LDA RWFLG ORA A MOV A,E ;REGET THE COMMAND DI JZ WRDAT ;WRITE IF ZERO RDAT: STA CMND OUT DCMMD ;DISK COMMAND PORT READ1: IN DDATA ;READ THE DATA MOV M,A ;PUT INTO BUFFER INX H ;INCREMENT MEMORY POINTER IN DDATA ;READ THE DATA MOV M,A ;PUT INTO BUFFER INX H ;INCREMENT MEMORY POINTER IN DDATA ;READ THE DATA MOV M,A ;PUT INTO BUFFER INX H ;INCREMENT MEMORY POINTER IN DDATA ;READ THE DATA MOV M,A ;PUT INTO BUFFER INX H ;INCREMENT MEMORY POINTER DCR B JNZ READ1 CALL EOJ ANI 9CH ;ISOLATE READ ERROR BITS RET ; WRDAT: ORI 20H ;MAKE INTO WRITE COMMAND STA CMND OUT DCMMD ;DISK COMMAND PORT WRT1: MOV A,M ;GET DATA FROM BUFFER OUT DDATA ;OUTPUT IT INX H ;ADVANCE MEMORY POINTER MOV A,M ;GET DATA FROM BUFFER OUT DDATA ;OUTPUT IT INX H ;ADVANCE MEMORY POINTER MOV A,M ;GET DATA FROM BUFFER OUT DDATA ;OUTPUT IT INX H ;ADVANCE MEMORY POINTER MOV A,M ;GET DATA FROM BUFFER OUT DDATA ;OUTPUT IT INX H ;ADVANCE MEMORY POINTER DCR B JNZ WRT1 JMP EOJ ; EOJB: MVI B,RSTR ;BASIS OF RESTORE COMMAND EOJA: PUSH H ;SAVE (H,L) PUSH B CALL FDSB ;GET THE PRMTBL POINTER POP B DCX H ;POINT TO THE STEP RATE ENTRY MOV A,M ;GET THE STEP RATE POP H ;RESTORE (H,L) ORA B ;ADD ON THE COMMAND EOJC: STA CMND OUT DCMMD ;DO THE COMMAND EOJ: NOP IN DFLAG ;DISK FLAG PORT RAR JNC EOJ EOJ1: IN DSTAT ;GET THE DISK STATUS STA STATUS ANI 0FCH IF MAXI RP ;DONE IF DRIVE IS READY LDA DISKNO ;GET DRIVE NUMBER ADI 'A' ;CONVERT TO ASCII STA DNRMSGA ;PUT IT INTO MESSAGE PUSH H ;SAVE (H,L) LXI H,DNRMSG CALL PRTRD ;PRINT THE MESSAGE POP H ;RESTORE (H,L) JMP EOJ1 ; AND TRY AGAIN ENDIF IF NOT MAXI RET ENDIF ; SEEK: CALL IDRD ;INSURE HEADER HAS BEEN READ RNZ ;ERROR RETURN SEEK1: LDA SECTOR ;SET THE SECTOR OUT DSCTR ;DISK SECTOR PORT IN DTRCK ;READ THE CURRENT TRACK SETTING MOV C,A ;SAVE FOR A MOMENT LDA TRACK ;GET DESIRED TRACK CMP C ;SEE IF SEEK NEEDED JZ RDWRT ;NO, PRESS ON OUT DDATA ;SET THE SEEK TRACK ORA A ;SEE IF TRACK 0 DESIRED MVI C,0 ;NO AUTOWAIT WANTED LDA CUNIT CALL SU2 ;RESET THE DENSITY BIT IF SO MVI B,SEEKV ;BUILD THE SEEK COMMAND CALL EOJA ;DO THE SEEK ANI 98H ;SEEK ERROR MASK RNZ ;DONE IF SEEK ERROR RDWRT: MVI C,80H ;AUTO-WAIT BIT CALL SETUP IN DFLAG ;DISK FLAG PORT ANI 20H ;SEE IF HEAD IS LOADED MVI A,4 JZ RDWRT1 ;JUMP IF NOT XRA A ;ELSE, RESET THE HEAD LOAD FLAG RDWRT1: ADI RDSEC ;BUILD A READ SECTOR COMMAND MOV C,A ;SAVE THE COMMAND IN C IN DTRCK ;SEE IF ON TRACK 0 ORA A JZ RDWRT3 ;SET SECTOR SIZE = 0 INX H ;GET THE SECTOR SIZE MOV A,M RDWRT3: MOV B,A ;PUT IN B FOR LOOP CONTROL MVI A,10H ;SECTOR BASE LENGTH RDWRT0: ADD A DCR B JP RDWRT0 MOV B,A MOV A,C LHLD HSTBUF ;GET THE DMA ADDRESS RDWRT2: CMP A ;CLEAR THE FLAGS RET ; IDRD5: MVI B,STEPI ;BUILD A STEP-IN COMMAND CALL EOJA IDRD: LHLD LUNIT MOV A,H ;GET THE CUNIT VALUE CMP L ;SEE IF SAME AS LUNIT RZ ;RETURN IF SO IDRD1: MVI C,80H ;SET THE AUTO-WAIT BIT CALL SETUP PUSH H ;SAVE POINTER LXI H,HLWAIT ;WAIT FOR HEADS TO SETTLE IDRD3: DCX H MOV A,H ORA A JNZ IDRD3 LXI H,IDSV ;SET UP TO READ ADDRESS MVI B,2 ;SET UP TO READ 6(8) BYTES OF DATA MVI A,RDADD ;READ ADDRESS COMMAND DI CALL RDAT POP H ;RESTORE POINTER JZ IDRD2 ;JUMP IF GOOD READ MVI A,40H ;SEE IF DDEN IS SET CMP M RC ;TAKE THE ERROR IF SO ORA M ;ELSE, TRY DDEN MOV M,A JMP IDRD ; IDRD2: IN DSCTR ;GET THE TRACK NUMBER OUT DTRCK ;SET THE TRACK REGISTER CPI 2 ;INSURE NOT ON TRACK 0 OR 1 JC IDRD5 ;JUMP IF SO MOV A,M ;REGET SELBITS STA LUNIT ;UPDATE LAST USED UNIT STA CUNIT INX H ;SET THE SECTOR SIZE LDA IDSV+3 MOV M,A CMP A ;RESET ERROR FLAGS RET ; ;SET UP DRIVE NUMBER SETUP: CALL FDSB ;GET THE DISK SELECT BITS JNZ SU0 ;YES, SKIP INIT CODE ; SETIT: STC ;DRIVE SELECT BIT SET1: RAL ;SHIFT BIT INTO POSITION DCR B JNZ SET1 ;LOOP TIL BIT IS IN POSITION IF MINI ORI 20H ;ADD ON MOTOR ON BIT MOV M,A ;SAVE IT OUT DCTRL ;SELECT THE DRIVE ENDIF IF BOTH MVI A,RSTR OR 3 ;GET WORST CASE RESTORE COMMAND CALL EOJC ;RESTORE THE DRIVE IN BCTRL ;READ THE MINI TRK00 BIT RAR ;ISOLATE IT ENDIF IF MINI MVI A,STEP5 ;MINI STEP RATE BITS ENDIF IF BOTH JNC SET2 ;JUMP IF MINI DRIVE MOV A,M ;REGET THE SELBITS ENDIF IF MAXI ORI 30H ;ADD ON THE 8", MOTOR ON BITS OUT DCTRL MOV M,A IN BCTRL ;SEE IF DOUBLE-SIDED DRIVE ANI 40H ;ISOLATE THE BIT JZ SET2 ;SET 3 MS STEP RATE FOR DOUBLE-SIDED DRIVES MVI A,STEP8 ;SET MAXI STEP RATE ENDIF SET2: DCX H ;POINT TO STEP RATE HOLD MOV M,A ;SET THE STEP RATE INX H ;RESET POINTER SU0: IN DTRCK ;ELSE, SEE IF TRACK ZERO ORA A IN DDATA ;CLEAR OUT ANY JUNK MOV A,M ;REGET THE SELBITS SU2: JNZ SU1 ANI 0BFH ;INSURE DDEN IS RESET SU1: ORA C ;ADD ON AUTOWAIT BIT OUT DCTRL ;OUTPUT THE SELBITS LDA SIDE ;SET THE SIDE SELECT OUT BCTRL JMP EOJ1 ;GO INSURE A UNIT IS THERE ; FDSB: LDA DISKNO ;GET THE SELECT UNIT FDSB0: LXI H,PRMTBL-2 ;SEE IF DRIVE HAS BEEN ACTIVE INR A ;OFFSET FOR LOOP CONTROL MOV B,A ;SAVE FOR LATER USE FDSB1: INX H ;OFFSET TABLE POINTER INX H INX H DCR A JNZ FDSB1 ;LOOP CONTROL MOV A,M ;READ THE SELECT BITS ORA A RET ; ; ; ;FIXED DATA TABLES FOR FOUR-DRIVE STANDARD ;IBM-COMPATIBLE 8" DISKS ;DISK PARAMETER HEADER FOR DISK 00 DPBASE: DW 0,0 DW 0,0 DW DIRBF,0 DW CHK00,ALL00 ;DISK PARAMETER HEADER FOR DISK 01 DW 0,0 DW 0,0 DW DIRBF,0 DW CHK01,ALL01 ;DISK PARAMETER HEADER FOR DISK 02 DW 0,0 DW 0,0 DW DIRBF,0 DW CHK02,ALL02 ;DISK PARAMETER HEADER FOR DISK 03 DW 0,0 DW 0,0 DW DIRBF,0 DW CHK03,ALL03 ; ;PARAMETER TABLE FOR DRIVE-UNIQUE CONSTANTS PRMTBL: DB 0,0,0 ;DRIV 0 STP RAT, SLCT BYTS, SCTR SZ DB 0,0,0 ; 1 DB 0,0,0 ; 2 DB 0,0,0 ; 3 ; ;SECTOR TRANSLATE VECTOR ; IF MAXI SELTBL: DW T826,DP8S0 DW T815,DP8S1 DW T88,DP8S2 DW T84,DP8S2 DW T848,DP8D0 DW T826,DP8D1 DW T815,DP8D2 DW T88,DP8D3 ; DP8S0: DW 26 ;SECTORS PER TRACK DB 3 ;BLOCK SHIFT FACTOR DB 7 ;BLOCK MASK DB 0 ;EXTENT MASK DW 242 ;BLOCKS PER DISKETTE DW 63 ;# DIRCTORY ENTRIES DB 192 ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;DIR CHECK VECTOR SIZE DW 2 ;SYSTEM TRACK OFFSET DP8S1: DW 30 ;SECTORS PER TRACK DB 4 ;BLOCK SHIFT FACTOR DB 15 ;BLOCK MASK DB 1 ;EXTENT MASK DW 139 ;BLOCKS PER DISKETTE DW 63 ;# DIRCTORY ENTRIES DB 128 ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;DIR CHECK VECTOR SIZE DW 2 ;SYSTEM TRACK OFFSET DP8S2: DW 32 ;SECTORS PER TRACK DB 4 ;BLOCK SHIFT FACTOR DB 15 ;BLOCK MASK DB 1 ;EXTENT MASK DW 149 ;BLOCKS PER DISKETTE DW 63 ;# DIRCTORY ENTRIES DB 128 ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;DIR CHECK VECTOR SIZE DW 2 ;SYSTEM TRACK OFFSET DP8D0: DW 48 ;SECTORS PER TRACK DB 4 ;BLOCK SHIFT FACTOR DB 15 ;BLOCK MASK DB 1 ;EXTENT MASK DW 195 ;BLOCKS PER DISKETTE DW 63 ;# DIRECTORY ENTRIES DB 128 ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;DIR CHECK VECTOR SIZE DW 2 ;SYSTEM TRACK OFFSET DP8D1: DW 52 ;SECTORS PER TRACK DB 4 ;BLOCK SHIFT FACTOR DB 15 ;BLOCK MASK DB 1 ;EXTENT MASK DW 242 ;BLOCKS PER DISKETTE DW 63 ;# DIRECTORY ENTRIES DB 128 ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;DIR CHECK VECTOR SIZE DW 2 ;SYSTEM TRACK OFFSET DP8D2: DW 60 ;SECTORS PER TRACK DB 5 ;BLOCK SHIFT FACTOR DB 31 ;BLOCK MASK DB 3 ;EXTENT MASK DW 139 ;BLOCKS PER DISKETTE DW 127 ;# DIRECTORY ENTRIES DB 128 ;ALLOC 0 DB 0 ;ALLOC 1 DW 32 ;DIR CHECK VECTOR SIZE DW 2 ;SYSTEM TRACK OFFSET DP8D3: DW 64 ;SECTORS PER TRACK DB 4 ;BLOCK SHIFT FACTOR DB 15 ;BLOCK MASK DB 0 ;EXTENT MASK DW 299 ;BLOCKS PER DISKETTE DW 127 ;# DIRECTORY ENTRIES DB 192 ;ALLOC 0 DB 0 ;ALLOC 1 DW 32 ;DIR CHECK VECTOR SIZE DW 2 ;SYSTEM TRACK OFFSET ; SELTBLA: DW T826,DP8D1 DW T815,DP8D2 DW T88,DP8D3 DW T84,DP8D3 DW T848,DP8D0A DW T826,DP8D1A DW T815,DP8D2A DW T88,DP8D3A ; DP8D0A: DW 96 ;SECTORS PER TRACK DB 5 ;BLOCK SHIFT FACTOR DB 31 ;BLOCK MASK DB 3 ;EXTENT MASK DW 225 ;BLOCKS PER DISKETTE DW 127 ;# DIRECTORY ENTRIES DB 128 ;ALLOC 0 DB 0 ;ALLOC 1 DW 32 ;DIR CHECK VECTOR SIZE DW 2 ;SYSTEM TRACK OFFSET DP8D1A: DW 104 ;SECTORS PER TRACK DB 5 ;BLOCK SHIFT FACTOR DB 31 ;BLOCK MASK DB 3 ;EXTENT MASK DW 242 ;BLOCKS PER DISKETTE DW 127 ;# DIRECTORY ENTRIES DB 128 ;ALLOC 0 DB 0 ;ALLOC 1 DW 32 ;DIR CHECK VECTOR SIZE DW 2 ;SYSTEM TRACK OFFSET DP8D2A: DW 120 ;SECTORS PER TRACK DB 6 ;BLOCK SHIFT FACTOR DB 63 ;BLOCK MASK DB 7 ;EXTENT MASK DW 139 ;BLOCKS PER DISKETTE DW 127 ;# DIRECTORY ENTRIES DB 128 ;ALLOC 0 DB 0 ;ALLOC 1 DW 32 ;DIR CHECK VECTOR SIZE DW 2 ;SYSTEM TRACK OFFSET DP8D3A: DW 128 ;SECTORS PER TRACK DB 6 ;BLOCK SHIFT FACTOR DB 63 ;BLOCK MASK DB 7 ;EXTENT MASK DW 149 ;BLOCKS PER DISKETTE DW 127 ;# DIRECTORY ENTRIES DB 128 ;ALLOC 0 DB 0 ;ALLOC 1 DW 32 ;DIR CHECK VECTOR SIZE DW 2 ;SYSTEM TRACK OFFSET ; T848: DB 48,48,1 T826: DB 26,13,6 T815: DB 15,15,4 T88: DB 8,8,3 T84: DB 4,2,2 ENDIF ; IF MINI MSELTBL: DW T518,DP5S0 DW T510,DP5S1 DW T55,DP5S1 DW T52,DP5S3 DW T529,DP5D0 DW T518,DP5D1 DW T510,DP5D2 DW T55,DP5D2 DP5S0: DW 18 ;SECTORS PER TRACK DB 3 ;BLOCK SHIFT FACTOR DB 7 ;BLOCK MASK DB 0 ;EXTENT MASK DW 172 ;BLOCKS PER DISKETTE DW 63 ;# DIRECTORY ENTRIES DB 192 ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;DIR CHECK VECTOR SIZE DW 3 ;SYSTEM TRACK OFFSET DP5S1: DW 20 ;SECTORS PER TRACK DB 3 ;BLOCK SHIFT FACTOR DB 7 ;BLOCK MASK DB 0 ;EXTENT MASK DW 192 ;BLOCKS PER DISKETTE DW 63 ;# DIRECTORY ENTRIES DB 192 ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;DIR CHECK VECTOR SIZE DW 3 ;SYSTEM TRACK OFFSET DP5S3: DW 16 ;SECTORS PER TRACK DB 3 ;BLOCK SHIFT FACTOR DB 7 ;BLOCK MASK DB 0 ;EXTENT MASK DW 153 ;BLOCKS PER DISKETTE DW 63 ;# DIRECTORY ENTRIES DB 192 ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;DIR CHECK VECTOR SIZE DW 3 ;SYSTEM TRACK OFFSET DP5D0: DW 29 ;SECTORS PER TRACK DB 4 ;BLOCK SHIFT FACTOR DB 15 ;BLOCK MASK DB 1 ;EXTENT MASK DW 138 ;BLOCKS PER DISKETTE DW 63 ;# DIRECTORY ENTRIES DB 128 ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;DIR CHECK VECTOR SIZE DW 3 ;SYSTEM TRACK OFFSET DP5D1: DW 36 ;SECTORS PER TRACK DB 4 ;BLOCK SHIFT FACTOR DB 15 ;BLOCK MASK DB 1 ;EXTENT MASK DW 172 ;BLOCKS PER DISKETTE DW 63 ;# DIRECTORY ENTRIES DB 128 ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;DIR CHECK VECTOR SIZE DW 3 ;SYSTEM TRACK OFFSET DP5D2: DW 40 ;SECTORS PER TRACK DB 4 ;BLOCK SHIFT FACTOR DB 15 ;BLOCK MASK DB 1 ;EXTENT MASK DW 192 ;BLOCKS PER DISKETTE DW 63 ;# DIRECTORY ENTRIES DB 128 ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;DIR CHECK VECTOR SIZE DW 3 ;SYSTEM TRACK OFFSET T529: DB 29,29,7 T518: DB 18,9,4 T510: DB 10,10,3 T55: DB 5,5,2 T52: DB 2,2,1 ENDIF ; ;END OF FIXED TABLES ; ; CO: LDA IOBYTE ANI 3 ;ISOLATE CONSOLE ASGT JZ TTYOUT ;TTY ACTIVE CPI 2 JM CRTOUT ;CRT ACTIVE JNZ CUSO1 ;USER CONSOLE 1 ACTIVE ; LO: LDA IOBYTE ANI 0C0H ;ISOLATE LIST ASGT JZ TTYOUT ;TTY ACTIVE CPI 80H JM CRTOUT ;CRT ACTIVE JZ LPRT ;LINE PRINTER ACTIVE JMP LUSE1 ;USER PRINTER 1 ACTIVE ; CSTS: LDA IOBYTE ANI 3 ;ISOLATE CONSOLE ASGT JZ TTST ;TTY ACTIVE CPI 2 JM CRTST ;CRT ACTIVE JNZ CUST1 ;USER CONSOLE 1 ACTIVE ; BATST: LDA IOBYTE ANI 0CH ;ISOLATE BATCH ASGT JZ TTST ;TTY ACTIVE CPI 8 JM PTRST ;PAPER TAPE READER ACTIVE JZ RUST1 ;USER READER 1 ACTIVE JMP RUST2 ;USER READER 2 ACTIVE ; CI: LDA IOBYTE ANI 3 ;ISOLATE CONSOLE ASGT JZ TTYIN ;KBD ACTIVE CPI 2 JM CRTIN ;CRT ACTIVE JNZ CUSI1 ;USER CONSOLE 1 ACTIVE ; RI: LDA IOBYTE ANI 0CH ;ISOLATE BATCH ASGT JZ TTYRDR ;TTY ACTIVE CPI 8 JM PTRIN ;PAPER TAPE READER ACTIVE JZ RUSI1 ;USER READER 1 ACTIVE JMP RUSI2 ;USER READER 2 ACTIVE ; LSTAT: LDA IOBYTE ANI 0C0H ;ISOLATE THE LIST DEVICE ASSIGNMENT JZ TTOST CPI 80H JM HSPST JZ LPRTS JMP LUST1 ; PO: LDA IOBYTE ANI 30H ;ISOLATE PUNCH ASGT JZ TTPNCH ;TTY ACTIVE CPI 20H JM HSP ;HIGH SPEED PUNCH ACTIVE JZ PUSO1 ;USER PUNCH 1 ACTIVE JMP PUSO2 ;USER PUNCH 2 ACTIVE ; ; ROUTINE CONI READS THE CONSOLE AND STRIPS OFF THE ASCII ; PARITY BIT. ; PRTRD: CALL PMSG CONI: CALL CI ;GET THE NEXT CHARACTER ANI 7FH ;STRIP OFF THE PARITY BIT RTS: RET ; ; ROUTINE PRTWD PRINTS AN ASCII STRING ONTO THE CONSOLE. ; THE STRING MUST BE TERMINATED BY BIT 7 SET IN THE ; LAST CHARACTER OF THE STRING. THE STRING WILL START ; A NEW LINE (EP = PRTWD) OR CONTINUE ON THE SAME ; LINE (EP = PRTWA) ; PRTWD: CALL CRLF ;START A NEW LINE PRTWA: PUSH B ;SAVE (B,C) PRTA: MOV C,M ;GET NEXT CHARACTER FROM MEMORY CALL CO ;OUTPUT IT INX H ;INCREMENT MEMORY POINTER MOV A,C RLC ;TEST FOR BIT 7 DELIMITER JNC PRTA ;NO DELIMITER, GO DO NEXT CHARACTER PRTB: POP B ;RESTORE (B,C) RET ; ; ROUTINE CRLF GENERATES A CARRIAGE RETURN, LINE FEED ; SEQUENCE ON THE CURRENT CONSOLE TO START A NEW LINE ; IT INCLUDES TWO NULL CHARACTERS FOR TTY TYPE ; DEVICES FOR THE HEAD MOVEMENT TIME. ; PMSG: CALL PRTWD CRLF: PUSH H ;SAVE THE CONTENTS OF (H,L) CRLFA: LXI H,CRMSG ;ADDRESS OF CR,LF MESSAGE CALL PRTWA ; OUTPUT IT POP H ;RESTORE (H,L) RET ; IOER: XRA A ;RESET IOBYTE STA IOBYTE LXI H,IOMSG ;ADDRESS OF IO ERROR MESSAGE JMP COMERR ; RSTER: LXI H,RSTMSG ;GET ADDRESS OF RESTART ERROR MSG COMERR: CALL PMSG ;PRINT IT ON NEW LINE JMP WBOOTV ;GO TO WARM BOOT ; IOMSG: DB BELL,'I/O ASGT ERRO','R'+80H RSTMSG: DB BELL,'RST ER','R'+80H DNRMSG: DB BELL,'DRIVE ' DNRMSGA: DB 0,' NOT READ','Y'+80H BOTMSG: DB BELL,'CANNOT BOO','T'+80H CRMSG: DB CR,LF,0,80H ; ; I/O DRIVERS FOR THE 8250 ASYNC COMM ELEMENT ; TTST: IN SLSTAT ;GET 8250 LINE STATUS ANI RXRDY ;SEE IF RECEIVE DATA AVAILABLE RZ ;RETURN IF NOT ADI 0FFH AND NOT RXRDY ;FLAG THAT DATA IS AVAILABLE RET ; TTYIN: CALL TTST ;GET 8250 LINE STATUS JZ TTYIN ;LOOP UNTIL DATA IS IN IN SDATA ;READ THE DATA RET ; TTOST: IN SLSTAT ;GET 8250 LINE STATUS ANI TXMTY ;ISOLATE TX BUFFER EMPTY BIT RZ ;RETURN IF NOT EMPTY ADI 0FFH AND NOT TXMTY ;FLAG THE EMPTY STATE RET ; TTYOUT: CALL TTOST ;GET 8250 LINE STATUS JZ TTYOUT ;WAIT UNTIL ONE OF THE REGISTERS EMPTIES MOV A,C ;MOVE THE DATA OVER OUT SDATA ;OUTPUT THE DATA RET ; ; ; I/O DRIVERS FOR XEROX 630 PRINTER ; LPRT: CALL LPRTS JNC LPRT CPBSY: CALL POBUSY JC CPBSY MOV A,C CALL POSEND CPI 0AH RNZ ; CPBSY2: CALL POBUSY JC CPBSY2 MVI A,03H CALL POSEND WAIT: CALL LPRTS JC WAIT ; POBUSY: IN LPSTS ANI 80H XRI 80H STC RNZ ORA A RET ; LPRTS: IN LPSTS ANI RXRDY XRI RXRDY STC RNZ IN LPOUT ORA A RET ; POSEND: OUT LPOUT RET ; ; EQUATES FOR ADDITIONAL CONSOLE DEVICES ; CRTIN: EQU IOER CRTOUT: EQU IOER CRTST: EQU IOER CUSI1: EQU IOER ;UNASSIGNED USER CONSOLE (INPTUT) CUSO1: EQU IOER ;UNASSIGNED USER CONSOLE (OUPTUT) CUST1: EQU IOER ; ; EQUATES FOR ADDITIONAL PAPER TAPE PUNCH DEVICES ; TTPNCH: EQU TTYOUT ;UNASSIGNED TELETYPE PUNCH HSP: EQU IOER ;UNASSIGNED HIGH SPEED PUNCH HSPST: EQU IOER ;UNASSIGNED HIGH SPEED PUNCH STATUS PUSO1: EQU IOER ;UNASSIGNED USER PUNCH 1 PUSO2: EQU IOER ;UNASSIGNED USER PUNCH 2 ; ; EQUATES FOR ADDITIONAL LIST DEVICES ; LUSE1: EQU IOER ;UNASSIGNED LIST DEVICE 1 LUST1: EQU IOER ;UNASSIGNED LIST DEVICE 1 STATUS ; ; EQUATES FOR ADDITIONAL PAPER TAPE READER DEVICES ; TTYRDR: EQU TTYIN ;UNASSIGNED TELETYPE PAPER TAPE READER PTRIN: EQU IOER ;UNASSIGNED HIGH SPEED PAPER TAPE READER PTRST: EQU IOER ;UNASSIGNED HS PTR STATUS RUSI1: EQU IOER ;UNASSIGNED PAPER TAPE READER 1 RUST1: EQU IOER ;UNASSIGNED PAPER TAPE READER 1 (STATUS) RUSI2: EQU IOER ;UNASSIGNED PAPER TAPE READER 2 RUST2: EQU IOER ;UNASSIGNED PAPER TAPE READER 2 (STATUS) ; ; ONE-TIME CODE (USED ONLY DURING COLD BOOT) ; BOOT: IN DCTRL ;SEE IF AUTO-BOOT IN PROGRESS ANI 40H ;ISOLATE THE BOOT BIT JNZ BOOTA ;JUMP IF NOT AUTO-BOOT MVI A,RESET ;SET MODEM CONTROL REGISTER OUT ACMD ;RESET DEVICE A MVI A,MASKA ;GET INT MASK OUT AMSK ;MASK A SET MVI A,BAUDA ;GET BAUD RATE OUT SLSTAT ;SET BAUD RATE CHANNEL A BOOTA: LXI H,LOGMSG ;SIGN ON TO THE SYSTEM CALL PMSG LXI H,0 SHLD IOBYTE ;SET IOBYTE, CDISK JMP BOOT0 ;GO DO THE BOOT COMMON CODE ; LOGMSG: DB MSIZE/10+'0',MSIZE MOD 10 + '0' DB 'k CP/M Vers ' DB VERS/10+'0','.',VERS MOD 10+'0',80H ; ORG BOOT ; ;THE REMAINDER OF THE CCBIOS 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"). ; BEGDAT EQU $ ;BEGINNING OF DATA AREA ; SEKDSK: DS 1 SEKTRK: DS 1 SEKHST: DS 1 SEKSID: DS 1 SEKSEC: DS 1 SEKSEL: DS 1 ; DMAAD: DS 2 ;DIRECT MEMORY ADDRESS ; HSTACT: DS 1 HSTWRT: DS 1 ; UNADSK: DS 1 UNATRK: DS 1 UNASEC: DS 1 UNASID: DS 1 UNACNT: DS 1 CPMSEC: DS 1 NXTSCT: DS 1 ; ERFLAG: DS 1 RSFLAG: DS 1 READOP: DS 1 WRTYPE: DS 1 ; ;SCRATCH RAM AREA FOR BDOS USE ; DIRBF: DS 128 ;SCRATCH DIRECTORY AREA ALL00: DS 38 ;ALLOCATION VECTOR 0 ALL01: DS 38 ;ALLOCATION VECTOR 1 ALL02: DS 38 ;ALLOCATION VECTOR 2 ALL03: DS 38 ;ALLOCATION VECTOR 3 CHK00: DS 32 ;CHECK VECTOR 0 CHK01: DS 32 ;CHECK VECTOR 1 CHK02: DS 32 ;CHECK VECTOR 2 CHK03: DS 32 ;CHECK VECTOR 3 ; DBUF: DS 1024 ;DISK BUFFER ; ENDDAT EQU $ ;END OF DATA AREA DATSIZ EQU $-BEGDAT;SIZE OF DATA AREA ; CONST: EQU CSTS CONOUT: EQU CO LIST: EQU LO PUNCH: EQU PO READER: EQU RI LISTST: EQU LSTAT END