; ;***************************************************************************; ; ; ; ; ; CP/M 2.2 MAGNUM BIOS ; ; FOR THE FC-100 ; ; AND MAGNUM SERIES CONTROLLERS ; ; ; ; COPYRIGHT 1984, DION VAUGHN ; ; ; ; ; ;***************************************************************************; ; ; ;VERSION 2.5NS - FOR NORTH STAR (ONLY DIFFERENCE IS BIAS AND CCP VALUES) ; ; MSIZE: EQU 56 ;TOP OF RAM MSIZH: EQU 56H ;ENTER AS HEX NUMBER ALSO FOR SIGNON MSG ; ; WHEN USING MOVCPM, USE MSIZE-3 FOR NN ; COMMAND FORMAT WILL THEN BE: MOVCPM NN * ; STACK: EQU 0100H ;STACK BASE BIAS: EQU (MSIZE-21)*1024 ;SET FOR NORTH STAR, (MSIZE-23 IS STANDARD) CCP: EQU BIAS+03100H ;CCP BASE SET FOR NORTH *, (+3400H IS STANDARD) BDOS: EQU CCP+0806H ;BDOS BASE BIOSB: EQU CCP+01600H ;BIOS BASE ; IOBYTE: EQU 03 ;I/O BYTE CDISK: EQU 04 ;CURRENT LOGGED IN DISK BDOSEV: EQU 05 ;BDOS ENTRY VECTOR ; DMADA: EQU 0080H ;DMA DEFAULT ADDRESS ; PUNS: EQU 01H ;PUNCH STATUS PORT (SERIAL) PUNDT: EQU 00H ;PUNCH DATA PORT (SERIAL) CONS: EQU 03H ;CONSOLE STATUS PORT (SERIAL) CONDT: EQU 02H ;CONSOLE DATA PORT (SERIAL) LSTST: EQU 08H ;LIST DEVICE STATUS PORT LSTDT: EQU 08H ;LIST DEVICE DATA PORT ; CNTBS: EQU 0D0H ;BASE PORT FOR DISK CONTROLLER CNTS: EQU CNTBS ;CONTROLLER STATUS COMR: EQU CNTBS ;COMMAND REGISTER TRKR: EQU CNTBS+01 ;TRACK REGISTER SECR: EQU CNTBS+02 ;SECTOR REGISTER DATR: EQU CNTBS+03 ;DATA REGISTER BRDST: EQU CNTBS+04 ;BOARD SETUP LATCH DRQS: EQU CNTBS+06 ;DRQ SYNC TMRT: EQU CNTBS+07 ;TIMER ON TEST ; FILL: EQU 0E5H ;FILL CHARACTER RDSEC: EQU 084H ;READ COMMAND WRSEC: EQU 0A0H ;WRITE COMMAND FCINT: EQU 0D0H ;FORCED INTERRUPT OF CONTROLLER CHIP ; CR: EQU 0DH LF: EQU 0AH ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; JUMP TABLE ; ; ORG BIOSB ;ORIGIN OF MBIOS ; START: JMP BOOT ;COLD BOOT BIOS: JMP WBOOT ;WARM BOOT JMP CONST ;CONSOLE STATUS JMP CONIN ;CONSOLE CHARACTER IN ROUTINE JMP CONOUT ;CONSOLE CHARACTER OUT ROUTINE JMP LIST ;LIST CHARACTER OUT JMP PUNCH ;PUNCH CHARACTER OUT JMP READER ;READER CHARACTER IN JMP HOME0 ;MOVE HEAD TO HOME POSITION JMP SLDSK ;SELECT DISK JMP SETTRK ;SET TRACK NUMBER JMP SETSEC ;SET SECTOR NUMBER JMP SETDMA ;SET DMA ADDRESS JMP READ ;READ FROM DISK JMP WRITE ;WRITE TO DISK JMP LISTST ;LIST STATUS JMP SECTRAN ;SECTOR TRANSLATE TABLES ; ; ; THE BIOS MAP (BMAP) IS SET UP TO REMAIN AT THIS LOCATION RELATIVE TO THE ; BIOS ORIGIN (BIOSB). THIS ALLOWS EXTERNAL PROGRAMS TO ACCESS THE ROUTINES ; LISTED IN BMAP. ; BMAP: DW DSPB ;ADDRESS OF FIRST DISK SETUP PARAMETER BLOCK DW DPBAS ;DISK PARAMETER BLOCK BASE ; DW CRTST ;ROUTINE FOR CRT INPUT STATUS DW 0 ;RESERVED ; DW LAST ;END OF BIOS CODE (NOT INCLUDING DATA AREA) DW 0 ;RESERVED DW START ;BIOS ORIGIN ; DW CRTIN ;CONSOLE INPUT ROUTINE DW CRTOUT ;CONSOLE OUTPUT ROUTINE ; DW TTYLST ;LIST DEVICE STATUS ROUTINE DW TTYLOUT ;LIST DEVICE OUTPUT ROUTINE ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; COLD BOOT ; BOOT: LXI SP,STACK ;INITIALIZE STACK ; MVI A,01 ;SET IO BYTE TO CRT STA IOBYTE ;INITIALIZE MVI A,00 ;ZERO THE ACCUMULATOR STA BUFST LDA CDISK ;CURRENT DEFAULT DISK (CDISK) SET BY ROM STA BOOTDSK ;ALSO MAKE IT THE BOOT DISK LXI B,0 ;SET DISKNO VALUE (0-3) MOV H,B ;STORE IN VARIABLE 'DISKNO' MOV L,C SHLD DISKNO CALL CLSCR ;CLEAR THE SCREEN ; LXI H,SMSG ;LOAD ADDRESS OF SIGN-ON MESSAGE CALL PRNT ;PRINT MESSAGE MVI A,MSIZH ;PRINT SYSTEM SIZE CALL AHEX LXI H,SMSG1 CALL PRNT ; MVI A,00 ;RESET BOOT FLAG STA BOOTFL JMP WBOOT ; CBOOT: MVI A,0FFH ;SET BOOT FLAG STA BOOTFL JMP CCP ; SGNON: DB '(C) COPYRIGHT 1984 DION VAUGHN$' ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; WARM BOOT ; WBOOT: LXI SP,STACK ;INITIALIZE STACK LDA BUFST ;RESET THE BUFFER ANI 0FEH ;MARK AS CLEAN BUFFER STA BUFST MVI A,0FFH ;MARK AS IMPOSSIBLE DISK STA BDISK LHLD BOOTDSK MVI B,00 MOV C,L ;SELECT BOOT DISK MVI E,0 CALL SLDSK ; LHLD DISKNO ;GET THE BOARD SETUP BYTE CALL SELDSPB ; SHLD CDPB ;STORE FOR LATER USE INX H ;SIDE MOV A,M ORI 010H ;SET TO SIDE 0 ANI 0DFH ;RESET TO DOUBLE DENSITY OUT BRDST ;OUT TO BOARD SETUP LATCH CALL DSKRDY ;GET IT READY ; ;READ IN 1ST HALF OF CCP (TRACK 0, SECTOR 5) LXI H,5 ;STARTING SECTOR LXI B,1024 ;READ ONE SECTOR LXI D,CCP ;ADDRESS OF CCP CALL MSRD ;MULTIPLE SECTOR READ ; CPI 0 ;ANY ERRORS? JZ WBOOT1 ;THEN CONTINUE ; LXI H,WBMSG1 ;REPORT CCP1 READ ERROR CALL PRNT ; JMP WBOOT ; WBMSG1: DB CR,LF,'CCP1 READ ERROR$' ; ;STEP IN TO TRACK 1, OR FLIP SIDES IF DOUBLE SIDED WBOOT1: LHLD CDPB ;LOAD CURRENT DSPB INX H ;SINGLE/DOUBLE SIDED AND STEP RATE INX H MOV A,M ANI 04H ;TEST SINGLE/DOUBLE SIDED JZ STPIN ;IF SINGLE SIDED STEP IN ; DCX H ;SIDE MOV A,M ;ELSE SET CONTROLLER FOR SIDE 1 ANI 0EFH ;RESET BIT 4 OUT BRDST JMP WBOOT2 ;BACK TO BOOT ROUTINE ; STPIN: MVI A,05BH ;STEP IN (SLOW RATE) DI OUT COMR CALL BUSY ; ;READ IN THE REST OF THE CCP AND THE BDOS (TRACK 1, SECTORS 1-5) WBOOT2: LXI H,1 ;STARTING SECTOR LXI B,0400H+0E00H ;NUMBER OF BYTES TO READ CALL MSRD ;CALL MULTIPLE SECTOR READ ROUTINE ; CPI 0 ;ANY ERRORS? JZ GOCPM ;IF NOT CONTINUE ; LXI H,WBMSG2 ;REPORT CCP2/BDOS READ ERROR CALL PRNT ; JMP WBOOT ; WBMSG2: DB CR,LF,'CCP2/BDOS READ ERROR$' ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; GOCPM: MVI A,0C3H ;LOAD A WITH JUMP INSTRUCTION STA 0000 ;STORE IT AT LOCATION 0 LXI H,BIOS ;LOAD BIOS ADDRESS INTO HL SHLD 0001H ;STORE IT AT BIOS ENTRY VECTOR STA BDOSEV ;SETUP BDOS ENTRY VECTOR LXI H,BDOS ;LOAD BDOS ADDRESS INTO HL SHLD BDOSEV+1 ;STORE IT AT BDOS ENTRY VECTOR LXI B,DMADA ;LOAD BC WITH DEFAULT DMA ADDRESS CALL SETDMA ; LDA CDISK ;LOAD A WITH CURRENT DISK NUMBER MOV C,A ;SAVE IT IN C ; LDA BOOTFL ;CHECK BOOT FLAG CPI 00H JZ CBOOT ; JMP CCP+3 ;TAKE IT TO THE CCP ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; IOBYTE (LOCATION 0003) ; ; DEVICE ----- LIST PUNCH READER CONSOLE ; BIT ----- 7, 6 5, 4 3, 2 1, 0 ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; CONSOLE STATUS ; ; ENTRY: NONE ; EXIT: A = 00H: NO CHARACTER READY ; A = FFH: CHARACTER READY ; CHANGED: A ; CONST: LDA IOBYTE ANI 03 ;MASK OFF BITS 0 AND 1 CPI 01 ;CRT ROUTINE JZ CRTST ; ; CPI 02 ;BATCH ROUTINE ; JZ BATST ; ; CPI 03 ;USER DEFINED I/O ; JZ USRST ; ;TTYST: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; CRTST: IN CONS ;INPUT THE STATUS ANI 02 ;MASK BIT 1 JNZ CRTST1 ;IF SO JUMP TO CRTST1 ; MVI A,0 ;IF NOT LOAD ZERO STATUS RET ; CRTST1: MVI A,0FFH ;IF SO LOAD READY STATUS RET ; ;BATST: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;USRST: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; CHARACTER IN ROUTINE ; ; ENTRY: NONE ; EXIT: A = 7 BIT CHARACTER FROM CONSOLE ; CHANGED: A ; CONIN: LDA IOBYTE ;LOAD THE IOBYTE ANI 03 ;MASK BITS 0 AND 1 CPI 01 ;CRT ROUTINE JZ CRTIN ; ; CPI 02 ;BATCH ROUTINE ; JZ BATIN ; ; CPI 03 ;USER DEFINED I/O ; JZ USRIN ; ;TTYIN: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; CRTIN: IN CONS ;INPUT THE STATUS ANI 02 ;CHARACTER READY? JZ CRTIN ;LOOP UNTIL READY ; IN CONDT ;IF READY INPUT THE CHARACTER ANI 07FH ;STRIP OFF PARITY BIT RET NOP NOP NOP NOP NOP NOP ; ;BATIN: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;USRIN: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; CHARACTER OUT ROUTINE ; ; ENTRY: C = 7 BIT CHARACTER TO SEND TO CONSOLE ; EXIT: NONE ; CHANGED: A ; CONOUT: LDA IOBYTE ;LOAD THE IOBYTE ANI 03 ;MASK BITS 0 AND 1 CPI 01 ;CRT ROUTINE JZ CRTOUT ; ; CPI 02 ;BATCH ROUTINE ; JZ BATOUT ; ; CPI 03 ;USER DEFINED I/O ; JZ USROUT ; ;TTYOUT: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; CRTOUT: IN CONS ;INPUT THE STATUS ANI 01 ;CHARACTER READY? JZ CRTOUT ;LOOP UNTIL READY ; MOV A,C ;IF READY OUTPUT THE CHARACTER OUT CONDT RET NOP NOP NOP NOP NOP NOP NOP ; ;BATOUT: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;USROUT: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; LIST DEVICE STATUS ; ; ENTRY: NONE ; EXIT: A = 00H: NOT READY ; A = 01H: READY ; CHANGED: A ; LISTST: ;LDA IOBYTE ;LOAD IOBYTE INTO A ; RLC ;SHIFT BITS 6, 7 TO 0, 1 ; RLC ; ANI 03 ;MASK BITS 0 AND 1 ; CPI 01 ;CRT ROUTINE ; JZ CRTLST ; ; CPI 02 ;BATCH ROUTINE ; JZ BATLST ; ; CPI 03 ;USER DEFINED I/O ; JZ USRLST ; TTYLST: IN LSTST ;INPUT STATUS ANI 01 ;TEST BIT 0 MVI A,0 RZ MVI A,0FFH RET ; ;CRTLST: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;BATLST: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;USRLST: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; LIST DEVICE ; ; ENTRY: C = 7 BIT CHARACTER TO SEND TO LIST DEVICE ; EXIT: NONE ; CHANGED: A ; LIST: ;LDA IOBYTE ;LOAD IOBYTE INTO A ; RLC ;SHIFT BITS 6, 7 TO 0, 1 ; RLC ; ANI 03 ;MASK BITS 0 AND 1 ; CPI 01 ;CRT ROUTINE ; JZ CRTLOUT ; ; CPI 02 ;BATCH ROUTINE ; JZ BATLOUT ; ; CPI 03 ;USER DEFINED I/O ; JZ USRLOUT ; TTYLOUT:IN LSTST ;INPUT STATUS ANI 01 ;TEST BIT 0 JNZ TTYLOUT ;LOOP UNTIL READY ; MOV A,C ;MOVE CHARACTER TO A ORI 80H ;ADD STROBE OUT LSTDT ;OUTPUT XRI 80H ;STROBE OUT LSTDT ;OUTPUT XRI 80H ;STROBE OUT LSTDT ;OUTPUT RET NOP ;EXTRA SPACE NOP NOP NOP NOP ; ;CRTLOUT:MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;BATLOUT:MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;USRLOUT:MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; PUNCH DEVICE ; ; ENTRY: C = 7 BIT CHARACTER TO SEND TO PUNCH DEVICE ; EXIT: NONE ; CHANGED: A ; PUNCH: ;LDA IOBYTE ;LOAD THE IOBYTE ; RLC ; RLC ; RLC ; RLC ; ANI 03 ;MASK BITS 0 AND 1 ; CPI 01 ;CRT ROUTINE ; JZ CRTPOUT ; ; CPI 02 ;BATCH ROUTINE ; JZ BATPOUT ; ; CPI 03 ;USER DEFINED I/O ; JZ USRPOUT ; TTYPOUT:IN PUNS ;INPUT THE STATUS ANI 01 ;CHARACTER READY? JZ TTYPOUT ;LOOP UNTIL READY ; MOV A,C ;IF READY OUTPUT THE CHARACTER OUT PUNDT RET ; ;CRTPOUT:MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;BATPOUT:MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;USRPOUT:MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; READER DEVICE ; ; ENTRY: NONE ; EXIT: A = 7 BIT CHARACTER FROM READER DEVICE ; CHANGED: A ; READER: ;LDA IOBYTE ;LOAD THE IOBYTE ; RRC ; RRC ; ANI 03 ;MASK BITS 0 AND 1 ; CPI 01 ;CRT ROUTINE ; JZ CRTRIN ; ; CPI 02 ;BATCH ROUTINE ; JZ BATRIN ; ; CPI 03 ;USER DEFINED I/O ; JZ USRRIN ; TTYRIN: IN PUNS ;INPUT THE STATUS ANI 01 ;CHARACTER READY? JZ TTYRIN ;LOOP UNTIL READY ; IN PUNDT ;IF READY INPUT THE CHARACTER ANI 07FH ;STRIP OFF PARITY BIT RET ; ;CRTRIN: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;BATRIN: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;USRRIN: MVI A,00 ; RET ;NOT YET IMPLEMENTED ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; SELECT DISK ; ; ENTRY: C = LOGICAL DISK SELECTED (0-15) ; E = IF 0, FIRST TIME SELECTED ; EXIT: HL = DISK PARAMETER HEADER ADDRESS ; HL = 00 IF ERROR ; CHANGED: ; SLDSK: PUSH PSW ;SAVE REGISTERS PUSH B PUSH D LXI H,0 ;LOAD HL WITH ZERO FOR DEFAULT ERROR LDA NMDRVS ;TEST FOR VALID DISK DCR A ;ZERO BASED DRIVE NUMBERS CMP C ;COMPARE JC SLDBP ;RETURN ON ERROR (C > NMDRVS) ; LHLD DISKNO ;GET OLD DISK'S DSPB CALL SELDSPB ; IN TRKR ;SAVE HEAD POSITION OF OLD DISK MOV M,A MVI H,0 MOV L,C ;SELECT NEW DISK SHLD DISKNO ;STORE IT IN DISKNO CALL SELDSPB ;GET THE TABLE ADDRESS IN HL ; MOV A,M ;GET THE NEW TRACK ADDRESS OUT TRKR ;OUTPUT CURRENT TRACK TO TRACK REGISTER INX H ;SIDE MOV A,M ;GET THE NEW SETUP BYTE OUT BRDST ;OUTPUT CONTROLLER SETUP BYTE ;SET STEP RATE FOR SEEK AND RESTORE COMMANDS INX H MOV A,M ;RATE, SINGLE/DOUBLE SIDED BYTE ANI 03 ;MASK BITS 0 AND 1 MOV B,A ;SAVE IN B LDA SKCMD ;GET THE SEEK COMMAND ANI 0FCH ;STRIP OFF BITS 0 AND 1 (RATE BITS) ORA B ;SET THE RATE BITS STA SKCMD ;STORE AT SKCMD LDA RSTCD ;LOAD THE RESTORE COMMAND ANI 0FCH ;STRIP OFF BITS 0 AND 1 ORA B ;SET THE RATE BITS STA RSTCD ;STORE AT RSTCD MOV A,E ;MOVE E TO A ANI 01 ;LOGGED IN YET? CZ HOME ;SET HOME AND HOME DISK ;COMPUTE PROPER DISK PARAMETER HEADER ADDRESS LHLD DISKNO DAD H ;*2 DAD H ;*4 DAD H ;*8 DAD H ;*16 (SIZE OF EACH HEADER) LXI D,DPBAS ;DE=TABLE BASE ADDRESS DAD D ;HL=DPBASE(DISKNO*16) SLDBP: POP D ;RESTORE REGISTERS POP B POP PSW RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; HOME: CALL HOME0 ; HOMER: DI ;DISABLE INTERUPTS LDA RSTCD ;LOAD RESTORE COMMAND OUT COMR CALL BUSY ;WAIT UNTILL RESTORE IS DONE ; RET ; HOME0: LXI B,0 ;USING SET TRACK ROUTINE ; ; ESTABLISH LOGICAL TRACK NUMBER FOR NEXT R/W OPERATION ; (ACTUALLY CONVERTS TRACK TO SIDE/CYLINDER PAIR) ; ; ENTRY: BC = LOGICAL TRACK NUMBER ( EX. 0-153 FOR DOUBLE SIDED 8 IN. ) ; EXIT: NONE ; CYLINDER 0 1 2 3 4 ... ; TRACK CONVERSION: SIDE 0 - 000 002 004 006 008 ... N-1 ; SIDE 1 - 001 003 005 007 009 ... N ; SECTOR HEADER: CYLINDER : SIDE : SECTOR : LENGTH CODE ; SETTRK: PUSH D PUSH H MOV L,C ;MOVE C TO L MOV H,B ;LOAD H WITH 0 SHLD TRACK ;STORE AT 'TRACK' ; LHLD DISKNO ;TEST SINGLE/DOUBLE SIDED CALL SELDSPB ; INX H ;RATE, SINGLE/DOUBLE SIDED INX H MOV A,M ANI 04H ;BIT 2 JZ SD0SEL ;IF 0 THEN THE DRIVE IS SINGLE SIDED ; ;DOUBLE SIDED - TRACK DIVIDED BY 2 = CYLINDER ;IF EVEN - SIDE 0, IF ODD - SIDE 1 ORA A ;CLEAR CARRY FLAG MOV A,C RAR ;DIVIDE BY 2 MOV C,A JNC SD0SEL ;IF EVEN, SELECT SIDE 0 ; XRA A STA SIDE ;IF ODD, SET SIDE FLAG FOR SIDE 1 JMP SDSEL ; SD0SEL: MVI A,10H ;SET SIDE FLAG FOR SIDE 0 STA SIDE ; SDSEL MOV E,M ;CHECK FOR 48/96 TPI DRIVE INX H MOV A,M ;CHECK FOR 48/96 TPI DISKETTE XRA E ANI 080H ;BIT 7 STA FORTY8 ;48/96 TPI FLAG (1 = 48 TPI IN 96 TPI DRIVE) ; MOV H,B MOV L,C SHLD CYLIND ;SET CYLINDER POP H POP D RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; SETSEC ; ; CONVERT LOGICAL RECORD TO PHYSICAL SECTOR/OFFSET PAIR ; ; ENTRY: BC = STANDARD 128 BYTE RECORD NUMBER ; NOTE: DEPENDING ON DSPB, OFFSET 3, BIT 3 ... ; IF FIRST SECTOR IS 1 THEN BC RANGES FROM 1-SPT ; IF FIRST SECTOR IS 0 THEN BC RANGES FROM 0-SPT-1 ; EXIT: NONE ; SETSEC: PUSH H MOV H,B MOV L,C SHLD SECTOR ;SAVE ORIGINAL VALUE LXI H,0 ;INITIALIZE OFFSET STORE SHLD OFFSET LHLD DISKNO ;INITIALIZE... CALL SELDSPB ; INX H ;SECTOR SIZE (0=128, 1=256, 2=512, 3=1024) INX H INX H MOV A,M ANI 07H LXI D,128 ;128 BYTE SECTOR LENGTH ORA A ;IF SECSZ = 0 (128 BYTES), BYPASS JZ SEC1 ; MVI H,0 MOV L,A SHLD CDPB DCX B ;ADJUST TO 0 BASE TEMPORARILY FOR MATH BELOW ; ; PERFORM AN "N SHIFT" OF REG PAIR BC WHERE "N" IS SECSZ VALUE (1-7) IN A ; LOW N BITS - VALUE V SUCH THAT 128*2^V IS BUFFER OFFSET ; HIGH 16-N BITS - WHEN 1 BASED, IS THE PHYSICAL SECTOR SSTOP: ORA A ;CLEAR CARRY FLAG MOV A,B ;DIVIDE BY 2 RAR MOV B,A MOV A,C RAR MOV C,A JNC SEC0 ; LHLD OFFSET DAD D ;ADD "ADDER" VALUE INTO RUNNING TOTAL SHLD OFFSET SEC0: ORA A ;CLEAR CARRY FLAG MOV A,E RAL ;MULTIPLY BY 2 MOV E,A MOV A,D RAL MOV D,A LHLD CDPB DCR L ;COUNT DOWN SHLD CDPB JNZ SSTOP ;IF NOT DONE JUMP BACK ; INX B ;BACK TO 1 BASE SECTOR COUNT ; SEC1: MOV H,B MOV L,C SHLD DSECT ;PHYSICAL DESTINATION SECTOR POP H RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; SECTOR TRANSLATION ; ; TRANSLATE RECORD ACCORDING TO DISK SKEW FACTOR ; ; ENTRY: BC = 128 BYTE RECORD NUMBER TO TRANSLATE (0-N) ; DE = ADDRESS OF SKEW TABLE ; EXIT: HL = TRANSLATED 128 BYTE RECORD NUMBER ; CHANGED: NONE ; SECTRAN:PUSH PSW ;SAVE STATUS WORD MOV A,D ORA E JNZ SECT1 ;IF NON-ZERO, TABLE IS NEEDED ; MOV H,B ;TRANSFER BC TO HL MOV L,C ;FOR 128 BYTE RECORD JMP SECT2 ; SECT1: XCHG ;HL= TRANSLATE TABLE ADDR DAD B MOV L,M MVI H,0 ;HL= TRANS(SECTOR) SECT2: POP PSW RET ;WITH VALUE IN HL ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; SET DMA (BASE OF FILE BUFFER FOR R/W OPERATIONS) ; ; ENTRY: BC = ADDRESS FOR SYSTEM R/W OPERATIONS ; EXIT: NONE ; CHANGED: NONE ; SETDMA: PUSH H MOV L,C MOV H,B SHLD DMAAD POP H RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ;READ ; ; RECORD PLACED AT LAST SETDMA AS PER SELDSK, SETTRK AND SETSEC ; ; ENTRY: NONE ; EXIT: A = 0 - NO ERROR NONZERO - ERROR ; READ: CALL MATCH ;ENSURE DESIRED SECTOR IS IN MEMORY BUFFER ; CPI 0 ;TEST FOR ERROR RNZ ;ON ERROR RETURN TO BDOS ; RLS: LHLD OFFSET ;READ LOGICAL SECTOR (128 BYTE RECORD) LXI D,BUFFER ;FROM OFFSET IN BUFFER TO DMA ADDRESS DAD D PUSH H LHLD DMAAD XCHG POP H LXI B,128 CALL BLKMV ; RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; BLOCK READ ROUTINE ; ; READ 1024 BYTE PHYSICAL BUFFER PER DISKNO, CYLIND, SIDE, DSECT ; LABEL THE PHYSICAL BUFFER AS PER BDISK, BCYLIND, BSIDE, BSECT ; ; NOTE: ERROR-ON-READ LEAVES BUFFER INVALID, MATCH WILL FORCE RE-READ ; ENTRY: NONE ; EXIT: NONE ; CHANGED: ALL ; BLKRD: LDA BUFST ;MARK BUFFER INVALID ORI 02 ;SET BIT 1 STA BUFST ; LHLD DISKNO ;BOARD SETUP SHLD BDISK ;DISK NUMBER LHLD CYLIND SHLD BCYLIND ;CYLINDER LHLD SIDE SHLD BSIDE ;SIDE LHLD DSECT SHLD BSECT ;SECTOR ; LHLD BCYLIND ;SEEK CYLINDER ; LDA FORTY8 ;CHECK IF 48 TPI IN 96 TPI DRIVE CPI 080H ;BIT 7 CZ DBLTRK ;IF 48 TPI - GO TO TRACK DOUBLER ; MOV A,L OUT DATR LDA SKCMD DI OUT COMR CALL BUSY ;WAIT TIL COMMAND IS THRU ; LDA BSECT ;SET SECTOR OUT SECR LDA BSIDE ;SET SIDE MOV B,A LHLD BDISK ;LOAD BOARD SETUP BYTE CALL SELDSPB SHLD CDPB ; INX H ;SIDE MOV A,M ANI 0EFH ;CLEAR SINGLE/DOUBLE SIDED BIT ORA B ;SET SIDE OUT BRDST INX H ;SECTOR SIZE INX H MOV A,M ;SET TRACK REGISTER (IF NOT SAME AS CYLINDER) ANI 010H ;BIT 4 JZ BR2 ; LDA TRACK OUT TRKR ; BR2: CALL DSKRDY ;WAIT TIL DRIVE IS READY CALL SECSIZ ;GET SECTOR LENGTH (COMES BACK IN BC) ; LXI D,BUFFER ;PHYSICAL BUFFER POINTER MVI A,RDSEC ;READ SECTOR CALL RD ;READ DATA FROM DISK CALL BUSY ;WAIT TILL COMMAND IS DONE ; IN CNTS ;GET THE CONTROLLER STATUS ANI 09CH ;SAVE BITS 2, 3, 4, 7 STA ERRST ;SAVE STATUS TEMPORARILY ; LHLD CDPB ;RESET TRACK REGISTER INX H ;SECTOR SIZE INX H INX H MOV A,M ANI 010H ;BIT 4 JZ BR4 ; LDA BCYLIND OUT TRKR ; BR4: LDA ERRST ;ON ERROR MARK BUFFER INVALID CPI 0 JNZ BR1 ; LDA BUFST ;IF NO ERROR MARK BUFFER AS VALID ANI 0FDH ;RESET BIT 1 STA BUFST JMP BRND ; ;READ ERROR REPORT ; BR1: LHLD BDISK ;RESELECT DISK MOV B,H MOV C,L MVI E,01 CALL SLDSK CALL HOMER ;DON'T RESTORE WILL MESS UP TRACK ; LDA ERRST ;STATUS LXI B,BR3 ;MESSAGE CALL PRTERR ; BRND: LDA ERRST ;RESTORE ERROR STATUS RET ; BR3: DB ' READ ERROR $' ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; RD ; ; READ DATA STREAM FROM CONTROLLER ; ; ENTRY: A = CONTROLLER READ COMMAND ; BC = NUMBER OF BYTES TO READ ; DE = DESTINATION ADDRESS ; EXIT: NONE ; CHANGED: ALL ; RD: DI OUT COMR ; RD1: OUT DRQS ;SYNC Z80 AND WD279X IN DATR ;GET BYTE FROM DISK STAX D ;STORE IN BUFFER INX D ;INCREMENT POINTER DCX B ;DECREMENT BYTE COUNT MOV A,C ;DONE? ORA B JNZ RD1 ;LOOP UNTIL DONE ; RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; MSRD ; ; PERFORMS A MULTIPLE SECTOR READ ; ; ENTRY: BC = NUMBER OF BYTES TO READ ; DE = DESTINATION ADDRESS ; L = STARTING SECTOR ; EXIT: ERROR CODE ; CHANGED: PSW,CDPB ; MSRD: MOV A,L ;SECTOR NUMBER OUT SECR ;OUT TO SECTOR REGISTER MVI A,094H ;LOAD MULTIPLE SECTOR READ COMMAND CALL RD ;CALL READ ROUTINE ; IN CNTS ;GET THE STATUS ANI 09CH ;MASK BITS 2, 3, 4, 7 CALL CLEAR ;WAIT TILL OPERATION IS COMPLETE ; RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; WRITE ; ; RECORD SPECIFIED BY LAST SETDMA WRITTEN PER SELDSK, SETTRK, SETSEC ; ; ENTRY: C = 0: NORMAL WRITE, PREREAD, DEFER WRITING IF POSSIBLE ; 1: DIRECTORY, PREREAD, NO DEFER OF WRITING ; 2: FIRST WRITE, NO PREREAD, DEFER WRITING IF POSSIBLE ; EXIT: A = 0: NO ERROR NONZERO: ERROR ; WRITE: MOV A,C CPI 01 ;DIRECTORY WRITE? JZ DIR ;IF SO JUMP TO DIR ; CPI 02 ;NEW BLOCK? JZ NEWBLK ;IF SO JUMP TO NEWBLK ; NORMAL: CALL MATCH ;MATCH THE DESIRED SECTOR TO BUFFERED SECTOR ; CPI 0 ;TEST FOR ERROR RNZ ;ERROR - RETURN TO BDOS ; CALL WLS ;WRITE FROM DMA TO BUFFER ; RET ; DIR: CALL NORMAL ;DIRECTORY WRITE FOLLOWS SAME PATH ; CPI 0 ;TEST FOR ERROR RNZ ;ERROR - RETURN TO BDOS ; CALL BLKWR ;WRITE BUFFERED PHYSICAL SECTOR IMMEDIATELY ; RET ; NEWBLK: CALL MATCH ;DOES A PREREAD TO POSITION DISK HEAD PROPERLY CPI 0 ;TEST FOR ERROR RNZ ;ON ERROR RETURN TO BDOS ;INITIALIZE NEW 1K BUFFER MVI A,FILL ;INITIALIZE BUFFER WITH FILL CHARACTER E5H STA BUFFER LXI H,BUFFER LXI D,BUFFER+1 LXI B,1024-1 CALL BLKMV ; CALL WLS ;WRITE A LOGICAL SECTOR INTO THE BUFFER ; RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; MOVE A LOGICAL SECTOR (128 BYTES) FROM DMA TO BUFFERED PHYSICAL SECTOR ; ; ENTRY: NONE ; EXIT: A = 0 ; CHANGED: ALL ; WLS: LHLD OFFSET LXI D,BUFFER DAD D XCHG LHLD DMAAD LXI B,128 CALL BLKMV ; LDA BUFST ;MARK BUFFERED PHYSICAL SECTOR AS UPDATED ORI 01 ;SET BUFST BIT STA BUFST ;STORE FLAG XRA A RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; BLOCK WRITE ROUTINE ; ; PERFORM ACTUAL WRITING OF BUFFERED PHYSICAL SECTOR TO DISK ; ; NOTE: ALWAYS CLEARS BUFST BIT - KEEPS ERROR-ON-WRITE FROM HANGING ; ENTRY: NONE ; EXIT: A = 0: NO ERROR ; CHANGED: ALL ; BLKWR: LHLD DISKNO ;SAVE CURRENT LOGICAL DISK PUSH H LHLD BDISK MOV C,L MVI B,0 ;SELECT PHYSICAL BUFFER'S DISK MVI E,01 CALL SLDSK ; ; ASSUME HEAD IS ALREADY SET TO CYLINDER ; BW1: LDA BSIDE ;SET SIDE MOV B,A LHLD BDISK ;GET BOARD SETUP BYTE CALL SELDSPB ; SHLD CDPB INX H ;SIDE MOV A,M ANI 0EFH ;CLEAR SINGLE/DOUBLE SIDED BIT ORA B ;SET SIDE OUT BRDST ; LDA BSECT ;SET SECTOR OUT SECR ; INX H ;SECTOR SIZE INX H MOV A,M ;SET TRACK REGISTER (IF NOT SAME AS CYLINDER) ANI 010H ;BIT 4 JZ BW4 ; LDA TRACK ;SET TRACK OUT TRKR ; BW4: CALL DSKRDY ;IS DISK READY? CALL SECSIZ ;SECTOR LENGTH LXI D,BUFFER ;PHYSICAL BUFFER POINTER MVI A,WRSEC ;LOAD WRITE SECTOR COMMAND CALL WRT CALL BUSY ;WAIT UNTIL COMMAND IS EXECUTED IN CNTS ;GET STATUS TO CHECK FOR ERRORS ANI 0DCH ;STRIP OFF BITS 0 AND 1 STA ERRST ;SAVE STATUS ; LHLD CDPB ;RESET TRACK REGISTER TO REPRESENT CYLINDER INX H ;SECTOR SIZE INX H INX H MOV A,M ANI 010H ;BIT 4 JZ BW5 ; LDA BCYLIND OUT TRKR ; BW5: LDA ERRST ;EXIT IF NO ERROR CPI 0 JZ BWND ; ;WRITE ERROR REPORT ; BW2: LHLD BDISK ;RESELECT DISK, RESTORE HEAD MOV C,L MVI B,0 MVI E,0 ;FIRST TIME DISK SELECT CALL SLDSK ; LHLD BCYLIND ;REPOSITION HEAD ; LDA FORTY8 ;CHECK IF 48 TPI IN 96 TPI DRIVE CPI 080H ;BIT 7 CZ DBLTRK ;IF 48 TPI - GO TO TRACK DOUBLER ; MOV A,L OUT DATR LDA SKCMD DI OUT COMR DBLRET: CALL BUSY ; LDA ERRST ;STATUS LXI B,BW3 ;MESSAGE CALL PRTERR ; BWND: LDA BUFST ;CLEAR THE UPDATE BIT OF THE BUFST WORD ANI 0FEH ;RESET BIT 0 STA BUFST POP B ;RESTORE ORIGINALLY SELECTED DISK MVI E,01 CALL SLDSK ; LDA ERRST ;RESTORE STATUS FOR ERROR CHECKING RET ; BW3: DB ' WRITE ERROR ','$' ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; WRT ; ; WRITE DATA STREAM TO CONTROLLER ; ; ENTRY: A = CONTROLLER WRITE COMMAND ; BC = NUMBER OF BYTES TO WRITE ; DE = SOURCE ADDRESS ; EXIT: NONE ; CHANGED: ALL ; WRT: DI OUT COMR ; WRT1: OUT DRQS ;SYNC Z80 AND WD279X LDAX D ;STORE INTO BUFFER OUT DATR ;WRITE BYTE TO DISK INX D ;INCREMENT POINTER DCX B ;DECREMENT BYTE COUNT MOV A,C ;DONE? ORA B JNZ WRT1 ;LOOP UNTIL DONE ; RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; TRACK DOUBLER ; ; SET UP FOR 48 TPI DISK IN 96 TPI DRIVE - (DOUBLE STEP) ; DBLTRK: IN TRKR ;GET CURRENT TRACK REGISTER MOV C,A ;STORE IT TEMPORARILY MOV A,L ;FIRST SEEK OUT DATR LDA SKCMD ;SEEK COMMAND DI OUT COMR CALL BUSY ; MOV A,C ;RESTORE OLD TRACK REGISTER VALUE OUT TRKR ;MAKE CONTROLLER THINK SEEK NOT YET DONE ; RET ;GO DO SECOND SEEK AND CONTINUE ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; BLOCK MOVE ; ; BLOCK MOVE FROM HL POINTER TO DE POINTER ; ; ENTRY: BC = NUMBER OF BYTES IN BLOCK TO MOVE ; EXIT: NONE ; BLKMV: MOV A,M ;SOURCE POINTER STAX D ;DESTINATION POINTER INX D INX H DCX B ;NUMBER OF BYTES COUNTER MOV A,C ORA B ;EMPTY? JNZ BLKMV ;IF NOT LOOP TIL DONE ; RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; BUFFER UPDATE ; ; WRITES UPDATED BUFFER TO DISK ; ; ENTRY: NONE ; EXIT: A = ERROR FLAG ; BUFUD: LDA BUFST ;BUFFER BEEN UPDATED? ANI 01 JZ BUFW ; CALL BLKWR ;IF YES, WRITE IT TO DISK ; CPI 0 RNZ ;REPORT WRITE ERROR ; BUFW: CALL BLKRD ;GET SECTOR ; RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; MATCH ; ; CHECKS FOR NEW SECTOR, TRACK, SIDE, DISK ; ; ENTRY: NONE ; EXIT: A = ERROR CODE ; MATCH: LDA DSECT ;NEW SECTOR? MOV B,A LDA BSECT CMP B JNZ BUFUD ;IF SO GO GET IT ; LDA CYLIND ;TRACK MOV B,A LDA BCYLIND CMP B JNZ BUFUD ; LDA SIDE ;SIDE MOV B,A LDA BSIDE CMP B JNZ BUFUD ; LDA DISKNO ;DISK MOV B,A LDA BDISK CMP B JNZ BUFUD ; LDA BUFST ;BUFFER VALID? ANI 02 JNZ BUFUD ; XRA A ;SET FOR NO ERROR RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; SELDSPB ; ; RETURN DSPB ADDRESS OF SPECIFIED LOGICAL DISK ; ; ENTRY: HL = LOGICAL DISK NUMBER ; EXIT: HL = DSPB OF SPECIFIED DISK ; CHANGED: NONE ; SELDSPB:PUSH D ;SAVE REGISTERS DAD H ; * 2 SHIFT FOR OFFSET DAD H ; * 4 LXI D,DSPB ;TABLE BASE DAD D ;OFFSET POP D ;RESTORE REGISTER RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; SECSIZ ; ; RETURNS SECTOR LENGTH FOR ANY GIVEN DISK ; ; ENTRY: NONE ; EXIT: BC = SECTOR LENGTH IN BYTES ; CHANGED: NONE ; SECSIZ: PUSH PSW ;SAVE REGISTERS PUSH H LHLD CDPB ;LOAD DSPB INX H ;SECTOR SIZE INX H INX H MOV A,M ;GET CODE FOR SECTOR SIZE (0 - 3) ANI 07H ;MASK OFF BITS 0-2 ADD A ;MULTIPLY BY 2 MOV C,A ;MOVE IT TO BC MVI B,0 LXI H,LENCODE ;LOAD BASE ADDRESS DAD B ;ADD OFFSET MOV C,M ;LOAD INTO C INX H MOV B,M POP H POP PSW RET LENCODE:DW 128,256,512,1024 ;LENGTH CODE TABLE ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; PRINT MESSAGE ; ; ENTRY: HL = STRING ADDRESS ; EXIT: HL = POINTS TO DELIMITER ; CHANGED: NONE ; PRNT: PUSH PSW ;SAVE THE STATUS WORD PUSH B ;SAVE BC PRNTLP: MOV A,M ;LOAD CHAR INTO A CPI 024H ;'$'= END OF STRING DELIMITER JZ PRNT0 ;RETURN IF EOS ; MOV C,A ;SAVE CHAR IN C CALL CONOUT ;PRINT THE CHARACTER ; INX H ;INCREMENT THE COUNTER JMP PRNTLP ; PRNT0: POP B ;RESTORE BC POP PSW ;RESTORE STATUS WORD RET ; ; CLSCR: LXI H,CLRSC ;CLEAR SCREEN CALL PRNT RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; PRTERR ; ; PRINTS MESSAGE, BUFFER DISK, SIDE, SECTOR, AND STATUS ; ; ENTRY: A = STATUS ; BC = MESSAGE ; EXIT: NONE ; CHANGED: NONE ; PRTERR: PUSH PSW ;SAVE REGISTERS PUSH B LXI H,CRLF ;NEW LINE CALL PRNT ; POP H ;(WAS PUSHED BY BC) MESSAGE LINE CALL PRNT ; LDA BDISK ;DISK ADI 041H ;CALCULATE ASCII DISK NAME MOV C,A CALL CONOUT ; MVI C,03AH ;':' CALL CONOUT ; LXI H,TRMSG ;'TRK' CALL PRNT ; LDA BCYLIND ;TRACK NUMBER CALL AHEX ; LDA BSIDE ;SIDE CPI 0 JZ ERRS1 ; LXI H,EMS0 ;'SIDE 0' JMP ERRCOM ; ERRS1: LXI H,EMS1 ;'SIDE 1' ERRCOM: CALL PRNT ; LXI H,SECMSG ;' SECTOR ' CALL PRNT ; LDA BSECT ;SECTOR CALL AHEX ; LXI H,STMSG ;'STATUS: ' CALL PRNT ; POP PSW ;STATUS CALL AHEX ; RET ; EMS0: DB ' SIDE 0$' EMS1: DB ' SIDE 1$' TRMSG: DB ' TRK$' SECMSG: DB ' SECTOR $' CRLF: DB CR,LF,'$' STMSG: DB ' STATUS: $' ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; AHEX ; ; PRINTS REG A IN 2 HEX DIGITS ; ; ENTRY: A = VALUE TO BE PRINTED ; EXIT: NONE ; CHANGED: NONE ; AHEX: PUSH B PUSH PSW ;SAVE A RRC ;HIGH ORDER NIBBLE RRC RRC RRC CALL NIBHEX ;CONVERT TO ASCII CALL CONOUT ;PRINT IT ; POP PSW ;LOW ORDER NIBBLE CALL NIBHEX ;CONVERT TO ASCII CALL CONOUT ;PRINT IT ; POP B RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; NIBHEX ; ; CONVERTS A NIBBLE TO A HEX DIGIT ; ; ENTRY: A = VALUE WHOSE LOW 4 BITS GET CONVERTED ; EXIT: C = HEX CODE FOR LOW ORDER NIBBLE ; CHANGED: NONE ; NIBHEX: ANI 0FH ;MASK OFF LOWER NIBBLE ADI 030H ;CONVERT TO ASCII CPI 039H+1 ;IS IT A-F? JC NIB1 ;IF SO BYPASS ; ADI 07 ;CONVERT TO A-F NIB1: MOV C,A RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; CLEAR ; ; WAITS UNTIL DISK STATUS INDICATES READY ; ; ENTRY: NONE ; EXIT: NONE ; CHANGED: NONE ; CLEAR: ; ON ENTRY TO THIS COMMAND INTERRUPTS ARE EXPECTED TO BE OFF PUSH PSW ;SAVE A MVI A,FCINT ;RESET CONTROLLER CHIP (FORCED INTERRUPT) OUT COMR CALL BUSY ;WAIT TILL DONE ; POP PSW ;RESTORE A RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; BUSY - WAITS (LOOPS) UNTIL CONTROLLER IS FINISHED WITH LAST COMMAND ; ; ENTRY: NONE ; EXIT: NONE ; CHANGED: NONE ; BUSY: PUSH PSW ;SAVE REGISTERS PUSH B MVI B,10 ;SET UP TIGHT LOOP FOR WAIT (PER W D) WTLP: DCR B JNZ WTLP ; CSTAT: IN CNTS ;INPUT STATUS BYTE ANI 1 ;MASK BIT 0 JNZ CSTAT ;LOOP IF STILL BUSY ; POP B ;RESTORE REGISTERS POP PSW RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; DSKRDY ; ; WAITS UNTIL DRIVE IS READY ; ; ENTRY: NONE ; EXIT: NONE ; CHANGED: PSW ; ;DISK READY ROUTINE NOT USING READY LINE, FIVE REVOLUTIONS FOR SPIN-UP DSKRDY: IN TMRT ;GET TIMER STATUS ANI 08H ;TEST BIT 3 RZ ;RETURN IF TIMER IS STILL ON ; PUSH B ;SAVE REGISTERS MVI B,05H ;COUNT 5 INDEX PULSES DR1: IN CNTS ;START DISK AND LOOK FOR INDEX PULSE (MARK) ANI 02H ;TEST BIT 1 JZ DR1 ; DR2: IN CNTS ;NOW LOOK FOR SPACE BETWEEN HOLES ANI 02 ;TEST BIT 1 JNZ DR2 DCR B JNZ DR1 ;COUNT 5 INDEX PULSES POP B ;RESTORE REGISTERS RET ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; INITIALIZED DATA AREA ; ; CLRSC: DB LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF,LF DB LF,LF,LF,CR,'$' ; SMSG: DB CR,LF,'MAGNUM COMPUTER SYSTEMS',CR,LF,' BIOS FOR CP/M 2.2 $' SMSG1: DB 'K',CR,LF,' BIOS VERSION 2.5 ',CR,LF,LF,'$' ; NMDRVS: DB 04 ;NUMBER OF DRIVES IN SYSTEM SKCMD: DB 18H ;SEEK COMMAND RSTCD: DB 08H ;RESTORE COMMAND ; FORTY8: DB 0 ;48/96 TPI FLAG ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; DISK SETUP PARAMETER BLOCK ; ; OFFSET 1 - BOARD SETUP BYTE PRCMPE EQU 00000000B ;WRITE PRECOMP ENABLED PRCMPD EQU 10000000B ;WRITE PRECOMP DISABLED INCH8 EQU 01000000B ;8 INCH DISK DRIVE INCH5 EQU 00000000B ;5 1/4 INCH DISK DRIVE SDEN EQU 00100000B ;SINGLE DENSITY DDEN EQU 00000000B ;DOUBLE DENSITY ; DRV0 EQU 00001110B ;PHYSICAL DRIVE 0 DRV1 EQU 00001101B ;PHYSICAL DRIVE 1 DRV2 EQU 00001011B ;PHYSICAL DRIVE 2 DRV3 EQU 00000111B ;PHYSICAL DRIVE 3 ; ;OFFSET 2 - DRIVE HEAD STEP RATE ; TPI96 EQU 00000000B ;96 TPI TPI48 EQU 10000000B ;48 TPI ; RATE0 EQU 00000000B ;8" 3 MS 5" 6 MS RATE1 EQU 00000001B ;8" 6 MS 5" 12 MS RATE2 EQU 00000010B ;8" 15 MS 5" 30 MS RATE3 EQU 00000011B ;8" 30 MS 5" 60 MS ; SSIDE EQU 00000000B ;SINGLE SIDED DSIDE EQU 00000100B ;DOUBLE SIDED ; ; ;OFFSET 3 - PHYSICAL SECTOR SIZE L128 EQU 00 ;3 BITS FOR EXPANSION TO LARGE SECTORS L256 EQU 01 L512 EQU 02 L1024 EQU 03 ; ; TRKCYL EQU 00010000B ;SECTORS LABELED WITH TRACK (JADE) ; ; ; DRIVE A ------- MAGNUM 5 DSPB: DB 00 ;OLD CYLINDER DB INCH5+DDEN+DRV0 ;BOARD SETUP BYTE DB TPI48+SSIDE+RATE0 ;SINGLE/DOUBLE SIDED AND STEP RATE DB TPI48+L1024 ;DISKETTE TPI, SECTOR LENGTH ; ; DRIVE B ------- MAGNUM 5 DB 00 ;OLD CYLINDER DB INCH5+DDEN+DRV1 ;BOARD SETUP BYTE DB TPI48+SSIDE+RATE0 ;SINGLE/DOUBLE SIDED AND STEP RATE DB TPI48+L1024 ;DISKETTE TPI, SECTOR LENGTH ; ; DRIVE C ------- MAGNUM 8 DB 00 ;OLD CYLINDER DB INCH8+DDEN+DRV2 ;BOARD SETUP BYTE DB SSIDE+RATE0 ;SINGLE/DOUBLE SIDED AND STEP RATE DB L1024 ;SECTOR LENGTH ; ; DRIVE D ------- MAGNUM 8 DB 00 ;OLD CYLINDER DB INCH8+DDEN+DRV3 ;BOARD SETUP BYTE DB SSIDE+RATE0 ;SINGLE/DOUBLE SIDED AND STEP RATE DB L1024 ;SECTOR LENGTH ; ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; DISK PARAMETER HEADER MAP ; ; ; DISK A DPBAS: DW STTA ;ADDR OF SECTOR TRANSLATE (SKEW FACTOR) DW 0000H,0000H,0000H ;BDOS WORK AREA DW DIRBF ;DIRBUF - ADDR OF DIRECTORY BUFFER DW DSKA ;ADDR OF DISK PARAMTER BLOCK (DPB) DW CHKA ; CSV ; ADDR OF DIRECTORY CKECK AREA DW ALLA ; ALV ; ADDR OF ALLOCATION VECTOR AREA ; ; DISK B DW STTB ;ADDR OF SECTOR TRANSLATE (SKEW FACTOR) DW 0000H,0000H,0000H ; BDOS WORK AREA DW DIRBF ; DIRBUF ; ADDR OF DIRECTORY I/O BUFFER DW DSKB ;ADDR OF DISK PARAMTER BLOCK (DPB) DW CHKB ; CSV ; ADDR OF DIRECTORY CKECK AREA DW ALLB ; ALV ; ADDR OF ALLOCATION VECTOR AREA ; ; DISK C DW STTC ;ADDR OF SECTOR TRANSLATE (SKEW FACTOR) DW 0000H,0000H,0000H ; BDOS WORK AREA DW DIRBF ; DIRBUF ; ADDR OF DIRECTORY I/O BUFFER DW DSKC ;ADDR OF DISK PARAMTER BLOCK (DPB) DW CHKC ; CSV ; ADDR OF DIRECTORY CKECK AREA DW ALLC ; ALV ; ADDR OF ALLOCATION VECTOR AREA ; ; DISK D DW STTD ;ADDR OF SECTOR TRANSLATE (SKEW FACTOR) DW 0000H,0000H,0000H ; BDOS WORK AREA DW DIRBF ; DIRBUF ; ADDR OF DIRECTORY I/O BUFFER DW DSKD ;ADDR OF DISK PARAMTER BLOCK (DPB) DW CHKD ; CSV ; ADDR OF DIRECTORY CKECK AREA DW ALLD ; ALV ; ADDR OF ALLOCATION VECTOR AREA ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; SECTOR TRANSLATE TABLE (SKEW) ; ; ; TRANSLATE TABLE FOR MAGNUM STANDARD 5 1/4 INCH DRIVES STTA: DB 01,02,03,04,05,06,07,08 ; 1 ; 1, 2, 3, 4, 5, 6, 7, 8 DB 17,18,19,20,21,22,23,24 ; 3 ; 9,10,11,12,13,14,15,16 DB 33,34,35,36,37,38,39,40 ; 5 ; 17,18,19,20,21,22,23,24 DB 09,10,11,12,13,14,15,16 ; 2 ; 41,42,43,44,45,46,47,48 DB 25,26,27,28,29,30,31,32 ; 4 ; 49,50,51,52,53,54,55,56 DS 32 ; ; ; TRANSLATE TABLE FOR MAGNUM STANDARD 5 1/4 INCH DRIVES STTB: DB 01,02,03,04,05,06,07,08 ; 1 ; 1, 2, 3, 4, 5, 6, 7, 8 DB 17,18,19,20,21,22,23,24 ; 3 ; 9,10,11,12,13,14,15,16 DB 33,34,35,36,37,38,39,40 ; 5 ; 17,18,19,20,21,22,23,24 DB 09,10,11,12,13,14,15,16 ; 2 ; 41,42,43,44,45,46,47,48 DB 25,26,27,28,29,30,31,32 ; 4 ; 49,50,51,52,53,54,55,56 DS 32 ; ; TRANSLATE TABLE FOR MAGNUM STANDARD 8 INCH DISKETTES STTC: DB 01,02,03,04,05,06,07,08 ; 1 ; 1, 2, 3, 4, 5, 6, 7, 8 DB 17,18,19,20,21,22,23,24 ; 3 ; 9,10,11,12,13,14,15,16 DB 33,34,35,36,37,38,39,40 ; 5 ; 17,18,19,20,21,22,23,24 DB 49,50,51,52,53,54,55,56 ; 7 ; 25,26,27,28,29,30,31,32 DB 65,66,67,68,69,70,71,72 ; 9 ; 33,34,35,36,37,38,39,40 DB 09,10,11,12,13,14,15,16 ; 2 ; 41,42,43,44,45,46,47,48 DB 25,26,27,28,29,30,31,32 ; 4 ; 49,50,51,52,53,54,55,56 DB 41,42,43,44,45,46,47,48 ; 6 ; 57,58,59,60,61,62,63,64 DB 57,58,59,60,61,62,63,64 ; 8 ; 65,66,67,68,69,70,71,72 ; ; ; TRANSLATE TABLE FOR MAGNUM STANDARD 8 INCH DISKETTES STTD: DB 01,02,03,04,05,06,07,08 ; 1 ; 1, 2, 3, 4, 5, 6, 7, 8 DB 17,18,19,20,21,22,23,24 ; 3 ; 9,10,11,12,13,14,15,16 DB 33,34,35,36,37,38,39,40 ; 5 ; 17,18,19,20,21,22,23,24 DB 49,50,51,52,53,54,55,56 ; 7 ; 25,26,27,28,29,30,31,32 DB 65,66,67,68,69,70,71,72 ; 9 ; 33,34,35,36,37,38,39,40 DB 09,10,11,12,13,14,15,16 ; 2 ; 41,42,43,44,45,46,47,48 DB 25,26,27,28,29,30,31,32 ; 4 ; 49,50,51,52,53,54,55,56 DB 41,42,43,44,45,46,47,48 ; 6 ; 57,58,59,60,61,62,63,64 DB 57,58,59,60,61,62,63,64 ; 8 ; 65,66,67,68,69,70,71,72 ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; DISK PARAMTER BLOCK TABLES ; ; ; MAGNUM 5 - DSDD 5 1/4" - 48TPI 1024 BYTES/SECTOR 5 SECTORS/TRACK ; ; 2K BLOCKS, TOTAL DISK DATA CAPACITY: 390K = 195 BLOCKS ; 64 DIRECTORY ENTRY/BLOCK ( 16K/DIR ) == 25 MIN. ENTRY FOR 1 LARGE FILE ; 64 ENTRY/BL * 2BL = 128 ENTRY = 256K MAX ( ASSUMING 1 BLOCK FILES ) DSKA: DW 40 ; SPT - SECTORS PER TRACK DB 4 ; BSH - BLOCK SHIFT FACTOR DB 15 ; BLM - BLOCK MASK DB 1 ; EXM - EXTENT MASK DW 194 ; DSM - DRIVE CAPACITY: ((80-2)*5/2BLS)-1 DW 127 ; DRM - DIRECTORY SIZE: 64DIR/BL.2BL DB 0C0H,0 ; AL0/AL1 - INITIAL ALLOCATION VECTOR DW 32 ; CKS - CHECK AREA SIZE (127+1)/4 DW 2 ; OFF - RESERVED TRACKS ; ; ; MAGNUM 5 - DSDD 5 1/4" - 48TPI 1024 BYTES/SECTOR 5 SECTORS/TRACK ; ; 2K BLOCKS, TOTAL DISK DATA CAPACITY: 390K = 195 BLOCKS ; 64 DIRECTORY ENTRY/BLOCK ( 16K/DIR ) == 25 MIN. ENTRY FOR 1 LARGE FILE ; 64 ENTRY/BL * 2BL = 128 ENTRY = 256K MAX ( ASSUMING 1 BLOCK FILES ) DSKB: DW 40 ; SPT - SECTORS PER TRACK DB 4 ; BSH - BLOCK SHIFT FACTOR DB 15 ; BLM - BLOCK MASK DB 1 ; EXM - EXTENT MASK DW 194 ; DSM - DRIVE CAPACITY: ((80-2)*5/2BLS)-1 DW 127 ; DRM - DIRECTORY SIZE: 64DIR/BL.2BL DB 0C0H,0 ; AL0/AL1 - INITIAL ALLOCATION VECTOR DW 32 ; CKS - CHECK AREA SIZE (127+1)/4 DW 2 ; OFF - RESERVED TRACKS ; ; ; ; DISK DESCRIPTION FOR MAGNUM 8 DSDD DISK DRIVES ; NOTE: 2K BLOCKS, TOTAL DISK DATA CAPACITY = 152TR*9K/TR = 1368K = 684 BLOCKS ; 64 DIRECTORY ENTRY/BLOCK ( 16K/DIR ) == 86 MIN. ENTRY FOR 1 LARGE FILE ; 64 ENTRY/BL * 5BL = 320 ENTRY = 640K MAX ( ASSUMING 1 BLOCK FILES ) DSKC: DW 72 ; SPT - SECTORS PER TRACK DB 4 ; BSH - BLOCK SHIFT FACTOR DB 15 ; BLM - BLOCK MASK DB 0 ; EXM - EXTENT MASK DW 683 ;DSM - DRIVE CAPACITY ((154-2)*9/2BLS)-1 DW 319 ; DRM - DIRECTORY SIZE DB 0F8H,0 ; AL0/AL1 - INITIAL ALLOCATION VECTOR DW 80 ; CKS - CHECK AREA SIZE (319+1)/4 DW 2 ; OFF - RESERVED TRACKS ; ; ; DISK DESCRIPTION FOR MAGNUM 8 DSDD DISK DRIVES ; NOTE: 2K BLOCKS, TOTAL DISK DATA CAPACITY = 152TR*9K/TR = 1368K = 684 BLOCKS ; 64 DIRECTORY ENTRY/BLOCK ( 16K/DIR ) == 86 MIN. ENTRY FOR 1 LARGE FILE ; 64 ENTRY/BL * 5BL = 320 ENTRY = 640K MAX ( ASSUMING 1 BLOCK FILES ) DSKD: DW 72 ; SPT - SECTORS PER TRACK DB 4 ; BSH - BLOCK SHIFT FACTOR DB 15 ; BLM - BLOCK MASK DB 0 ; EXM - EXTENT MASK DW 683 ;DSM - DRIVE CAPACITY ((154-2)*9/2BLS)-1 DW 319 ; DRM - DIRECTORY SIZE DB 0F8H,0 ; AL0/AL1 - INITIAL ALLOCATION VECTOR DW 80 ; CKS - CHECK AREA SIZE (319+1)/4 DW 2 ; OFF - RESERVED TRACKS ; ; ; ; ; ; END OF FIXED TABLES ; LAST: EQU $-START ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ; ; ; UNINITIALIZED DATA AREA ; ; ; THIS IS AN UNINITIALIZED DATA AREA, AND DOES NOT NEED TO ; BE A PART OF THE SYSTEM MEMORY IMAGE STORED ON TRACK 1 SECTORS 1-4. ; WHEN PLANNING CP/M SIZE, ALLOW ENOUGH ROOM. ; BEGDAT EQU $ ; BEGINNING OF IMPURE DATA AREA ; ; VARIOUS AND SUNDRY VARIABLES ; BOOTDSK:DB 0 ; THE ASSIGNED BOOT DISK CDPB: DW 0 ;CURRENT DSPB BOOTFL: DB 0 ;COLD BOOT/WARM BOOT FLAG TEMP: DW 0 ;STATUS ERRST: DB 0 ;STATUS ; DMAAD: DW 0 ;DMA ADDRESS SET BY SETDMA ; ;VARIABLES FOR DRIVE, HEAD PLACEMENT, SECTOR AND DEBLOCKING DISKNO: DW 0 ;CURRENT DISK PER SETDSK ; TRACK: DW 0 ;USEFUL FOR SECTORS LABELED WITH TRACK NOT CYLINDER CYLIND: DW 0 ;ACTUAL PHYSICAL CYLINDER PER SETTRK SIDE: DW 0 ;SIDE PER SETTRK ; DSECT: DW 0 ;DESTINATION PHYSICAL SECTOR NUMBER SECTOR: DW 0 ;LOGICAL RECORD (128 BYTE SECTOR) NUMBER PER SETSEC OFFSET: DW 0 ;OFFSET INTO PHYSICAL RECORD BUFFER ; ;BUFFERED SECTOR VARIABLES BDISK: DW 0 ;DISK OF CURRENT BUFFERED SECTOR ; BCYLIND:DW 0 ;CYLINDER OF CURRENT BUFFERED SECTOR BSIDE: DW 0 ;SIDE OF CURRENT BUFFERED SECTOR ; BSECT: DW 0 ;CURRENT PHYSICAL SECTOR IN BUFFER ; ;1K SECTOR BUFFER AREA BUFST: DB 0 ;BUFFER STATUS BUFFER: DS 1024 ;BUFFER FOR LARGEST POSSIBLE PHYSICAL SECTOR ; DIRBF: DS 128 ;SCRATCH DIRECTORY AREA ; ;ALLOCATION VECTOR - SIZE IS DSM/8+1 ALLA: DS 100 ;ALLOCATION VECTOR - LARGE ENOUGH FOR 793 BLOCKS ALLB: DS 100 ;ALLOCATION VECTOR ALLC: DS 100 ;ALLOCATION VECTOR ALLD: DS 100 ;ALLOCATION VECTOR ; ;DIRECTORY CHECK INFORMATION - SIZE IS CKS (OF DPBM) OR (DRM+1)/4 CHKA: DS 100 ;CHECK VECTOR - LARGE ENOUGH FOR 400 DIRECTORY ENTRIES CHKB: DS 100 ;CHECK VECTOR CHKC: DS 100 ;CHECK VECTOR CHKD: DS 100 ;CHECK VECTOR ; ; END ;