TITLE 'BIOS - NORTH STAR DD CP/M 3.0 OF 29 AUG 97' ; This is a CP/M 3.0 bios for the North Star double density ; controller in a non banked environment. ; ; The present plan is to boot CP/M 3 using an existing ; version of CP/M 2.2 patched to autoload CPM3.COM on bootup. ; ; Later versions will incorporate a loaderbios version for ; direct booting and the Morrow 8 inch disk board perhaps ; using a 1.2 or 1.44 meg drive for IBM compatability. ; ; These routines copyright (c) 1980, 1981, 1982 by Steve Bogolub, ; 2338 S. Scoville Ave., Berwyn, IL 60402. ; (The Jade routines will be replaced with Morrow) ; Jade Double D (tm) ; disk handlers contributed to the public domain for use on Jade ; equipment by special permission of Jade Computer Products. ; This software may be used freely for non-commercial purposes ; only, and may not be sold. ; ; THIS BIOS CONTAINS ROUTINES TO SUPPORT THE ; FOLLOWING HARDWARE: ; ; DISK: NORTH STAR MDS-AD2 DOUBLE DENSITY 5.25" ; FLOPPY DISK UNITS 1 AND 2 AS CP/M DRIVES ; A: AND B: ; ; JADE DOUBLE D REV C 8" FLOPPY DISK UNITS ; 0 AND 1 AS CP/M DRIVES C: AND D: ; ; SERIAL I/O: HORIZON LEFT (LOW) SERIAL I/O PORT AS ; CP/M DEVICE CRT: ; ; ; ; THE GENNED-IN CONSOLE IS DETERMINED BY SOLICITING ; A SPACE CODE (20H) FROM CRT:, TTY:, AND UC1:. IF ; NO SPACE CODE IS RECEIVED AFTER ABOUT EIGHT SECONDS ; (AT 4 MHZ), CRT: IS ASSUMED TO BE THE CONSOLE. IF ; A SPACE IS READ FROM ONE OF THE DEVICES, THAT DEVICE ; IS ASSUMED TO BE THE CONSOLE. ; ; SINCE THIS BIOS IS SO LARGE, MOVCPM SHOULD BE ; RUN FOR TWO LESS THAN THE DESIRED SYSTEM SIZE ; IN K, I.E. SPECIFY 30 FOR A 32K SYSTEM. ; ; *** IMPORTANT BOOTSTRAP INFO *** ; ; THIS BIOS IS INTENDED TO RUN IN THE LAST ; 3.5K OF MEMORY. THE LAST .5K IS SET ASIDE ; FOR A NORTH STAR SECTOR DEBLOCKING BUFFER. ; THE FIRST 3K IS GENNED-IN BIOS CODE, AND ; IS EXPECTED TO RESIDE ON TRACK 0 OF NORTH ; STAR DISK UNIT 1 (A:) IN SECTORS 5-9, AND ; 4. THE NORTH STAR BOOT PROM READS IN SECTOR ; 4 INTO CONSECUTIVE PAGES OF MEMORY, STARTING ; WITH THE PAGE NUMBER SPECIFIED BY THE FIRST ; BYTE OF SECTOR DATA, THEN JUMPS TO THAT ; ADDRESS + 10 (0AH). THIS BIOS IS SET UP TO ; USE THAT METHOD TO COLD BOOT ITSELF. CODE ; AT THAT ADDRESS READS THE LAST FIVE SECTORS ; OF TRACK ZERO INTO MEMORY AT ADDRESS "BIOS", ; THEN JUMPS TO THE BIOS COLD START ADDRESS. ; THE BIOS COLD BOOT EXPECTS THE JADE DOUBLE D ; CONTROL CODE ("NDCM") TO RESIDE ON SECTORS ; ONE AND TWO OF TRACK ZERO, AND LOADS THOSE ; SECTORS FROM THE DISK INTO THE JADE DD MEMORY, ; THEN RESETS AND STARTS UP THE JADE DD RESIDENT ; Z80. THE BIOS WARM BOOT EXPECTS THE CCP/BDOS ; CODE TO RESIDE ON TRACKS 0-9 OF TRACK ONE ; (IN OTHER WORDS, THE WHOLE TRACK), AND THE ; LAST SECTOR IS EXPECTED TO BE ON TRACK ZERO, ; SECTOR 3. TRACK ZERO, SECTOR ZERO IS RESERVED ; FOR LIFEBOAT-COMPATIBLE ID INFO AND FUTURE ; ADDITIONS. THE MODIFIED VERSION OF SYSGEN ; NAMED "NSGEN" IS SET UP TO TRANSFER CP/M TO ; AND FROM DISK IN THIS REQUIRED MANNER. ; ; WE USE THE Z80 INSTRUCTION "LD A,I" ON ENTRY ; TO THE DISK READ AND WRITE ROUTINES TO GET ; THE STATUS OF THE INTERRUPT FLIP/FLOP, SINCE ; WE MUST DISABLE INTERRUPTS WHILE THE NORTH ; STAR DISK READS OR WRITES ARE PERFORMED. ; USING THE Z80 STATUS, WE CAN RE-ENABLE ; INTERRUPTS AFTER WE LEAVE. THIS CHECK IS ; DONE BY THE ROUTINES "INTDI" AND "INDEN", ; AND CAN EASILY BE REMOVED IF WE EVER GO ; TO A NON-Z80 CPU (NEVER, I HOPE). ; ; ; ; CONSOLE DEFINITIONS ; MOTHR EQU 000H ;HORIZON MOTHERBOARD BASE CRT EQU MOTHR+2 ;HORIZON LEFT SERIAL BASE ; ; ************************************************************* * * * BIOS AND LOADER BIOS FOR CP/M 3.0 (BETA V1.2) FOR DJ2D * * CONTROLLER. * * WRITTEN NOVEMBER 1982 BY DAVE HARDY AND KEN JACKSON * * * ************************************************************* TITLE 'BIOS AND LOADER BIOS FOR CP/M 3.0' ************************************************************* * * * TO INSTALL THIS BIOS INTO CP/M 3.0, PERFORM THE FOLLOWING * * STEPS: * * 1. CONSOLE AND PRINTER I/O ARE SET UP FOR A * * NORTH STAR MOTHERBOARD * * 2. ADD ANY INITIALIZATION THAT YOU NEED AT TINIT: * * 3. SET THE LDRBIOS EQUATE IN THIS FILE TO TRUE * * 4. RMAC SCB (ASSEMBLE SCB.ASM, SUPPLIED) * * 5. RMAC BIOS3 (ASSEMBLE LDRBIOS) * * 6. REN LDRBIOS.REL=BIOS3.REL * * 7. SET THE LDRBIOS EQUATE IN THIS FILE FALSE * * 8. RMAC BIOS3 (ASSEMBLE BIOS) * * 9. LINK BIOS3[B]=BIOS3,SCB * * 10. GENCPM * * (ANSWER ALL QUESTIONS WITH A CARRIAGE RETURN * * EXCEPT ANSSWER "N" AT "BANK SWITCHED MEMORY?" * * QUESTION, AND ANSWER WITH YOUR TOP PAGE OF * * MEMORY WHEN ASKED "TOP PAGE OF MEMORY?") * * 11. LINK CPMLDR[L100]=CPMLDR,LDRBIOS * * 12. CPMLDR (LOAD AND RUN CP/M 3.0) * * * ************************************************************* FALSE EQU 0 ;DEFINE TRUE AND FALSE TRUE EQU NOT FALSE ************************************************************* * * * THE FOLLOWING REVISION NUMBER IS IN REFERENCE TO THE CP/M * * 3.0 CBIOS. * * * ************************************************************* REVNUM EQU 10 ;BIOS REVISION NUMBER CPMREV EQU 30 ;CP/M REVISION NUMBER ************************************************************* * * * THESE ARE THE ROUTINES CALLED FROM THE DJ2D'S BUILT-IN * * EPROM. (MODEL B ONLY) * * * ************************************************************* ORIGIN EQU 0E000H ;EPROM ORIGIN OF YOUR DJ2D BOARD DJRAM EQU ORIGIN+400H ;RAM ADDRESS DJHOME EQU DJRAM+9H ;DJ2D TRACK ZERO SEEK DJTRK EQU DJRAM+0CH ;DJ2D TRACK SEEK ROUTINE DJSEC EQU DJRAM+0FH ;DJ2D SET SECTOR ROUTINE DJDMA EQU DJRAM+012H ;SET DMA ADDRESS DJREAD EQU DJRAM+15H ;READ ROUTINE DJWRITE EQU DJRAM+18H ;WRITE ROUTINE DJSEL EQU DJRAM+1BH ;DJ2D SELECT DRIVE ROUTINE DJSTAT EQU DJRAM+27H ;STATUS ROUTINE DJSIDE EQU DJRAM+30H ;SET SIDE ROUTINE ************************************************************* * * * MISCELLANEOUS INTERNAL BIOS EQUATES. * * WE'VE TRIED TO MAINTAIN COMPATIBILITY WITH THE MORROW'S * * DJ2D BIOS. * * * ************************************************************* LDRBIOS EQU FALSE ;TRUE IF YOU WANT TO ASSEMBLE AS LOADER BIOS CDISK EQU 4 ;ADDRESS OF LAST LOGGED DISK BUFF EQU 80H ;DEFAULT BUFFER ADDRESS TPA EQU 100H ;TRANSIENT MEMORY ENTRY EQU 5 ;BDOS ENTRY JUMP ADDRESS RETRIES EQU 10 ;MAX RETRIES ON DISK I/O BEFORE ERROR ACR EQU 0DH ;CARRIAGE RETURN ALF EQU 0AH ;A LINE FEED SPACE EQU 20H ;ASCII SPACE MAXDISK EQU 4 ;MAX OF DISK DRIVES CLEAR EQU 1AH ;CLEAR SCREEN CODE FOR LDRBIOS LDAI EQU 057EDH ;Z80 "LD A,I" BYTE-SWAPPED ; FOR "DW" USE ; ; DISK OPERATING SYSTEM ADDRESSES ; NKSYS EQU 52 ;SYS SIZE IN K BYTES KBYTE EQU 1024 ;1K BYTE SIZE CPMSZ EQU NKSYS*KBYTE ;TOP SYSTEM ADDRESS CPMBS EQU CPMSZ-(22*KBYTE);CP/M BIAS VALUE CCP EQU CPMBS+3400H ;ADDRESS OF CCP BDOS EQU CPMBS+3C00H ;ADDRESS OF BDOS BIOS EQU CPMBS+4A00H ;ADDRESS OF BIOS BIOSR EQU 1F80H-BIOS+400H ;DDT LOAD OFFSET ;(LEAVES ROOM FOR NDCM) DEFDSK EQU 0004H ;DEFAULT DISK FOR CCP SECSZ EQU 128 ;BYTES PER SECTOR HSTSIZ EQU 512 ;BYTES PER N* SECTOR ; ; BDOS CONSTANTS ON ENTRY TO WRITE ; WRALL EQU 0 ;WRITE TO ALLOCATED WRDIR EQU 1 ;WRITE TO DIRECTORY WRUAL EQU 2 ;WRITE TO UNALLOCATED ; ; NORTH STAR MEMORY MAPPED I/O ADDRESSES ; CBOOT EQU 0E800H ;COLD BOOT ROM ADDRESS WDATA EQU 0E900H ;WRITE DATA. DATA IS ; LOW 8 ADRESS BITS. CORDER EQU 0EA00H ;CONTROLLER ORDER CCMND EQU 0EB00H ;CONTROLLER COMMAND ************************************************************* * * * PUBLIC AND EXTERNAL DECLARATIONS REQUIRED FOR CP/M PLUS. * * * ************************************************************* CSEG PUBLIC ?BOOT,?WBOOT,?CONST,?CONIN,?CONO,?LIST,?AUXO,?AUXI PUBLIC ?HOME,?SLDSK,?STTRK,?STSEC,?STDMA,?READ,?WRITE PUBLIC ?LISTS,?SCTRN PUBLIC ?CONOS,?AUXIS,?AUXOS,?DVTAB,?DEVIN,?DRTBL,?MLTIO,?FLUSH PUBLIC ?MOV,?TIM,?BNKSL,?STBNK,?XMOV IF NOT LDRBIOS PUBLIC ?INIT,?LDCCP EXTRN @CIVEC,@COVEC,@AIVEC,@AOVEC,@LOVEC,@MXTPA ENDIF ;NOT LDRBIOS ************************************************************* * * * THE BIOS JUMP TABLE * * * * THE JUMP TABLE BELOW MUST REMAIN IN THE SAME ORDER, THE * * ROUTINES MAY BE CHANGED, BUT THE FUNCTION EXECUTED MUST BE* * THE SAME. THERE ARE 33 JUMPS IN THE CP/M PLUS BIOS VECTOR* * * ************************************************************* ; ?BOOT: JMP CBOOT ;COLD START ENTRY POINT WBOOTE: ?WBOOT: JMP WBOOT ;WARM START ENTRY POINT ?CONST: JMP CONST ;CONSOLE STATUS A=FF=READY ?CONIN: JMP CONIN ;CONSOLE INPUT DATA IN A COUT: ?CONO: JMP CONOUT ;CONSOLE OUTPUT DATA IN C ?LIST: JMP LIST ;LIST DEVICE DATA IN C ?AUXO: JMP AUXOUT ;PUNCH DEVICE NONE ?AUXI: JMP AUXIN ; READER DEVICE NONE ?HOME JMP HOME ;SEEK HOME TRACK ?SLDSK: JMP SETDRV ;SELECT DISK DISK IN C ?STTRK: JMP SETTRK ;SEEK TRACK TRACK IN BC ?STSEC: JMP SETSEC ;SET SECTOR SECTOR IN BC ?STDMA: JMP SETDMA ;SET DMA DMA IN BC ?READ: JMP READ ;READ SECTOR ?WRITE: JMP WRITE ;WRITE SECTOR ?LISTS: JMP LISTST ;RETURN LIST STATUS A=FF=READY ?SCTRN: JMP SECTRAN ;SECTOR TRANSLATE SECTOR IN BC ?CONOS: JMP CONOST ; OUTPUT STATUS OF CONSOLE ?AUXIS: JMP AUXIST ; INPUT STATUS OF AUX. PORT ?AUXOS: JMP AUXOST ; OUTPUT STATUS OF AUX. PORT ?DVTAB: JMP DEVTBL ; ADDRESS OF CHAR. I/O TABLE ?DEVIN: JMP DEVINI ;INITIALIZE CHAR. I/O DEVICES ?DRTBL: JMP DRVTBL ; ADDRESS OF DISK DRIVE TABLE ?MLTIO: JMP MULTIO ;SET NUMBER OF LOGICALLY CONSECUITIVE ;SECTORS TO BE READ OR WRITTEN ?FLUSH: JMP FLUSH ;FORCE PHYSICAL BUFFER FLUSHING FOR ;USER-SUPPORTED DEBLOCKING ?MOV: JMP MOVE ;MEMORY MOVE FOR LARGE MEMORY COPY ?TIM: JMP ?TIME ;GET THE TIME ?BNKSL: JMP SELMEM ;SELECT ALTERNATE BANK OF MEMORY ?STBNK: JMP SETBNK ;SELECT BANK FOR DMA OPERATION ?XMOV: JMP XMOVE ;SET BANK WHEN A BUFFER IS IN A BANK ; THAN 0 OR 1 DJDRV JMP DJSEL ;HOOK FOR SINGLE.COM PROGRAM ;RESERVED FOR SYSTEM IMPLEMENTOR JMP RESERV1 ;RESERVED FOR CP/M PLUS JMP RESERV2 ;RESERVED FOR CP/M PLUS ; ; DEVICE TABLE IS NOT IMPLEMENTED, SO RETURN HL=0 DEVTBL: LXI H,0 RET ; ; FLUSH ROUTINE IS NOT IMPLEMENTED, SO RETURN A=0 FLUSH: XRA A RET ; ; DRIVE TABLE IS NOT USED, SO RETURN HL=0FFFEH DRVTBL: LXI H,0FFFEH RET ; ; THE FOLLOWING JUMPS FROM THE BIOS JUMP VECTOR ; ARE NOT IMPLEMENTED: IF LDRBIOS AUXIST: AUXOUT: AUXIN: AUXOST: LIST: LISTST ENDIF ;LDRBIOS DEVINI: MULTIO: XMOVE: SELMEM: SETBNK: RESERV1: RESERV2: ?TIME: RET ************************************************************* * * * MOVER MOVES 128 BYTES OF DATA. SOURCE POINTER IN DE, DEST * * POINTER IN HL. * * * ************************************************************* MOVER LXI B,128 ;LENGTH OF TRANSFER ************************************************************* * * * GENERAL PURPOSE MEMORY MOVE SUBROUTINE. * * MOVES BC BYTES FROM DE TO HL * * * ************************************************************* MOVE: LDAX D MOV M,A INX D INX H DCR C JNZ MOVE MOV A,B ORA C RZ DCR B JMP MOVE ; ; BLOCK - BLOCK MOVE (Z80 LDIR REGISTER USAGE) ; BLOCK: MOV A,M ;GET BYTE STAX D ;STORE IT INX H ;BOP PTRS INX D DCX B ;COUNT OFF BYTE MOV A,B ;CHECK FOR DONE ORA C JNZ BLOCK ;GO BACK IF NOT RET ; ;******************************************************** ; NORTH STAR STUFF FROM HERE DOWN ;******************************************************** ; ; INIT - COLD START ENTRY ** DIRECTORY BUFFER OVERLAY ** ; DIRBUF EQU $ ;BUFFER BEGINNING ; ; SCRATCH RAM FOR BDOS OVERLAY ; D0ALL EQU DIRBUF+SECSZ ;OVERLAY ALLOCATE AND CHECK D0CHK EQU D0ALL+23 ; BUFFERS HERE TOO D1ALL EQU D0CHK+16 D1CHK EQU D1ALL+23 D2ALL EQU D1CHK+16 ;NOTE THAT THE JADE DISKS D2CHK EQU D2ALL+150 ; (C: AND D:) MAY NEED D3ALL EQU D2CHK+64 ; MUCH MORE ALLOC AND D3CHK EQU D3ALL+150 ; CHECK SPACE THAN N* ENDOV EQU D3CHK+64 ;END OF OVERLAY AREA ; ; THE INIT ROUTINE IS ACTUALLY A CONTINUATION OF THE ; COLD BOOT BEGUN DOWN AT "BOOT". ; INIT: LXI SP,HSTBUF+HSTSIZ ;SET SP TO SCRATCH AREA LXI H,CCP ;WHERE TO START CP/M PUSH H XRA A ;INIT HORIZON MOTHERBOARD OUT MOTHR+6 STA COLDB ;BIOS NOW IN MEMORY CALL DELAY ;DELAY FOR 8251'S MVI A,0AEH ;INIT SERIAL PORTS OUT CRT+1 ;OUTPUT DUMMY MODE TO INSURE CALL DELAY MVI A,040H ; CMD EXPECTED, THEN OUTPUT OUT CRT+1 ; RESET CMD CALL DELAY MVI A,04EH ;MODE: 1 STOP BIT, 16X CLK, OUT CRT+1 ; 8 DATA BITS, NO PARITY CALL DELAY MVI A,037H ;CMD: RTS, ER, RXEN, DTR, TXEN OUT CRT+1 CALL DELAY IN CRT ;FLUSH RECEIVER INPUTS LXI H,MSGSO ;SIGN-ON MSG ADDRESS CALL MSGOT ;ISSUE MESSAGE ; ; JMP CPMLD ;GO PERFORM WARM BOOT FUNCS ; ; THIS DELAY SUBROUTINE IS USED TO HELP US OUT ON ; TIMING WHEN RESETTING THE 8251 CONSOLE SERIAL DEVICE. ; DELAY: LXI B,600H DEL5: DCX B MOV A,B ORA C JNZ DEL5 RET ; MSGSO: DB ACR,ALF,'North Star / ' DB 'Disk Jockey 2D/B ' DB (NKSYS/10)+'0',(NKSYS MOD 10)+'0' DB 'K CP/M 2.2 of 02/21/82',ACR,ALF+80H ; IF ($-ENDOV) SHR 15 ORG ENDOV ;FILL OUT OVERLAY SIZE ENDIF ; ; SELECT DRIVE - LOGON ; SETDRV: LXI H,0 ;ERROR RETURN CODE MOV A,C ;PUT DRIVE # IN A CPI MAXDISK ;CHECK IF LEGAL DRIVE RNC ;NO CARRY IF ILLEGAL STA SEKDSK ;STORE DRIVE NUMBER MOV B,E ;SAVE LOGON REQ REG MOV L,C ;L = DISK NUMBER MVI H,0 ;ZERO H REG DAD H ; *2 DAD H ; *4 DAD H ; *8 DAD H ; *16 (SIZE OF HEADER) LXI D,D0DPH ;DRIVE 0 DPH DAD D ;HL = DRIVE N DPH SHLD DTPTR ;STORE DRIVE TBL PTR ; ; LOG-ON - SET DISK PARAMETER BLOCK ; ; -- CHECK IF LOG-ON REQUESTED ; XRA A STA LOGFLG ;ASSUME NO JADE LOGON MOV A,B ;CHECK LOG REQUEST ANI 001H ;LOG ON BIT TEST JNZ NOLOG ;PASS IF NO REQUEST CALL HFLUSH ;MAKE SURE HOST BUF JNZ LOGERR ; AVAILABLE, OUT ON ERR ; ; SEE IF DISK IS JADE OR NORTH STAR. ; LDA SEKDSK ;GET DISK # CPI 2 JNC LOGDJ2D ;IF DISK JOCKEY, GO ELSEWHERE ; ; LOG ON NORTH STAR BY READING ID SECTOR, THEN DECIDE ; WHICH TABLE TO USE BASED ON SINGLE OR DOUBLE DENSITY. ; IF DOUBLE DENSITY, LOOK FOR LIFEBOAT 2.X FLAG BYTE ; AT OFFSET 05CH IN THE SECTOR, AND USE LIFEBOAT 2.X ; DPB IF THAT BYTE CONTAINS 0B0H. IF NOT, ASSUME OUR ; NORMAL LIFEBOAT 1.4-COMPATIBLE DPB FOR DOUBLE DENSITY. ; STA HSTDSK ;GOING TO ACCESS THIS DISK XRA A STA HSTTRK ;TRACK ZERO STA HSTSEC ;N* SECTOR ZERO CALL INTDI ;INTERRUPTS OFF CALL READHST ;READ THE SECTOR CALL INTEN ;INTERRUPTS RESTORED LDA ERFLAG ;CHECK FOR READ ERROR ORA A JNZ LOGERR ;LOG-ON ERROR IF SO LDA NSDENS ;IF OK, GET DENSITY FLAG LXI B,TRAN5S ;ASSUME SINGLE DENSITY, LXI D,DPBNSS ; EVEN THO USUALLY WRONG ORA A ;CHECK JNZ LOGNSD ;GO ON IF RIGHT LXI B,TRAN5D ;DOUBLE DENS, COMMON XLATE LXI D,DPBNSD ; BUT ASSUME OUR 1.4 DPB LDA HSTBUF+05CH ;GET LIFEBOAT FLAG BYTE CPI 0B0H ;IS IT LIFEBOAT 2.X FLAG? JNZ LOGNSD ;KEEP OUR DPB IF NOT LXI D,DPBNSL ;GO TO LIFEBOAT 2.X IF NOT ; LOGNSD: LHLD DTPTR ;LOAD DRIVE TBL PTR MOV M,C ;SET TRANSLATE TABLE ADDR INX H MOV M,B LXI B,9 ;PT TO DPB ADDR DAD B MOV M,E ;SET DPB ADDR INX H MOV M,D JMP NOLOG ;GO COMPLETE LOGON NOW ; ; SET UP DEBLOCKING VARIABLES FROM DPB VALUES ; NOLOG: CALL DPBAD ;GET DPB ADDR XCHG ; IN HL MOV A,M ;SET UP DEBLOCK STA CPMSPT ; SECTORS PER TRACK INX H ;GET TO GROUP MASK INX H INX H MOV A,M ;GET IT INR A ;CALC # BLOCKS/GROUP STA UNAVAL ; AND SAVE THAT LXI D,12 DAD D ;PT TO SECTOR SHIFT MOV A,M ; BIT FLAG ORA A ;HAVE WE GOT ONE? JZ NOSHF ;PASS IF NOT MVI B,0FFH ;INIT SHIFT COUNT ; CALCSH: INR B ;COUNT UP A SHIFT RAR ;SEE IF DONE JNC CALCSH ;GO BACK IF NOT YET MOV A,B ;SHIFT COUNT TO ACC ; NOSHF: STA SECSHF ;STORE SHIFT COUNT MOV A,M ;RELOAD BIT FLAG DCR A ;FORM SECTOR MASK STA SECMSK ; AND SET IT LHLD DTPTR ;RELOAD PTR LDA LOGFLG ;WAS JADE LOGGED ON?++++++++++++++++++++ ORA A ;FLAG NON-ZERO IF SO, JNZ DSKOK ; GO HANDLE DCM MORE RET ;IF NOT, DONE, RET ZERO ; ; -- ASSUME 3740 DISKETTE ; LG3740: CALL TR3740 ;SET SECTOR TRANSLATE CALL DPBAD ;SET REGISTER DE LXI B,DPBSZ ;DPB SIZE IN BYTES LXI H,DPB8 ;ADDRESS OF BLK IMAGE CALL BLOCK ;MOVE INTO DPB JMP NOLOG ;GO SET UP (CLEAR) THE ; DEBLOCK VARIABLES ; ; -- SET 3740 SECTOR TRANSLATION ; TR3740: LXI D,TRAN8 ;SECTOR TRAN TBL ADDR ; TRCOM: LHLD DTPTR ;ADDR DISK PARA HDER MOV M,E INX H MOV M,D RET ; ; -- SET 1024 BYTES/SECTOR TRANSLATION ; TR1024: LXI D,TRN124 ;SECTOR TRAN TBL ADDR JMP TRCOM ;GO SET IT ; ; -- SET NO SECTOR TRANSLATION ; TRNONE: XRA A ;ZERO A REG LHLD DTPTR MOV M,A INX H MOV M,A RET ; ; -- GET DRIVE PARA BLK ADDR ; DPBAD: LHLD DTPTR ;ADDR DISK PARA HDED LXI D,10 ;DPB TBL PNTR OFFSET DAD D ;NOW AT DPB PNTR MOV E,M ;LOAD INTO DE INX H MOV D,M RET ;RETURN TO LOG USER ************************************************************* * * * HOME IS TRANSLATED INTO A SEEK TO TRACK ZERO. * * * ************************************************************* HOME MVI C,0 ;TRACK TO SEEK TO LDA HSTWRT ;CHECK FOR PENDING WRITE ORA A JNZ SETTRK STA HSTACT ;CLEAR HOST ACTIVE IF NOT ************************************************************* * * * SETTRK SAVES THE TRACK # TO SEEK TO. NOTHING IS DONE AT * * THIS POINT, EVERYTHING IS DEFFERED UNTIL A READ OR WRITE. * * * ************************************************************* SETTRK MOV A,C ;A <- TRACK # STA CPMTRK ;CP/M TRACK # RET ************************************************************* * * * SETSEC JUST SAVES THE DESIRED SECTOR TO SEEK TO UNTIL AN * * ACTUAL READ OR WRITE IS ATTEMPTED. * * * ************************************************************* SETSEC MOV A,C ;SAVE THE SECTOR NUMBER STA CPMSEC ;CP/M SECTOR # RET ************************************************************* * * * SETDMA SAVES THE DMA ADDRESS FOR THE DATA TRANSFER. * * * ************************************************************* SETDMA MOV H,B ;HL <- BC MOV L,C SHLD CPMDMA ;CP/M DMA ADDRESS RET ; ; SECTOR TRANSLATION+++++++++++++++++++++++++++++++++++++++++++++++++ ; SECTRAN: MOV A,E ;IS THERE A TABLE? ORA D JZ JTRAN ;JADE SPECIAL XLATE IF NOT XCHG ;MAP OFF TABLE IF SO DAD B MOV L,M MVI H,0 RET ; JTRAN: MOV H,B ;JADE XLATE OFF BY ONE MOV L,C ; SO FIX FOR CALLER INX H RET ; THEN DONE ************************************************************* * * * TERMINAL DRIVER SUBROUTINES. IOBYTE IS NOT USED. * * NOTE THAT THE CONSOLE DEVICE IS NOT THE DJ2D MEMORY * * MAPPED SERIAL I/O PORT. THE NORTHSTAR SERIAL PORT IS * * USED INSTEAD. * * * ************************************************************* ;I/O ROUTINES FOR NORTHSTAR MOTHERBOARD ************************************************************* * * * LEFT SERIAL PORT ROUTINES. CONSOLE I/O * * * ************************************************************* ************************************************************* * * * LEFT SERIAL PORT ROUTINES. CONSOLE INPUT * * * ************************************************************* CONIN: ;READ A CHARACTER IN 03H ANI 02H JZ CONIN ;WAIT TILL A CHARACTER IS ; READY IN 02H ;GET THE CHARACTER ANI 7FH ;STRIP PARITY RET ************************************************************* * * * LEFT SERIAL PORT ROUTINES. CONSOLE OUTPUT * * * ************************************************************* CONOUT: ;WRITE A CHARACTER IN 03H ANI 01H JZ CONOUT ;WAIT TILL THE BUFFER IS ; EMPTY MOV A,C ;WRITE THE CHARACTER OUT 02H RET ************************************************************* * * * LEFT SERIAL PORT ROUTINES. CONSOLE INPUT STATUS * * * ************************************************************* CONST: ;RETURN INPUT BUFFER STATUS IN 03H ANI 02H RZ ;RETURN NOT READY MVI A,0FFH RET ;THERE IS A CHARACTER READY ************************************************************* * * * LEFT SERIAL PORT ROUTINES. CONSOLE OUT STATUS * * * ************************************************************* CONOST: ;RETURN OUTPUT BUFFER STATUS IN 03H ANI 01H RZ ;RETURN NOT READY MVI A,0FFH RET ;RETURN READY IF NOT LDRBIOS ************************************************************* * * * RIGHT SERIAL PORT ROUTINES. RIGHT INPUT * * * ************************************************************* AUXIN: ;READ A CHARACTER IN 05H ANI 02H JZ AUXIN ;WAIT TILL A CHARACTER IS ; READY IN 04H ;GET THE CHARACTER ANI 7FH ;STRIP PARITY RET ************************************************************* * * * RIGHT SERIAL PORT ROUTINES. RIGHT OUTPUT * * * ************************************************************* AUXOUT: ;WRITE A CHARACTER IN 05H ANI 01H JZ AUXOUT ;WAIT TILL THE BUFFER IS ; EMPTY MOV A,C ;WRITE THE CHARACTER OUT 04H RET ************************************************************* * * * RIGHT SERIAL PORT ROUTINES. RIGHT INPUT STATUS * * * ************************************************************* AUXIST: ;RETURN INPUT BUFFER STATUS IN 05H ANI 02H RZ ;RETURN NOT READY MVI A,0FFH RET ;THERE IS A CHARACTER READY ************************************************************* * * * RIGHT SERIAL PORT ROUTINES. RIGHT OUT STATUS * * * ************************************************************* AUXOST: ;RETURN OUTPUT BUFFER STATUS IN 05H ANI 01H RZ ;RETURN NOT READY MVI A,0FFH RET ;RETURN READY ************************************************************* * * * PARALLEL PORT ROUTINES. PARALLEL INPUT * * * ************************************************************* PARIN: ;READ A CHARACTER IN 06H ANI 01H JZ PARIN ;WAIT TILL A CHARACTER IS ; READY IN 00H ;GET THE CHARACTER PUSH PSW MVI A,30H ;RESET THE PARALLEL INPUT ; FLAG OUT 06H POP PSW ANI 7FH ;STRIP PARITY RET ************************************************************* * * * PARALLEL PORT ROUTINES. PRINTER OUTPUT * * * ************************************************************* LIST: ;WRITE A CHARACTER IN 06H ANI 02H JZ LIST ;WAIT TILL THE BUFFER IS ; EMPTY MVI A,20H ;RESET THE PARALLEL OUTPUT ; FLAG OUT 06H MOV A,C ;WRITE THE CHARACTER, STROBE ; BIT 7 NSPOUT: ORI 80H OUT 00H ANI 7FH OUT 00H ORI 80H OUT 00H RET ************************************************************* * * * PARALLEL PORT ROUTINES. INPUT STATUS * * * ************************************************************* PINPST: ;RETURN INPUT BUFFER STATUS IN 06H ANI 01H RZ ;RETURN NOT READY MVI A,0FFH RET ;RETURN READY ************************************************************* * * * PARALLEL PORT ROUTINES. LIST DEVICE STATUS * * * ************************************************************* LISTST: ;RETURN OUTPUT BUFFER STATUS IN 06H ANI 02H RZ ;RETURN NOT READY MVI A,0FFH RET ;RETURN READY ENDIF ;NOT LDRBIOS ; ; HXBOT DISPLAYS HEXIDECIMAL EQUIV OF ACC CONTENTS. ; HXBOT: PUSH PSW ;SAVE CHAR RRC ;SWAP NIBBLES RRC RRC RRC CALL HXNOT ;OUTPUT HIGH NIBBLE POP PSW ; THEN LOW NIBBLE HXNOT: ANI 0FH ;STRIP HIGH NIBBLE ADI 90H ;CVT TO ASCII DECIMAL DAA ACI 40H DAA MOV C,A ;CHAR TO C JMP CONOUT ;THRU VECTOR TO CONOUT ; ; DEBLOCKING DISK WRITE ; WRITE: CALL INTDI ;MASK INTERRUPTS CALL DSKWR ;DO THE WRITE JMP INTEN ;GO RESTORE INTS ; ; DEBLOCKING DISK READ. NOTE THAT ON DEBLOCKING READ ; AND WRITE, THE CALLER SECTOR NUMBERS RANGE FROM 1-XX ; DECIMAL. THIS IS FOR COMPATIBILITY WITH 8" FORMATS ; THAT ARE 1-ORIGIN. WE ADJUST FOR THIS THROUGHOUT THE ; DEBLOCKING ROUTINES BY SUBTRACTING 1 FROM CPMSEC ; BEFORE WE USE IT. VARIABLES TO CONTROL DEBLOCKING ; ARE SET UP FOR US WHEN DISK IS SELECTED. ; READ: CALL INTDI ;DISABLE INTERRUPTS CALL DSKRD ;DO THE I/O ; INTEN: PUSH PSW ;SAVE DISK I/O ERROR CODE LHLD ENTPSW ;GET ENTRY PSW TO TEST PUSH H POP PSW JPO INTEN5 ;PASS IF INTS OFF WHEN ENTERED EI ; ELSE RE-ENABLE INTS ; INTEN5: POP PSW ;RESTORE DISK I/O ERROR CODE RET ; THEN RETURN TO CALLER ; INTDI: MVI A,7FH ;CHECK FOR RUNNING ON INR A ; 8080 OR Z80 JPO NOTZ80 ;CAN'T GET INT STATE ON 8080 DW LDAI ;GET INT STATE INTO PUSH PSW ; PARITY FLAG, THEN POP H ; SAVE PSW IN MEMORY SHLD ENTPSW ; NOTZ80: DI ;ALLOW NO INTERRUPTS RET ; DURING THE I/O XFER ; DSKRD: LDA SECSHF ;SEE IF DEBLOCKING ORA A JZ DJRD ;MUST BE JADE IF NOT LDA SEKDSK ;IF SO, SEE IF JADE ANYWAY CPI 2 JC NOTJR ;PASS IF NOT, N* READ LDA CPMTRK ;IF SO, IS TRACK 0 OR 1? CPI 2 JC DJRD ;NORMAL SECTOR SIZE IF SO ; NOTJR: MVI A,WRUAL STA WRTYPE ;TREAT AS UNALLOC STA READOP ;READ OPERATION JMP ALLOC ;GO END UNALLOC SECTORS ; AND FORCE READ ; DSKWR: LDA SECSHF ;SEE IF DEBLOCKING ORA A JZ DJWR ;MUST BE JADE IF NOT LDA SEKDSK ;IF SO, SEE IF JADE ANYWAY CPI 2 JC NOTJW ;PASS IF NOT, N* WRITE LDA CPMTRK ;IF SO, IS TRACK 0 OR 1? CPI 2 JC DJWR ;NORMAL SECTOR SIZE IF SO ; NOTJW: XRA A STA READOP ;NOT A READ OPERATION MOV A,C ;WRITE TYPE IN C STA WRTYPE CPI WRUAL ;WRITE UNALLOCATED? JNZ CHKUNA ;CHECK FOR UNALLOC ; ; WRITE TO UNALLOCATED, SET PARAMETERS ; LDA UNAVAL ;NEXT UNALLOC RECS STA UNACNT LHLD SEKDSK ;PICK UP SEKDSK AND CPMTRK SHLD UNADSK ;UNADSK=SEKDSK, UNATRK=CPMTRK LDA CPMSEC STA UNASEC ;UNASEC = CPMSEC ; ; CHECK FOR WRITE TO UNALLOCATED SECTOR ; CHKUNA: LDA UNACNT ;ANY UNALLOC REMAIN? ORA A JZ ALLOC ;SKIP IF NOT ; ; MORE UNALLOCATED RECORDS REMAIN ; DCR A ;UNACNT = UNACNT - 1 STA UNACNT LDA SEKDSK ;SAME DISK? LXI H,UNADSK CMP M ;SEKDSK = UNADSK? JNZ ALLOC ;SKIP IF NOT ; ; DISKS ARE THE SAME, CHECK TRACKS ; LDA CPMTRK LXI H,UNATRK CMP M ;CPMTRK = UNATRK? JNZ ALLOC ;SKIP IF NOT ; ; TRACKS ARE THE SAME, CHECK SECTORS ; LDA CPMSEC LXI H,UNASEC CMP M ;CPMSEC = UNASEC? JNZ ALLOC ;SKIP IF NOT ; ; MATCH, MOVE TO NEXT SECTOR FOR FUTURE REF ; INR M ;UNASEC = UNASEC+1 LDA CPMSPT ;CHECK FOR END OF TRACK CMP M JNC NOOVF ;SKIP IF STILL ON TRACK ; ; OVERFLOW TO NEXT TRACK ; MVI M,1 ;UNASEC = 1 LXI H,UNATRK INR M ;UNATRK = UNATRK+1 ; ; MATCH FOUND, MARK AS UNNECESSARY READ ; NOOVF: XRA A STA RSFLAG ;RSFLAG = 0 JMP RWOPER ;GO DO WRITE ; ; NOT AN UNALLOCATED RECORD, REQUIRES PRE-READ ; ALLOC: XRA A STA UNACNT ;UNACNT = 0 INR A STA RSFLAG ;RSFLAG = 1 ; ; COMMON CODE FOR READ AND WRITE FOLLOWS ; RWOPER: XRA A STA ERFLAG ;NO ERRORS (YET) LDA SECSHF ;GET SECTOR SHIFT COUNT MOV B,A ; IN COUNT REG LDA CPMSEC ;COMPUTE HOST SECTOR DCR A ;ADJUST FOR 1-ORIGIN ; RWOPSH: ORA A ;CARRY = 0 RAR ;SHIFT RIGHT DCR B ;COUNT OFF A SHIFT JNZ RWOPSH ;LOOP IF MORE STA SEKHST ;HOST SECTOR TO SEEK ; ; ACTIVE HOST SECTOR? ; LXI H,HSTACT ;HOST ACTIVE FLAG MOV A,M MVI M,1 ;ALWAYS BECOMES 1 ORA A ;WAS IT ALREADY? JZ FILHST ;FILL HOST IF NOT ; ; HOST BUFFER ACTIVE, SAME AS SEEK BUFFER? ; LDA SEKDSK LXI H,HSTDSK ;SAME DISK? CMP M ;SEKDSK = HSTDSK? JNZ NOMATCH ; ; SAME DISK, CHECK TRACK ; LDA CPMTRK LXI H,HSTTRK CMP M ;CPMTRK = HSTTRK? JNZ NOMATCH ; ; SAME DISK AND TRACK, CHECK SECTOR ; LDA SEKHST LXI H,HSTSEC CMP M ;SEKHST = HSTSEC? JZ MATCH ;SKIP IF MATCH ; ; MUST FLUSH HOST BUFFER FOR NEW SECTOR ; NOMATCH: LDA HSTWRT ;HOST WRITTEN? ORA A CNZ WRITEHST ;CLEAR HOST BUFFER LDA ERFLAG ;CHECK FOR ERROR ORA A RNZ ;RETURN ERROR IF SO ; FILHST: LHLD SEKDSK ;MAY HAVE TO FILL HOST BUFFER SHLD HSTDSK ;HSTDSK=SEKDSK,HSTTRK=CPMTRK LDA SEKHST STA HSTSEC XRA A STA HSTWRT ;NO PENDING WRITE LDA RSFLAG ;NEED TO READ? ORA A JZ MATCH ;NO IF FLAG ZERO LDA HSTDSK ;SEE WHICH DISK CPI 2 ;IF C: OR D:, JADE JNC NOTNSR ;BRANCH IF JADE CALL READHST ;IF A: OR B:, READ N* LDA ERFLAG ;CHECK FOR ERRORS ORA A RNZ ;NO MORE IF SO CALL GNSDEN ;CHECK DENSITY LXI H,NSDENS CMP M ;IS DENSITY RIGHT? JZ MATCH ;OK IF SO LXI H,SDEMSG ;ERROR IF NOT CALL DSKERR ;REPORT IT MVI A,5 STA ERFLAG RET ;RET NZ ACC TO CALLER ; NOTNSR: CALL JHREAD ;READ JADE DISK LDA ERFLAG ;READ ERROR? ORA A RNZ ;LEAVE BUF ALONE IF SO ; ; COPY DATA TO OR FROM BUFFER ; MATCH: LDA SECMSK ;GET MASK MOV H,A ; INTO TEMP REG LDA CPMSEC ;MASK SECTOR BUFFER NUMBER DCR A ;ADJUST FOR 1-ORIGIN ANA H ;LEAST SIGNIF BITS RAR ;GET VALUE SHIFTED MOV H,A ; LEFT 7 IN HL MVI A,0 RAR MOV L,A ; ; HL CONTAINS RELATIVE HOST BUFFER ADDRESS ; LXI D,HSTBUF ;ASSUME USING N* BUFFER LDA HSTDSK ;CHECK DISK SELECTED CPI 2 JC NJBUF ;RIGHT IF NOT JADE DISK MVI A,DCMB1 ;USING JADE BUFFER, OUT DPORT ; SWITCH BANK ONE IN XCHG ;PUT OFFSET IN DE NOW LHLD DADDR ;PT HL AT BUFFER ; NJBUF: DAD D ;HL = HOST ADDRESS XCHG ;NOW IN DE LHLD CPMDMA ;GET/PUT CP/M DATA MVI C,SECSZ ;LENGTH OF MOVE LDA READOP ;WHICH WAY? ORA A JNZ RWMOVE ;SKIP IF READ ; ; WRITE OPERATION, MARK AND SWITCH DIRECTION ; INR A ;ACC KNOWN ZERO ABOVE STA HSTWRT ;HSTWRT = 1 XCHG ;SOURCE/DEST SWAP ; RWMOVE: LDAX D ;SOURCE CHARACTER INX D MOV M,A ;TO DEST INX H DCR C ;LOOP 128 TIMES JNZ RWMOVE LDA HSTDSK ;IS THIS JADE DISK? CPI 2 CNC DSKOUT ;FIX MEM STATUS IF SO ; ; DATA HAS BEEN MOVED TO/FROM HOST BUFFER ; LDA WRTYPE ;WRITE TYPE CPI WRDIR ;TO DIRECTORY? MVI A,0 ;NO ERROR AT THIS PT RNZ ;RET IF NOT DIR WRITE ; ; CLEAR HOST BUFFER FOR DIRECTORY WRITE ; CALL WRITEHST LDA ERFLAG RET ; ; WRITEHST PERFORMS THE PHYSICAL WRITE TO THE ; NORTH STAR DISK. ON ENTRY, DRIVE IS IN HSTDSK, ; TRACK IS IN HSTTRK, SECTOR IS IN HSTSEC. ON ; EXIT, ERROR FLAG IS IN ERFLAG (ZERO IF NONE). ; ; IT IS ASSUMED INTERRUPTS ARE DISABLED AT ; THIS POINT. IF NOT, I/O MAY BE DISRUPTED. ; WRITEHST: ;WRITE HOST XRA A ;BUFFER WILL BE CLEARED STA HSTWRT LDA HSTDSK ;SEE IF N* DISK SELECTED CPI 2 JNC JHWRIT ;IF NOT, DO JADE WRITE CALL GNSDEN ;GET DENSITY BASED ON ID STA NSCNT ;SET WRITE BYTE COUNT CALL SETUP ;SELECT DRIVE AND ; SEEK TO TRACK LDA ERFLAG ;CHECK FOR ERRORS ORA A RNZ ;INDEX PULSE NOT FOUND IS FATAL CALL POSEC ;POSITION TO SECTOR JNZ SNFERR ;OUT ON ERROR LDA CCMND+20H ;GET B-STATUS ANI 02H ;IS DISK WRITE-PROTECTED? MVI A,6 ;ASSUME SO, ERROR CODE 6 STA ERFLAG JNZ WPERR ;WRITE ALWAYS FAILS IF SO LHLD HSTADR ;GET ADDRESS TO WRITE FROM MVI B,31 ;ASSUME DOUBLE DENSITY MVI E,2 LDA NSCNT ;CHECK MOV C,A ;SAVE COUNT FOR LATER ORA A JZ WRIT5 ;GO ON IF COUNTS RIGHT MVI B,15 ;CORRECT FOR SINGLE DENS DCR E ; WRIT5: LDA CCMND+16H ;INITIATE SECTOR WRITE ; WRIT10: LDA CCMND+15H ;KEEP MOTORS RUNNING, GET A-STAT ANI 08H ;MUST LOOP UNTIL 96 USEC WINDOW JNZ WRIT10 ; PAST, SO LOOP WHILE WI TRUE ; ; NOW WRITE THE 31 OR 15 BYTES OF LEADING ZEROES ON THE SECTOR ; WRIT15: LDA WDATA+00H ;WRITE A BYTE OF ZEROES NOP ;KILL TIME MVI D,WDATA SHR 8 ;KILL TIME BY LOADING D FOR LATER DCR B ;COUNT OFF A ZERO BYTE JNZ WRIT15 ;DO THEM ALL ; ; FOLLOW WITH ONE OR TWO SYNCH BYTES ; WRIT17: LDA WDATA+0FBH ;WRITE A SYNCH BYTE DCR E ;CHECK FOR 2ND NEEDED JNZ WRIT17 ;GO BACK IF SO ; ; NOW WRITE OUT 256 OR 512 BYTES. DO THIS TWO AT A ; TIME SO WE CAN USE A SINGLE PRECISION COUNTER. B IS ; ZERO FROM ABOVE TO INIT THE CRC BYTE. ; WRIT20: MOV A,M ;GET NEXT BYTE TO OUTPUT MOV E,A ; IN OUTPUT REG XRA B ;ADD INTO CHECKSUM RLC MOV B,A ;LEAVE CHECKSUM IN B LDAX D ;WRITE DATA BYTE TO DISK INX H ;BOP BUF PTR MOV A,M ;REPEAT FOR NEXT BYTE MOV E,A XRA B RLC MOV B,A LDAX D INX H DCR C ;COUNT OFF LAST PAIR OF BYTES JNZ WRIT20 ;GO BACK IF MORE TO WRITE MOV E,B ;IF NOT, TIME TO WRITE CHECKSUM INX B ;KILL TIME LDAX D ; THEN WRITE THE BYTE XRA A ;DONE, INDICATE NO ERROR STA ERFLAG RET ;RETURN TO CALLER ; WPERR: LXI H,WPEMSG ;WRITE PROTECT ERROR JMP DSKERR ;TELL OPERATOR ON WAY OUT ; ; GNSDEN IS CALLED BY N* I/O ROUTINES TO DETERMINE THE ; DENSITY OF THE CURRENT BLOCK BASED ON THE DENSITY OF ; THE ID BLOCK. THAT IS DETERMINED BY TAKING ADVANTAGE ; OF THE FACT THAT THE HOST DISK HAS NO TRANSLATE TABLE ; IF SINGLE DENSITY. ; GNSDEN: LXI H,D0DPH ;ASSUME A: LDA HSTDSK ;NOW CHECK ORA A JZ GNSDA ;GO ON IF SO LXI H,D1DPH ;B: IF NOT GNSDA: MOV A,M ;SEE IF GOT XLATE TABLE INX H ORA M ;IF NOT, SINGLE DENSITY MVI A,80H ;ASSUME SINGLE RZ ;DONE IF RIGHT XRA A ;CORRECT IF DOUBLE DENSITY RET ************************************************************* * * * DISK JOCKY 2D/B READ AND WRITE ROUTINES * * * * WRITE ROUTINE MOVES DATA FROM MEMORY INTO THE BUFFER. IF * * THE DESIRED CP/M SECTOR IS NOT CONTAINED IN THE DISK * * BUFFER, THE BUFFER IS FIRST FLUSHED TO THE DISK IF IT HAS * * EVER BEEN WRITTEN INTO, THEN A READ IS PERFORMED INTO THE * * BUFFER TO GET THE DESIRED SECTOR. ONCE THE CORRECT SECTOR * * IS IN MEMORY, THE BUFFER WRITTEN INDICATOR IS SET, SO THE * * BUFFER WILL BE FLUSHED, THEN THE DATA IS TRANSFERRED INTO * * THE BUFFER. * * * ************************************************************* DJWR MOV A,C ;SAVE WRITE COMMAND TYPE STA WRITTYP MVI A,1 ;SET WRITE COMMAND DB (MVI) OR (B*8) ;THIS "MVI B" INSTRUCTION ; CAUSES THE FOLLOWING ; "XRA A" TO BE SKIPPED OVER. ************************************************************* * * * READ ROUTINE TO BUFFER DATA FROM THE DISK. IF THE SECTOR * * REQUESTED FROM CP/M IS IN THE BUFFER, THEN THE DATA IS * * SIMPLY TRANSFERRED FROM THE BUFFER TO THE DESIRED DMA * * ADDRESS. IF THE BUFFER DOES NOT CONTAIN THE DESIRED * * SECTOR, THE BUFFER IS FLUSHED TO THE DISK IF IT HAS EVER * * BEEN WRITTEN INTO, THEN FILLED WITH THE SECTOR FROM THE * * DISK THAT CONTAINS THE DESIRED CP/M SECTOR. * * * ************************************************************* DJRD XRA A ;SET THE COMMAND TYPE TO READ STA RDWR ;SAVE COMMAND TYPE ************************************************************* * * * REDWRT CALCULATES THE PHYSICAL SECTOR ON THE DISK THAT * * CONTAINS THE DESIRED CP/M SECTOR, THEN CHECKS IF IT IS * * THE SECTOR CURRENTLY IN THE BUFFER. IF NO MATCH IS MADE, * * THE BUFFER IS FLUSHED IF NECESSARY AND THE CORRECT SECTOR * * READ FROM THE DISK. * * * ************************************************************* REDWRT MVI B,0 ;THE 0 IS MODIFIED TO CONTAIN SECSIZ EQU $-1 ; THE LOG2 OF THE PHYSICAL ; SECTOR SIZE/128 ON THE ; CURRENTLY SELECTED DISK. LDA CPMSEC ;GET THE DESIRED CP/M SECTOR # PUSH PSW ;TEMPORARY SAVE ANI 80H ;SAVE ONLY THE SIDE BIT MOV C,A ;REMEMBER THE SIDE POP PSW ;GET THE SECTOR BACK ANI 7FH ;FORGET THE SIDE BIT DCR A ;TEMPORARY ADJUSTMENT DIVLOOP DCR B ;UPDATE REPEAT COUNT JZ DIVDONE ORA A ;CLEAR THE CARRY FLAG RAR ;DIVIDE THE CP/M SECTOR # BY ; THE SIZE OF THE PHYSICAL ; SECTORS JMP DIVLOOP ; DIVDONE INR A ORA C ;RESTORE THE SIDE BIT STA TRUESEC ;SAVE THE PHYSICAL SECTOR ; NUMBER LXI H,CPMDRV ;POINTER TO DESIRED DRIVE, ; AND SECTOR LXI D,BUFDRV ;POINTER TO BUFFER DRIVE, ; TRACK AND SECTOR MVI B,4 ;COUNT LOOP DTSLOP DCR B ;TEST IF DONE WITH COMPARE JZ SECMOV ;YES, MATCH. GO MOVE THE DATA LDAX D ;GET A BYTE TO COMPARE CMP M ;TEST FOR MATCH INX H ;BUMP POINTERS TO NEXT DATA ; ITEM INX D JZ DTSLOP ;MATCH, CONTINUE TESTING ************************************************************* * * * IF DRIVE, TRACK, AND SECTOR DON'T MATCH, THEN FLUSH THE * * BUFFER IF NECESSARY AND THEN REFILL. * * * ************************************************************* CALL FILL ;FILL THE BUFFER WITH CORRECT ; PHYSICAL SECTOR RC ;NO GOOD, RETURN WITH ERROR ; INDICATION ************************************************************* * * * SECMOV HAS BEEN MODIFIED TO CAUSE EITHER A TRANSFER INTO * * OR OUT OF THE BUFFER. * * * ************************************************************* SECMOV LDA CPMSEC ;GET THE CP/M SECTOR TO ; TRANSFER DCR A ;ADJUST TO PROPER SECTOR IN ; BUFFER ANI 0 ;STRIP OFF HIGH ORDERED BITS SECPSEC EQU $-1 ;THE 0 IS MODIFIED TO ; REPRESENT THE # OF ; CP/M SECTORS PER PHYSICAL ; SECTOR MOV L,A ;PUT INTO HL MVI H,0 DAD H ;FORM OFFSET INTO BUFFER DAD H DAD H DAD H DAD H DAD H DAD H LXI D,BUFFER ;BEGINNING ADDRESS OF BUFFER DAD D ;FORM BEGINNING ADDRESS OF ; SECTOR TO TRANSFER XCHG ;DE = ADDRESS IN BUFFER LXI H,0 ;GET DMA ADDRESS, THE 0 IS ; MODIFIED TO ; CONTAIN THE DMA ADDRESS CPMDMA EQU $-2 MVI A,0 ;THE ZERO GETS MODIFIED TO ; CONTAIN A ZERO IF A READ, ; OR A 1 IF WRITE RDWR EQU $-1 ANA A ;TEST WHICH KIND OF OPERATION JNZ INTO ;TRANSFER DATA INTO THE BUFFER OUTOF CALL MOVER XRA A RET INTO XCHG ; CALL MOVER ;MOVE THE DATA, HL = DESTINATION ; DE = SOURCE MVI A,1 STA BUFWRTN ;SET BUFFER WRITTEN INTO FLAG MVI A,0 ;CHECK FOR DIRECTORY WRITE WRITTYP EQU $-1 DCR A MVI A,0 STA WRITTYP ;SET NO DIRECTORY WRITE RNZ ;NO ERROR EXIT ************************************************************* * * * FLUSHA WRITES THE CONTENTS OF THE BUFFER OUT TO THE DISK * * IF IT HAS EVER BEEN WRITTEN INTO. * * * ************************************************************* FLUSHA MVI A,0 ;THE 0 IS MODIFIED TO REFLECT ; IF THE BUFFER HAS BEEN ; WRITTEN INTO BUFWRTN EQU $-1 ANA A ;TEST IF WRITTEN INTO RZ ;NOT WRITTEN, ALL DONE LXI H,DJWRITE ;WRITE OPERATION ************************************************************* * * * PREP PREPARES TO READ/WRITE THE DISK. RETRIES ARE * * ATTEMPTED.UPON ENTRY, H&L MUST CONTAIN THE READ OR WRITE * * OPERATION ADDRESS. * * * ************************************************************* PREP XRA A ;RESET BUFFER WRITTEN FLAG STA BUFWRTN SHLD RETRYOP ;SET UP THE READ/WRITE ; OPERATION MVI B,RETRIES ;MAXIMUM NUMBER OF RETRIES ; TO ATTEMPT RETRYLP PUSH B ;SAVE THE RETRY COUNT LDA BUFDRV ;GET DRIVE NUMBER INVOLVED ; IN THE OPERATION MOV C,A CALL DJDRV ;SELECT THE DRIVE LDA BUFTRK ANA A ;TEST FOR TRACK ZERO MOV C,A PUSH B CZ DJHOME ;HOME THE DRIVE IF TRACK 0 POP B ;RESTORE TRACK # CALL DJTRK ;SEEK TO PROPER TRACK LDA BUFSEC ;GET SECTOR INVOLVED ; IN OPERATION PUSH PSW ;SAVE THE SECTOR # RLC ;BIT 0 OF A EQUALS SIDE # ANI 1 ;STRIP OFF UNNECESSARY BITS MOV C,A ;C <- SIDE # CALL DJSIDE ;SELECT THE SIDE POP PSW ;A <- SECTOR # ANI 7FH ;STRIP OFF SIDE BIT MOV C,A ;C <- SECTOR # CALL DJSEC ;SET THE SECTOR TO TRANSFER LXI B,BUFFER ;SET THE DMA ADDRESS CALL DJDMA CALL DJREAD ;THE READ OPERATION IS ; MODIFIED TO WRITE RETRYOP EQU $-2 POP B ;RESTORE THE RETRY COUNTER MVI A,0 ;NO ERROR EXIT STATUS RNC ;RETURN NO ERROR DCR B ;UPDATE THE RETRY COUNTER STC ;ASSUME RETRY COUNT EXPIRED MVI A,0FFH ;ERROR RETURN RZ JMP RETRYLP ;TRY AGAIN ************************************************************* * * * FILL FILLS THE BUFFER WITH A NEW SECTOR FROM THE DISK. * * * ************************************************************* FILL CALL FLUSHA ;FLUSH BUFFER FIRST RC ;CHECK FOR ERROR LXI D,CPMDRV ;UPDATE THE DRIVE, TRACK, ; AND SECTOR LXI H,BUFDRV MVI B,3 ;NUMBER OF BYTES TO MOVE CALL MOVE ;COPY THE DATA LXI H,DJREAD JMP PREP ;SELECT DRIVE, TRACK, AND ; SECTOR. THEN READ THE ; ; ; HERE TO REPORT DISK NOT READY. TELL CONSOLE WHICH ; DISK IT WAS, THEN SOLICIT REPLY. IF CTRL-C, WARM ; BOOT TO A:, ELSE RETURN TO CALLER. ; NOTRDY: LDA SEKDSK ;STUFF DISK ADI 'A' STA NRD ; INTO MSG LXI H,NRDMSG CALL MSGOT ;REPORT TO OPERATOR CALL CONIN ;GET REPLY SUI 3 ;IS ANSWER CTRL-C? RNZ ;RETURN TO CALLER IF NOT STA DEFDSK ;SELECT A: IF SO, ; THEN WARM BOOT IT ; ; WARM BOOT ENTRY. LOAD CCP/BDOS AND INITIALIZE ; WBOOT: DI ;NO PROCESSOR INTS DURING BOOT LDA DEFDSK ;GET CURRENT DEFAULT DISK MOV B,A ;SAVE IT ANI 0F0H ;GET USER # MOV C,A ;SAVE THAT MOV A,B ANI 00FH ;ISOLATE DISK # CPI MAXDISK ;IS IT LEGAL? JC WRMOK ;GO ON IF SO XRA A ;BACK TO DRIVE ZERO IF NOT MOV C,A ;USER # PROB BAD TOO WRMOK: ORA C ;COMBINE WITH USER # STA DFIMG ;PUT TO BASE PAGE IMAGE LXI SP,HSTBUF+HSTSIZ ;SET SP TO SCRATCH RAM LXI H,CCP+3 ;CP/M WARM START ADDR PUSH H ; ; MERGE HERE FROM COLD BOOT ; CPMLD: LXI B,8 ;MOVE ZERO PAGE STUFF LXI D,0 ; DOWN TO ZERO LXI H,BSIMG CALL BLOCK LXI H,05959H ;FORCE HOME OF N* DRIVES SHLD NSTRK ; A, B MOV A,H ;MAKE SURE NEW DISK SELECTED STA CURDSK XRA A ;DRIVE ZERO VALUE STA HSTDSK STA HSTACT ;HOST BUFFER INACTIVE STA HSTWRT ;NO HOST WRITE PENDING STA UNACNT ;CLEAR UNALLOC COUNT LXI H,CCP ;CP/M CCP ADDRESS SHLD HSTADR ;READ INTO THERE INR A ;GET 1 IN ACC STA HSTTRK ;READ FROM TRACK ONE CALL WSETUP ;KICK MOTORS AND SEEK TRK XRA A ;SECTOR ZERO ; ; READ ALL TEN SECTORS FROM TRACK ONE THEN ONE SECTOR ; FROM TRACK ZERO (SECTOR 3). ; WREAD: STA HSTSEC ;SET CURRENT SECTOR TO READ CALL WRMRD ;READ SECTOR AND CHK STATUS LXI D,HSTSIZ ;SECTOR SIZE LHLD HSTADR ;CALC NEW ADDRESS DAD D SHLD HSTADR LDA HSTSEC ;BOP SECTOR # INR A CPI 10 ;OFF END OF TRACK ONE? JNZ WREAD ;GO GET NEXT SECTOR IF NOT XRA A ;TO TRACK ZERO, STA HSTTRK CALL WSETUP MVI A,3 ; SECTOR 3 IF SO STA HSTSEC CALL WRMRD ;READ THE LAST SECTOR LXI H,HSTBUF ;NOW READ AND WRITE SHLD HSTADR ; USING DEBLOCK BUFFER LDA DFIMG ;RETRIEVE LAST USED DRIVE MOV C,A ; FOR BDOS RET ; THEN GO TO CP/M ; WSETUP: CALL SETUP ;KICK MOTORS AND SEEK TRK JMP WECHK ; WRMRD: CALL READNS ;READ HOST SECTOR WECHK: LDA ERFLAG ;CHECK FOR ERROR ORA A RZ ;RETURN IF NONE LXI H,MSGLE ;GET ERROR MESSAGE CALL MSGOT ;TYPE IT HLT ; THEN GIVE UP ; ; MSGOT DISPLAYS STRING OF CHARS PT'ED AT BY HL ON ; CONSOLE, UNTIL CHAR WITH PARITY BIT SET IS OUTPUT. ; MSGOT: PUSH PSW ;SAVE CALLER FLAGS MSGL: MOV C,M ;LOAD CHAR PUSH H ;SAVE HL CALL CONOUT ;OUTPUT CHAR IN C POP H ;RESTORE HL MOV A,M ;GET CHAR BACK TO LOOK AT INX H ;LEAVE PTR ON NEXT CHAR RAL ;IS HIGH BIT ON? JNC MSGL ;GO BACK IF NOT POP PSW ; ELSE RESTORE FLAGS RET ; AND RETURN ; ; DISK ERROR MESSAGES ; WPEMSG: DB 'Protec','t'+80H SDEMSG: DB 'Densit','y'+80H RERMSG: DB 'ACR','C'+80H SYEMSG: DB 'Syn','c'+80H NIPMSG: DB 'Inde','x'+80H SNFMSG: DB 'Secto','r'+80H JIOMSG: DB ACR,ALF,'Jade DD',' '+80H ; ERRMSG: DB ' err ' ASCDSK: DB ' : trk',' '+80H SECMSG: DB ' sec',' '+80H NRDMSG: DB ACR,ALF,'Disk ' NRD: DB ' : not ready',' '+80H CRLF: DB ACR,ALF+80H ; MSGLE: DB ACR,ALF,'Boot er','r'+80H ; ; JADE ID LABEL DEFINITIONS ; JADEID: DB 'Jade DD ' ;ID LABEL IDSZE EQU $-JADEID ;LABEL SIZE ; ; NORTH STAR DD SECTOR TRANSLATE TABLE. AFTER ; DEBLOCKING, WORKS OUT TO SKEW FACTOR OF 5. ; TRAN5D: DB 01,02,03,04 DB 21,22,23,24 DB 05,06,07,08 DB 25,26,27,28 DB 09,10,11,12 DB 29,30,31,32 DB 13,14,15,16 DB 33,34,35,36 DB 17,18,19,20 DB 37,38,39,40 ; ; NORTH STAR DD DISK PARAMETER BLOCK. THIS IS OUR ; NORMAL DPB, AND IS COMPATIBLE WITH LIFEBOAT CP/M 1.4 ; DISKS. ; DPBNSD: DW 40 ;SECTORS PER TRACK DB 3 ;BLOCK SHIFT FACTOR DB 07H ;BLOCK MASK DB 0 ;EXM MASK DW 165-1 ;DISK SIZE - 1 DW 63 ;DIRECTORY MAX DB 11000000B ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;CHECK SIZE DW 2 ;TRACK OFFSET ; ; THE NEXT BYTE IS ONE WE HAVE ADDED SPECIFICALLY ; FOR THIS BIOS TO CONVENIENCE OUR DEBLOCKING ROUTINES. ; IT IS A SECTOR SHIFT MASK, AND EACH DISK PARAMETER ; BLOCK HAS ONE IN THIS POSITION. THE ALLOWABLE VALUES ; ARE AS FOLLOWS: ; ; 1000B ;1024 BYTES/SECTOR ; 0100B ; 512 BYTES/SECTOR ; 0010B ; 256 BYTES/SECTOR ; 0000B ; 128 BYTES/SECTOR ; ; FOR THE NORTH STAR DD DISKS, 512 IS HARD-CODED. FOR ; THE NORTH STAR SD DISKS, 256 IS HARD-CODED. FOR ; JADE DISKS, THE VALUE IS READ IN FROM THE ID SECTOR. ; IF THE ID LOOKS BOGUS, THE STANDARD 8" DPB IS USED, ; WHICH HAS 128 CANNED-IN. ; DB 0100B ;512 BYTES/SECTOR ; ; NORTH STAR DD DISK PARAMETER BLOCK, SET UP ; FOR COMPATIBILITY WITH LIFEBOAT CP/M 2.X ; FORMAT DISKS. ; DPBNSL: DW 40 ;SECTORS PER TRACK DB 4 ;BLOCK SHIFT FACTOR DB 0FH ;BLOCK MASK DB 1 ;EXM MASK DW 82-1 ;DISK SIZE - 1 DW 63 ;DIRECTORY MAX DB 10000000B ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;CHECK SIZE DW 2 ;TRACK OFFSET DB 0100B ;512 BYTES/SECTOR ; ; THERE IS NO NORTH STAR SINGLE DENSITY TRANSLATE ; TABLE. ; TRAN5S: EQU 0 ;TELL SECTRAN TO JUST ADD 1 ; ; NORTH STAR SD DISK PARAMETER BLOCK ; DPBNSS: DW 20 ;SECTORS PER TRACK DB 3 ;BLOCK SHIFT FACTOR DB 07H ;BLOCK MASK DB 0 ;EXM MASK DW 80-1 ;DISK SIZE - 1 DW 63 ;DIRECTORY MAX DB 11000000B ;ALLOC 0 DB 0 ;ALLOC 1 DW 16 ;CHECK SIZE DW 3 ;TRACK OFFSET DB 0010B ;256 BYTES/SECTOR ; ; STANDARD 8" SECTOR TRANSLATE TABLE ; TRAN8: DB 1,7,13,19,25,5,11,17,23 DB 3,9,15,21,2,8,14,20,26 DB 6,12,18,24,4,10,16,22 ; ; STANDARD 8" DISK PARAMETER BLOCK ; DPB8: DW 26 DB 3 DB 7 DB 0 DW 242 DW 63 DB 0C0H DB 0 DW 16 DW 2 ; DB 0000B ;128 BYTES/SECTOR ; ; 1024 BYTES/SECTOR TRANSLATE TABLE ; TRN124: DB 1,2,3,4,5,6,7,8 DB 25,26,27,28,29,30,31,32 DB 49,50,51,52,53,54,55,56 DB 9,10,11,12,13,14,15,16 DB 33,34,35,36,37,38,39,40 DB 57,58,59,60,61,62,63,64 DB 17,18,19,20,21,22,23,24 DB 41,42,43,44,45,46,47,48 ; ; DRIVE PARAMETER HEADER AREA ; ; DRIVES A: AND B: ARE NORTH STAR 5" ; D0DPH: DW 0 ;SECTOR TRAN TBL SET BY SETDRV DW 0 ;SCRATCH DW 0 ;SCRATCH DW 0 ;SCRATCH DW DIRBUF ;DIRECTORY BUFFER DW 0 ;DRIVE PARAM BLK SET BY SETDRV DW D0CHK ;DRIVE CHANGE BLK DW D0ALL ;DRIVE ALLOCATION ; D1DPH: DW 0 ;SECTOR TRAN TBL SET BY SETDRV DW 0 ;SCRATCH DW 0 ;SCRATCH DW 0 ;SCRATCH DW DIRBUF ;DIRECTORY BUFFER DW 0 ;DRIVE PARAM BLK SET BY SETDRV DW D1CHK ;DRIVE CHANGE BLK DW D1ALL ;DRIVE ALLOCATION ; ; ; DRIVES C: AND D: ARE JADE 8" SHUGART ; D2DPH: DW 0 ;SECTOR TRAN TBL SET BY SETDRV DW 0 ;SCRATCH DW 0 ;SCRATCH DW 0 ;SCRATCH DW DIRBUF ;DIRECTORY BUFFER DW D2DPB ;DRIVE PARAM BLK SET BY SETDRV DW D2CHK ;DRIVE CHANGE BLK DW D2ALL ;DRIVE ALLOCATION ; ; D3DPH: DW 0 ;SECTOR TRAN TBL SET BY SETDRV DW 0 ;SCRATCH DW 0 ;SCRATCH DW 0 ;SCRATCH DW DIRBUF ;DIRECTORY BUFFER DW D3DPB ;DRIVE PARAM BLK SET BY SETDRV DW D3CHK ;DRIVE CHANGE BLK DW D3ALL ;DRIVE ALLOCATION ; ; ; ZERO PAGE IMAGE -- BLOCK MOVED TO BASE PAGE ; BSIMG: JMP BIOS+03H ;WARM BOOT VECTOR IOIMG: DS 1 ;IOBYTE NOT USED DFIMG: DB 0 ;DEFAULT DISK -- ZERO ; AFTER COLD BOOT JMP BDOS+06H ;BDOS CALL VECTOR ; ; BIOS VARIABLE STORAGE ; SEKDSK: DB 0 ;DRIVE NUMBER CPMTRK: DS 1 ;TRACK NUMBER (MUST IMM FOLLOW ; SEKDSK FOR LHLD) CPMSEC: DS 1 ;SECTOR NUMBER SEKHST: DS 1 ;SEEK SHR SECSHF HSTACT: DS 1 ;HOST ACTIVE FLAG HSTWRT: DS 1 ;HOST WRITTEN FLAG DTPTR: DW 0 ;DRIVE TABLE PTR LOGFLG: DB 0 ;NON-ZERO IF SETDRV ; LOGGED ON JADE DISK ; UNACNT: DS 1 ;UNALLOC REC CNT UNADSK: DS 1 ;LAST UNALLOC DISK UNATRK: DS 1 ;LAST UNALLOC TRACK (MUST IMM ; FOLLOW UNADSK FOR LHLD) UNASEC: DS 1 ;LAST UNALLOC SECTOR ; ; DEBLOCKING INFO ABOUT THE CURRENTLY-SELECTED DISK ; UNAVAL: DS 1 ;# UNALLOC RECS/GROUP CPMSPT: DS 1 ;# CP/M SECTORS/TRACK SECSHF: DS 1 ;SECTOR SHIFT COUNT, ; LOG2 (# CP/M SECTORS/HOST BLOCK) SECMSK: DS 1 ;SECTOR MASK, # CP/M ; SECTORS/HOST BLOCK - 1 ; ; ; RESERVE DRIVE PARAMETER BLOCKS FOR JADE DRIVES ; DPBSZ EQU 16 ;SIZE IS 16 BYTES D2DPB: DS DPBSZ ;RESERVE 16 BYTES/DISK C-D ; ; EVERYTHING FROM THIS POINT FOR THE NEXT ; 512 BYTES IS READ INTO MEMORY BY THE NORTH ; STAR BOOT PROM. OUR GOAL HERE IS TO GET ; A REASONABLE AMOUNT OF NORMAL BIOS CODE IN, ; BUT AT THE SAME TIME WE NEED THE PORTIONS ; THAT CAN READ THE DISK. ; ; IF THIS SECTION OVERLAYS PREVIOUS BIOS CODE ; OR DATA SPACE, THE PRECEDING BIOS MUST BE ; TRIMMED DOWN. ; PRVCHK EQU $ ;** MUST NOT EXCEED BOOTA ** ; ORG BIOS+(HSTSIZ*5) ;ORG TO COLD BOOT ; BOOTA: DB BOOTA SHR 8 ;TELL PROM LOAD ADDR ; ; THE NEXT NINE LOCATIONS ARE SKIPPED OVER ; BY THE BOOT PROM, WHICH READS THIS SECTOR ; THEN JUMPS TO BOOTA+0AH, SO PUT USEFUL VARIABLES ; HERE. NOTE THAT ALL VARIABLES IN THIS SECTOR ; WITH GENNED-IN VALUES ARE SET UP FOR COLD ; BOOT LOADING OF BIOS. ; HSTADR: DW BIOS ;READ BIOS INTO HERE TO START, ; BUT NORMALLY PTS TO HSTBUF HSTDSK: DB 0 ;HOST DISK NUMBER HSTTRK: DB 0 ;HOST TRACK NUMBER (MUST IMM ; FOLLOW HSTDSK FOR LHLD) HSTSEC: DB 5 ;HOST SECTOR NUMBER ERFLAG: DB 0 ;ERROR REPORTING CURDSK: DB 059H ;CURRENT ACTIVE DISK, ; GENNED-IN FORCE SELECT COLDB: DB 1 ;COLD BOOT WHEN NON-ZERO ERSEC: DS 1 ;SECTOR IN ERROR ; ; THIS IS THE SECTION OF THE COLD BOOT THAT ; READS IN THE REST OF BIOS. ON MORE CONVENTIONAL ; CP/M SYSTEMS, THIS WOULD BE THE BLOCK ZERO ; BOOT. READ BIOS INTO MEMORY, THEN JUMP TO ; IT TO FINISH COLD BOOTING. ; D3DPB: EQU $ ;*** OVERLAY N* COLD BOOT *** ; BOOT: DI ;ALLOW NO PROCESSOR INTERRUPTS LXI SP,HSTBUF+HSTSIZ ;SET SP TO SCRATCH RAM CALL SETUP ;GIVE MOTORS EXTRA KICK ; AND SEEK TRK 0 ; BOOTL: CALL READNS ;READ NEXT SECTOR OF BIOS ;WITH COLDB NON-ZERO, NO ; RETURN IF I/O ERROR LXI H,HSTSEC ;IF OK, BOP SEC NUM INR M LHLD HSTADR ; AND ADVANCE READ ADDR LXI D,HSTSIZ DAD D SHLD HSTADR MVI A,BOOTA SHR 8 ;SEE IF READ ENUFF CMP H JNZ BOOTL ;LOOP IF NOT JMP INIT ;GO START BIOS IF SO ; ; REMAINING NEEDED VARIABLES ; RTCNT: DS 1 ;ERROR RETRY COUNTER NSDENS: DS 1 ;DENSITY OF LAST NS DISK BLOCK ; READ, SD=128, DD=0 NSCNT: DB 00H ;COUNT AND DENSITY FLAG, SET ; BY WRITEHST TO MATCH ID SECTOR ; ; NORTH STAR CURRENT TRACK TABLE ; NSTRK: DB 059H ;NO CURRENT TRACK YET DB 059H ;EACH ENTRY CONTAINS ; DB 059H ; THE LAST TRACK POSITION ; DB 059H ; FOR THE UNIT 1-4 ; ; OTHER VARIABLES HERE BECAUSE THERE IS SPACE, CAN ; BE MOVED IF NECESSARY ; RSFLAG: DS 1 ;READ SECTOR FLAG READOP: DS 1 ;1 IF READ OPERATION WRTYPE: DS 1 ;WRITE OPERATION TYPE ;;CPMDMA: DS 2 ;LAST DMA ADDRESS ENTPSW: DW 0 ;ENTRY PSW AT DISK READ/WRITE ; ; READHST PERFORMS THE PHYSICAL READ FROM THE ; NORTH STAR DISK. ON ENTRY, DRIVE IS IN HSTDSK, ; TRACK IS IN HSTTRK, SECTOR IS IN HSTSEC. ON ; EXIT, ERROR FLAG IS IN ERFLAG (ZERO IF NONE). ; ; *** INTERRUPTS MUST BE DISABLED HERE *** ; READHST: MVI A,10 ;RETRY COUNT ON ERROR STA RTCNT ; READRT: CALL SETUP ;SELECT DRIVE AND ; SEEK TO TRACK LDA ERFLAG ;CHECK FOR ERRORS ORA A RNZ ;INDEX PULSE NOT FOUND IS FATAL ; ; HERE TO READ NORTH STAR WITHOUT TRACK SEEK FOR SPEED ; READNS: CALL POSEC ;POSITION TO OUR SECTOR JNZ SNFERR ;ERROR IF NOT FOUND MVI B,08CH ;COUNT FOR SYNC CHAR LOOP LXI D,CCMND+40H ;SET UP READ DATA REGS ; ; WAIT FOR RE SO WE CAN DO SECTOR READ, AND TEST ; THE DOUBLE DENSITY BIT. ; WAITRE: LDA CCMND+10H ;GET A-STATUS ANI 04H ;CHECK RE JZ WAITRE ;LOOP UNTIL RE TRUE XTHL ;KILL TIME TO GET INTO ZEROES XTHL XTHL XTHL XTHL XTHL XTHL XTHL LDA CCMND+10H ;GET A-STATUS AGAIN ANI 20H ;ARE WE READING DOUBLE DENS? RAL ;MAKE 80H IF NOT, ZERO IF SO RAL XRI 80H STA NSDENS ;SAVE DENSITY FOR CALLER ; ; NOW WAIT FOR SYNC CHAR DETECTED. ERROR IF WE HAVE TO ; WAIT TOO LONG. ; READ5: LDA CCMND+10H ;WAIT FOR SYNC CHAR DETECTED RRC ;CHECK BIT JC READ15 ;OUT IF GOT IT DCR B ;COUNT DOWN IF NOT JNZ READ5 ;GO BACK IF STILL OK MVI A,1 ;SYNC ERROR IF WAITED TOO LONG LXI H,SYEMSG ;SYNC ERROR MESSAGE ; RERR: STA ERFLAG ;STORE ERROR CODE LDA RTCNT ;COUNT OFF A RETRY DCR A STA RTCNT JNZ READRT ;IF COUNT LEFT, GO RETRY ; ; READ ERROR RETRIES FAILED. FLAG ERROR. ; JMP DSKERR ;TELL OPERATOR OF ERROR THEN OUT ; SNFERR: STA ERFLAG ;SET ERROR FLAG LXI H,SNFMSG JMP DSKERR ;REPORT ERROR ON WAY OUT ; ; READ THE DATA INTO HSTBUF ; READ15: LHLD HSTADR ;READ INTO HERE MVI B,0 ;INIT CHECKSUM BYTE LDA NSDENS ;GET # BYTES TO READ MOV C,A ;PUT READ COUNT IN C-REG ; READ20: LDAX D ;READ NEXT DATA BYTE MOV M,A ; AND PUT IT IN BUFFER XRA B ;ADD TO CHECKSUM RLC MOV B,A INX H ;BOP BUFFER PTR NOP ;KILL TIME LDAX D ;GET NEXT BYTE MOV M,A XRA B RLC MOV B,A INX H DCR C ;COUNT OFF LAST PAIR JNZ READ20 ;GO BACK IF MORE TO DO LDAX D ; ELSE READ CRC BYTE XRA B ; AND CHECK IT AGAINST OURS STA ERFLAG ;IF OK, ZERO EFLAG RZ ; AND RETURN TO CALLER MVI A,2 ; ELSE FLAG CHECKSUM ERROR LXI H,RERMSG ;MESSAGE IF NEEDED JMP RERR ;GO MAYBE RETRY ; ; SETUP SELECTS THE UNIT CORRESPONDING TO HSTDSK, ; THEN SEEKS TO THE TRACK SPECIFIED BY HSTTRK. ; WRITE PRECOMPENSATION IS SET IF REQUIRED AS ; WELL. ON ERROR, ERFLAG CONTAINS A NON-ZERO ; VALUE ON RETURN. ONLY UNITS 1 AND 2 ARE SUPPORTED ; TO SAVE SPACE. ; SETUP: LDA NSCNT ;GET DENSITY FLAG XRI 80H ;INVERT TO SET DD MOV C,A ;SAVE MASK LDA HSTDSK ;WANT THIS DISK INR A ;REMAP TO CONTROLLER MASK ; CPI 03H ;IF UNIT 1 OR 2, ; JC SET0 ; GOT CORRECT MASK ; RAL ;IF 3 OR 4, MUST MAP ; ANI 0CH ; TO 4 OR 8 RESPECTIVELY ;SET0: ORA C ;OR IN DENSITY MASK MOV C,A ;SAVE IN REG C CALL WAIT1S ;WAIT A SECTOR TIME, GET A-STAT ANI 10H ;ARE MOTORS ALREADY ON? LDA CCMND+15H ;GIVE THEM EXTRA KICK ANYWAY JNZ SET5 ;BRANCH IF SO MVI D,17H ;WAIT FOR MOTORS TO CALL SCWAIT ; COME UP TO SPEED IF NOT JMP SET10 ; THEN GO SELECT DRIVE ; SET5: LDA CURDSK ;IS THIS THE CURRENT DISK? CMP C JZ SET20 ;GO SEEK TO TRACK IF SO ; ; MUST SELECT NEW DISK ; SET10: MOV A,C STA CURDSK ;NEW CURRENT DISK MVI B,CORDER SHR 8 ;SET UP FOR SELECT LDAX B ; AND DO IT MVI D,2 ;WAIT TWO SECTOR TIMES CALL SCWAIT ; BEFORE LOOKING FOR INDEX MVI B,12 ;DON'T LOOK TOO LONG ; SET15: CALL WAIT1S ;WAIT A SECTOR TIME, GET A-STAT ANI 40H ;INDEX HOLE SEEN? JNZ SET20 ;CAN GO SEEK NOW IF SO DCR B ;COUNT DOWN IF NOT JNZ SET15 ; AND MAYBE GO LOOK AGAIN ; ; INDEX HOLE NOT FOUND. DISK IS PROBABLY NOT LOADED. ; MVI A,4 ;NO INDEX PULSE STA ERFLAG LXI H,NIPMSG CALL DSKERR ;TELL OPERATOR CALL NOTRDY ; AND CLAIM DISK NOT READY MVI A,059H ;FORCE RESELECT OF DISK STA CURDSK JMP SETUP ;TRY TO GET DISK AGAIN ; ; SEEK TO TRACK SPECIFIED BY HSTTRK NOW, AND SET ; WRITE PRECOMPENSATION IF APPROPRIATE. ; SET20: LDA HSTDSK ;GET NSTRK INDEX MOV C,A MVI B,0 LXI H,NSTRK ;PT AT TABLE DAD B ; THEN AT CORRECT ENTRY MOV A,M ;GET CURRENT TRACK PUSH H ;SAVE NSTRK PTR XRI 59H ;DISK EVER ACCESSED? CZ SEEK ;IF NOT, HOME DRIVE POP H ;RESTORE NSTRK PTR LDA HSTTRK ;SEEK TO THIS TRACK PUSH PSW ;SAVE OVER CALL CALL SEEK ;DO FINAL SEEK POP PSW ;GET HSTTRK BACK CPI 14H+1 ;ARE WE BEYOND TRACK 14H? JC SET25 ;GO ON IF NOT LDA NSCNT ;SEE IF DD OR SD ORA A JNZ SET25 ;NO PRECOMP IF SD LDA CURDSK ;IF SO, GET CURRENT MASK ORI 20H ; AND SET PRECOMP BIT MVI H,CORDER SHR 8 MOV L,A MOV A,M ;SET BIT IN CONTROLLER ; SET25: XRA A STA ERFLAG ;NO ERRORS RET ; ; POSEC IS CALLED TO POSITION TO HSTSEC WITHIN ; THE CURRENT TRACK. ERROR IS RETURNED BY NON-ZERO ; IF WE CAN'T FIND THE SECTOR AFTER 30 TRIES. ; POSEC: LDA HSTSEC ;GET TARGET SECTOR MOV C,A ;IN C STA ERSEC ;SET UP FOR POSSIBLE ERROR MVI B,30 ;LOOK AT THIS MANY SECTORS ; POSC5: CALL WAIT1S ;WAIT FOR NEXT SECTOR LDA CCMND+35H ;KICK MOTORS AND GET SECNUM ANI 0FH ;STRIP NON-SECTOR BITS SUB C ;IS THIS THE TARGET SECTOR? RZ ;OUT IF GOT IT DCR B ;COUNT OFF IF DIDN'T JNZ POSC5 ;GO BACK IF NOT GIVING UP INR B ;SET NON-ZERO IF NOT FOUND RET ; ; SEEK TO TRACK SPECIFIED BY ACC. CURRENT PTR INTO ; NSTRK TABLE IS GIVEN BY HL. IF TRACK SPECIFIED IS ; ZERO, SEEK WILL BE DONE UNTIL TRACK ZERO FLAG IS ; SEEN, REGARDLESS OF CURRENT POSITION, UNLESS ; WE ARE ALREADY THERE, SINCE NO SEEK IS DONE ; IF ALREADY AT THE DESIRED TRACK. ; SEEK: MOV B,A ;SAVE TARGET TRK # SUB M ;SEE HOW FAR AWAY WE ARE ; FROM TARGET TRACK MOV M,B ; BUT ALWAYS SET NEW TRACK RZ ;IF THERE, DONE LXI H,CORDER+30H ;ASSUME STEPPING IN MOV C,A ;SAVE STEP COUNT JP STEPIN ;BRANCH IF RIGHT CMA ;IF WRONG, NEGATE COUNT INR A MOV C,A ; THEN SAVE THAT LDA CCMND+20H ;GET B-STATUS ANI 01H ;ARE WE ON TRACK ZERO? RNZ ;MUST BE DONE IF SO MVI L,10H ;IF NOT, STEPPING OUT ; STEPIN: LDA CURDSK ;GET CURRENT UNIT MASK ORA L ;FORM FINAL CORDER VALUE MOV L,A MOV D,M ;SET THE STEP FLIP-FLOP ORI 10H MOV L,A MOV D,M ;SET IT AGAIN FOR SOME REASON XRI 10H MOV L,A MOV D,M ;NOW RESET THE STEP FLIP-FLOP ; ; WAIT WHILE HEAD STARTS MOVING ; MVI A,14H STEPW1: MVI D,38H STEPW2: DCR D ;KILL TIME JNZ STEPW2 DCR A JNZ STEPW1 ; ; THE STEP RATE DETERMINES HOW LONG TO WAIT. ONE SECTOR ; TIME IS 20 MSEC. A SLOW SHUGART SA400 MAY REQUIRE 40 ; MSEC, OR TWO SECTOR TIMES. MOST TYPICAL SA400'S WILL ; WORK WITH 20 MSEC, SO THAT'S WHAT WE'LL USE HERE. WE ; WILL CALL SCWAIT INSTEAD OF WAIT1S IN CASE WE NEED TO ; PATCH THIS VALUE. ; MVI D,1 ;NOW WAIT 20 MSEC ; MVI D,2 ;NOW WAIT 40 MSEC CALL SCWAIT LDA CCMND+25H ;GET B-STATUS AND KICK MOTORS ANI 01H ;ARE WE AT TRACK ZERO? JNZ WAIT1S ;DONE STEPPING IF SO DCR C ; ELSE COUNT OFF LAST TRACK JNZ STEPIN ;GO BACK IF MORE TO DO CALL WAIT1S ;WAIT ONE MORE SECTOR TIME ; TO MAKE SURE DONE STEPPING INR B ;SEEK TO TRACK ZERO? DCR B RNZ ;DONE IF NOT LDA CCMND+25H ;MUST HAVE TRK ZERO FLAG IF SO ANI 01H RNZ ;OK IF SO JMP STEPIN ;GO STEP MORE IF NOT ; ; SECTOR WAIT. ON ENTRY, # SECTORS TO WAIT IS IN D. ; ON EXIT, D=0 AND ACC=A-STATUS. CALL WAIT1S TO WAIT ; ONE SECTOR TIME. ; WAIT1S: MVI D,1 ;WAIT ONE SECTOR TIME ; SCWAIT: LDA CCMND+11H ;RESET SECTOR FLAG SCW5: LDA CCMND+10H ;GET A-STATUS ORA A ;CHECK SECTOR FLAG JP SCW5 ;WAIT FOR IT IF NOT UP LDA CCMND+11H ; ELSE RESET SECTOR FLAG DCR D ;COUNT DOWN WAIT COUNTER JNZ SCW5 ;GO BACK IF MORE TO DO RET ; ELSE RETURN A-STATUS IN ACC ; ; DISK ERRORS REPORTED HERE, BECAUSE STUPID BDOS GIVES ; NO USEFUL INFORMATION. ; DSKERR: LDA COLDB ;IN COLD BOOT? ORA A ;IF SO, CONOUT NOT IN MEM YET JNZ CBOOT ;BACK TO N* BOOT ROM ON SAME PUSH H ;SAVE BODY ADDRESS LXI H,CRLF ;EJECT LINE CALL MSGOT POP H CALL MSGOT ;REPORT BODY LDA HSTDSK ;THIS DISK ; ; ENTER HERE AFTER JADE DD I/O ERROR ; JAERR: ADI 'A' STA ASCDSK LXI H,ERRMSG CALL MSGOT LDA HSTTRK ;THIS TRACK CALL HXBOT LXI H,SECMSG CALL MSGOT LDA ERSEC ;THIS SECTOR JMP HXBOT ;OFF TO HXBOT TO FINISH ; EBOOT EQU $-1 ;LAST USED COLD BOOT BYTE ; ; ; NORTH STAR HOST SECTOR BUFFER ; HSTBUF: DS HSTSIZ ;HOST BUFFER ; ************************************************************* * * * CBIOS RAM LOCATIONS THAT DON'T NEED INITIALIZATION. * * * ************************************************************* CPMSEC DB 0 ;CP/M SECTOR # CPMDRV DB 0 ;CP/M DRIVE # CPMTRK DB 0 ;CP/M TRACK # TRUESEC DB 0 ;DISK JOCKEY SECTOR THAT ; CONTAINS CP/M SECTOR BUFDRV DB 0 ;DRIVE THAT BUFFER BELONGS TO BUFTRK DB 0 ;TRACK THAT BUFFER BELONGS TO BUFSEC DB 0 ;SECTOR THAT BUFFER BELONGS TO BUFFER DS 1024 ;MAXIMUM SIZE BUFFER FOR 1K ; SECTOR ; LAST EQU $-1 ;LAST USED BYTE IN MEM ; END