TITLE 'Z207 CP/M-86 LOADER BIOS 07 JUL 83' ;*** ; ; THIS IS THE Z207 LOADER BIOS FOR CP/M-86. ; ; ASSUMPTIONS: ; 1. INTERRUPTS ARE DISABLED ; 2. BOOT DRIVE IS SELECTED AND MOTOR IS RUNNING ; ; ; RESTRICTED RIGHTS LEGEND ; ------------------------ ; ; "Use, duplication, or disclosure by the ; government is subject to restrictions as set forth ; in paragraph (b) (3) (B) of the Rights in Technical ; Data and Computer Software clause in DAR ; 7-104.9(a). Contractor/manufacturer is Zenith ; Data Systems Corporation of Hilltop Road, St. ; Joseph, Michigan 49085. ; FALSE EQU 0 TRUE EQU NOT FALSE DSEG INCLUDE ZMEMMAP.LIB INCLUDE CPM86SYS.LIB INCLUDE ZDPEDEF.LIB INCLUDE Z207DEF.LIB INCLUDE LABDEF.LIB INCLUDE ZMTR100.LIB INCLUDE ZPORTS.LIB INCLUDE DEF8259A.LIB INCLUDE EXTRAOPS.LIB ORG BDOSE*4 BDOSVEC RW 2 ;SWI VECTOR FOR BDOS ENTRY EJECT CSEG ORG LDCCP+3 CCPLOAD: ;** LOADER BIOS JUMP VECTORS ; ORG LDBIOS JMP CBOOTE ;COLD BOOT INIT JMP WBOOTE ;WARM BOOT JMP UNUSED ;CONSOLE STATUS JMP WBOOTE ;CONSOLE INPUT ; (ONLY REASON IS DISK I/O ERROR) JMP CONOUTE ;CONSOLE OUTPUT JMP UNUSED ;LIST OUTPUT JMP UNUSED ;PUNCH OUTPUT JMP UNUSED ;READER INPUT JMP HOMEE ;HOME HEAD JMP SETDSKE ;SET DISK JMP SETTRKE ;SET TRACK JMP SETSECE ;SET SECTOR JMP SETDMAE ;SET DMA OFFSET JMP READE ;READ CP/M SECTOR JMP UNUSED ;WRITE CP/M SECTOR JMP UNUSED ;LIST STATUS JMP SECTRNE ;SECTOR TRANSLATE JMP SDMABE ;SET DMA SEGMENT JMP UNUSED ;GET MRT OFFSET JMP UNUSED ;GET I/O MAPPING BYTE JMP UNUSED ;SET I/O MAPPING BYTE EJECT ;** COLD BOOT ENTRY ; CBOOTE: MOV AX,CS ;INIT SEGMENT REGISTERS MOV DS,AX MOV SS,AX LEA SP,STACK ; AND STACK MOV AL,0FFH ;INSURE INTERRUPTS CAN'T BOTHER ME OUT Z8259AM+OCW1,AL ; BY DISABLING 8259A'S OUT Z8259AS+OCW1,AL IN AL,FDTRK ;GET CURRENT TRACK FROM CONTROLLER MOV HSTTRK,AL XOR AX,AX ;SET UP BDOS VECTOR MOV ES,AX MOV ES: BDOSVEC,LDBDOS MOV ES: BDOSVEC+2,CS ; MOVE LABEL INFO TO LOCAL DPE AND DPB MOV SI,BOOTORG+LABHTH ;HEATH EXTENSIONS LEA DI,DPE+OFFSET DPEHTH PUSH DS PUSH ES POP DS ; DS=>0 POP ES ; ES=>LOADER MOV CX,DPEHL CLD REP MOVSB MOV SI,BOOTORG+LABDPB ;DPB LEA DI,DPB MOV CX,DPBL REP MOVSB PUSH ES POP DS ;DS=>LOADER ; MOV CL,0 ;DEFAULT DISK DRIVE JMP CCPLOAD ;BACK TO LOADER ;** WARM BOOT ENTRY ; WBOOTE: XOR AL,AL ;TURN OFF DRIVE OUT FDCON,AL HLT ;HALT MACHINE ;** CONSOLE OUTPUT ENTRY ; ; ENTRY: (CL)=CHARACTER TO BE OUTPUT ; EXIT: NONE ; USES: ALL ; CONOUTE: MOV MSAVSS,SS ;SAVE STACK MOV MSAVSP,SP MOV AX,DS ;SETUP LOCAL STACK MOV SS,AX LEA SP,MSTACK PUSHA MOV AL,CL CALLFI MTRSCRT,MTRSEG ;USE MONITOR I/O ROUTINE CALLFI MTRTINT,MTRSEG POPA MOV SS,MSAVSS ;RESTORE STACK MOV SP,MSAVSP RET ;** HOME HEAD ENTRY ; ; ENTRY: NONE ; EXIT: NONE ; USES: ALL ; HOMEE: MOV CX,0 JMPS SETTRKE ;** SET DISK DRIVE ENTRY ; ; ENTRY: (CL)=REQUESTED DRIVE ; EXIT: (BX)=ADDRESS OFFSET OF 'DPE' ; USES: ALL ; SETDSKE: XOR AX,AX ;ASSUME 5 1/4" DRIVE (NO XLATE TABLE) TEST DPE + OFFSET DPEUNIT,CONDS8 JZ SETDSKE1 ;BR IF 5 1/4" DRIVE LEA AX,XLATE1 ;ASSUME SINGLE DENSITY 8" TEST DPE + OFFSET DPEFLAG,DPEDD JZ SETDSKE1 ;BR IF SINGLE DENSITY LEA AX,XLATE2 ;ASSUME DOUBLE DENSITY 8" 26X256 CMP DPE + OFFSET DPERPS,256/128 JE SETDSKE1 ;BR IF 256 BYTE SECTORS XOR AX,AX ;USE NO XLATE TABLE SETDSKE1: MOV WORD PTR (DPE + OFFSET DPEXLT),AX LEA BX,DPE ;POINT TO DISK PARAMETER HEADER RET ;** SET TRACK ENTRY ; ; ENTRY: (CX)=TRACK # ; EXIT: NONE ; USES: ALL SETTRKE: MOV REQTRK,CX RET ;** SET SECTOR ENTRY ; ; ENTRY: (CX)=SECTOR # (IN RANGE 1 TO SPT) ; EXIT: NONE ; USES: ALL ; ; *** NONE *** ; IT IS ASSUMED ON ENTRY THAT THE SECTOR NUMBER IS IN THE RANGE 1 TO ; 'CP/M SECTORS PER TRACK'. THEREFORE, ONLY THE VALUE PASSED ; IN REGISTER CL IS USED. ; INTERNALLY THE BIOS WANTS SECTOR NUBMERS IN THE RANGE ; 0 TO SPT-1. THEREFORE, BEFORE SAVING THE SECTOR NUMBER, ; IT IS DECREMENTED. ; SETSECE: DEC CL ;PUT IN RANGE 0 TO SPT-1 XOR CH,CH ;ZERO HIGH ORDER BYTE MOV REQSEC,CX RET ;** SET DMA OFFSET ENTRY ; ; ENTRY: (CX)=DMA POINTER OFFSET ; EXIT: NONE ; USES: ALL ; SETDMAE: MOV DMAPTR,CX RET ;** SECTOR TRANSLATE ENTRY ; ; ENTRY: (CX)=LOGICAL SECTOR NUMBER (IN RANGE 0 TO SPT-1) ; (DX)=ADDRESS OF SECTOR TRANSLATE TABLE ; EXIT: (BX)=TRANSLATED CP/M SECTOR NUMBER (IN RANGE 1 TO SPT) ; USES: ALL ; SECTRNE: MOV BX,CX TEST DX,DX JZ SECTRNE1 ADD BX,DX MOV BL,[BX] XOR BH,BH JMPS SECTRNE2 SECTRNE1: INC BX SECTRNE2: RET ;** SET DMA SEGMENT ADDRESS ; ; ENTRY: (CX)=SEGMENT BASE FOR DMA READ OR WRITE OPERATIONS ; EXIT: NONE ; USES: ALL ; SDMABE: MOV DMASEG,CX RET UNUSED: XOR AL,AL XOR BX,BX RET EJECT WAIT EQU TRUE ;USE WAIT STATE I/O ;** READ CP/M SECTOR ENTRY ; ; ENTRY: NONE ; EXIT: (AL)=ERROR STATUS ; 0=NO ERROR , 1=ERROR ; USES: ALL ; READE: ; DETERMINE PHYSICAL TRACK, SIDE, AND SECTOR MOV AX,REQTRK ;ASSUME PHYSICAL TRACK = REQ TRACK MOV PHYTRK,AL MOV PHYSID,0 ;ASSUME SIDE 0 TEST DPE + OFFSET DPEFLAG,DPE2S JZ READE1 ;BR IF SINGLE SIDED MEDIA SHR PHYTRK,1 ;PHYSICAL TRACK = REQ TRACK / 2 JNC READE1 ;EVEN PHYSICAL TRACK ON SIDE 0 MOV PHYSID,FDFSS1 ;ODD PHYSICAL TRACK ON SIDE 1 READE1: MOV AX,REQSEC ;CALCULATE PHYSICAL SECTOR & DIV DPE + OFFSET DPERPS ; OFFSET MOV WORD PTR PHYSEC,AX ; CHECK IF PHYSICAL IS ALREADY IN HOST BUFFER MOV AL,PHYSID ;CHECK SIDE CMP AL,HSTSID JNE READE2 MOV AL,PHYTRK ;CHECK TRACK CMP AL,HSTTRK JNE READE2 MOV AL,PHYSEC ;CHECK SECTOR CMP AL,HSTSEC JE READE5 ; NEED TO READ PHYSICAL SECTOR INTO HOST BUFFER READE2: MOV AL,PHYTRK CMP AL,HSTTRK JE READE3 ;BR IF HEAD ALREADY AT DESIRED TRACK CALL SEEK ;SEEK TO DESIRED TRACK TEST DPE + OFFSET DPEFLAG,DPE48RO JZ READE2A ;BR IF NO NEED TO DOUBLE STEP MOV AL,HSTTRK ;DO DOUBLE STEP OUT FDTRK,AL CALL SEEK READE2A: MOV AL,PHYTRK ;REMEMBER WHERE HEAD IS NOW MOV HSTTRK,AL READE3: MOV AL,PHYSEC ;GET PHYSICAL SECTOR # MOV HSTSEC,AL ;REMEMBER IT INC AL ;PUT INTO RANGE 1 TO SPT OUT FDSEC,AL ;TELL CONTROLLER IF WAIT MOV AL,DPE + OFFSET DPEUNIT ;ENABLE WAIT STATE I/O OR AL,CONWE OUT FDCON,AL ENDIF MOV AL,PHYSID ;GET PHYSICAL SIDE # MOV HSTSID,AL ;REMEMBER IT OR AL,FDCRDS+FDFSLF+FDFDLF ;FORM READ COMMAND MOV CX,WORD PTR COUNT ;GET # BYTES PER SECTOR LEA DI,HSTBUF ;HOST BUFFER POINTER MOV DX,DS MOV ES,DX CLD OUT FDCMD,AL ;ISSUE COMMAND READE4: IF NOT WAIT IN AL,FDAS ;WAIT FOR DRQ OR IRQ TEST AL,ASDRQ+ASIRQ JZ READE4 ENDIF IN AL,FDDAT ;GET DATA STOSB ;STORE DATA INTO BUFFER LOOP READE4 ;LOOP FOR COUNT BYTES IF WAIT MOV AL,DPE + OFFSET DPEUNIT ;TURN OFF WAIT STATE I/O OUT FDCON,AL ENDIF CALL WIO1 ;WAIT FOR IRQ AND GET STATUS TEST AL,AL JNZ READEE ;BR IF ERROR ; MOVE CP/M RECORD FROM HOST BUFFER TO USER BUFFER READE5: MOV AL,PHYOFF ;CALC START OF CP/M RECORD MOV AH,128 MUL AH LEA SI,HSTBUF ADD SI,AX MOV CX,128 ;MOVE DATA LES DI,DWORD PTR DMAPTR CLD REP MOVSB ; RETURN INDICATING NO ERROR XOR AL,AL RET ; READ ERROR READEE: CMP AL,FDSRNF ;Q. RECORD NOT FOUND JNE READEE1 ; BR IF NOT TEST DPE + OFFSET DPEFLAG,DPE48RO JNZ READEE1 ;BR IF ALREADY DOUBLE STEPPING OR DPE + OFFSET DPEFLAG,DPE48RO ;SET DOUBLE STEP MOV AL,FDCRST+FDFHLB+FDFS30 ;RESTORE HEAD CALL WAITIO MOV HSTTRK,0 JMP READE2 ;RETRY READ READEE1: MOV AL,0FFH ;INDICATE ERROR RET ;* SEEK TO DESIRED TRACK SEEK: MOV AL,PHYTRK ;SET DESIRED TRACK OUT FDDAT,AL MOV AL,FDCSEK+FDFHLB+FDFS30 ;SEEK COMMAND ;* WAIT FOR I/O COMPLETION ; ; WAITIO -- ISSUE COMMAND AND WAIT ; WIO1 -- JUST WAIT, COMMAND HAS ALREADY BEEN ISSUED ; WAITIO: OUT FDCMD,AL ;ISSUE COMMAND WIO1: IN AL,FDAS ;WAIT FOR IRQ TEST AL,ASIRQ JZ WIO1 WIO2: IN AL,FDSTA ;WAIT FOR DRIVE READY TEST AL,FDSNRD JNZ WIO2 IN AL,FDSTA ;GET FINAL STATUS RET EJECT X EQU OFFSET $ DSEG ORG X DPE RB 0 ;DISK PARAMETER ENTRY TABLE DW 0 ; SECTOR TRANSLATE TABLE ADDRESS DW 0,0,0 ; SCRATCH DW DIRBUF ; DIRECTORY BUFFER DW DPB ; DISK PARAMETER BLOCK POINTER DW CSV ; CHECKSUM VECTOR POINTER DW ALV ; ALLOCATION VECTOR POINTER RB DPEHL ; HEATH EXTENSIONS IF (OFFSET $ - OFFSET DPE) NE DPEL %: DPE IS NOT CORRECT LENGTH ENDIF COUNT EQU DPE+OFFSET DPETRK HSTSID DB -1 ;CURRENT SIDE IN HOST BUFFER XLATE1 RB 0 ;8" SINGLE DENSITY SECTOR XLATE TABLE DB 1,7,13,19,25 DB 5,11,17,23 DB 3,9,15,21 DB 2,8,14,20,26 DB 6,12,18,24 DB 4,10,16,22 XLATE2 RB 0 ;8" DOUBLE DENSITY SECTOR XLATE TABLE DB 1,2,19,20,37,38 DB 3,4,21,22,39,40 DB 5,6,23,24,41,42 DB 7,8,25,26,43,44 DB 9,10,27,28,45,46 DB 11,12,29,30,47,48 DB 13,14,31,32,49,50 DB 15,16,33,34,51,52 DB 17,18,35,36 EJECT ; ; *** NOTE *** ; ; THERE ARE ONLY 52 CP/M SECTORS AVAILABLE FOR THE BOOT/LOADER CODE. ; THE LOADER CCP AND LOADER BDOS OCCUPY 36 SECTORS, LEAVING 16 CP/M ; SECTORS FOR THE BOOT CODE AND THE LOADER BIOS. THEREFORE, THE ; LOCATION COUNTER AT THIS POINT CANNOT BE GREATER THAN ; LDBIOS+LDBIOSL. ; IF (OFFSET $ - LDBIOS) GT LDBIOSL %: LOADER BIOS IS TOO LARGE ENDIF DIRBUF RB 128 ;DIRECTORY BUFFER DPB RB DPBL ;DISK PARAMETER BLOCK CSV RB 64 ;CHECKSUM VECTOR ALV RB 77 ;ALLOCATION VECTOR REQTRK RW 1 ;REQUESTED CP/M TRACK REQSEC RW 1 ;REQUESTED CP/M SECTOR DMAPTR RW 1 ;DMA OFFSET DMASEG RW 1 ;DMA SEGMENT IF (OFFSET DMASEG - OFFSET DMAPTR) NE 2 %: 'DMASEG' DOES NOT IMMEDIATELY FOLLOW 'DMAPTR' ENDIF PHYTRK RB 1 ;PHYSICAL TRACK PHYSID RB 1 ;PHYSICAL SIDE PHYSEC RB 1 ;PHYSICAL SECTOR PHYOFF RB 1 ;CP/M RECORD OFFSET IF (OFFSET PHYOFF - OFFSET PHYSEC) NE 1 %: 'PHYOFF' DOES NOT IMMEDIATELY FOLLOW 'PHYSEC' ENDIF HSTTRK RB 1 ;CURRENT TRACK IN HOST BUFFER HSTSEC RB 1 ;CURRECT SECTOR IN HOST BUFFER HSTBUF RB 1024 ;HOST DISK BUFFER RB 1024 ;STACK FOR MONITOR CALLS MSTACK RB 0 MSAVSS RW 1 MSAVSP RW 1 RB 64 ;LOCAL STACK FOR COLD BOOT STACK RB 0 END