PAGESIZE 74 PAGEWIDTH 132 ; ; A BIOS FOR CPM-86 (v1.X) USING A HARD DISK, 2 FLOPPY DISKS & A RAMDISK ; ; IT IS SETUP AT THE MOMENT FOR ONE MINISCRIBE 10MG BYTE HARD DISK DRIVE & ; ONLY 2 8" DRIVES CONTROLLED BY THE 1791 CHIP. THIS BIOS IS VERY HARDWARE ; DEPENDENT AND WOULD REQUIRE SOME REWORKING FOR OTHERE S-100 BOARDS. ; THE S100 BOARDS ARE THE VERSAFLOPPY II, THE XCOMP HARD DISK CONTROLLERS. ; THE BIOS HAS SOME LINKS TO OTHER HOMEBREW BOARDS I USE. THESE ARE AN IO ; MAPPED 1MG BYTE MEMORY DISK, A SPEECH SYNTHESIS BOARD, AND A KEYBOARD WITH ; TYPE-AHEAD,TRANSLATION ETC. THESE NEED NOT CONCERN YOU SINCE THEY ARE ONLY ; INITILIZED IN THE BIOS. ; ; ; AUTHOR: JOHN J. MONAHAN (201)583-1548 7/1/82 ; MODIFIED FOR RAMDISK 7/5/83 ; MODIFIED FOR SPEECH SYNTHESIS 10/29/83 ; MODIFIED FOR SD 8024 BOARD / KEYBOARD Z80 CONTROLLER 1/1/84 ; ;-------- PORTS USED IN IO DRIVERS FOR CONSOLE ETC.------------------ ; IOBYTE EQU 0FFH ;IOBYTE (SEE BELOW) SDSTAT EQU 0H SDDATA EQU 1H KEYSTAT EQU 0H ;SEPERATE PORT TO SEE IF ANYTHING AT KEYBOARD KEYIN EQU 01H resetkey equ 0f8h ;inputting from this port causes an NMI on my ; ;z80 keyboard board to force the CPM keyboard ; CENTOUT EQU 5H ;CENTRONICS PRINTER PORT CENTSTAT EQU 5H CENTSTROBE EQU 4H ; TALKSTAT EQU 0B0H ;REQ FOR SPEECH SYNTHESIS TALKOUT EQU 0B1H ; ; MISC. EQUATES FOR RAMDISK ; CMDDLY EQU 0FFFFH MAXTRK EQU 2 ;RETURN MAXIMUM TRACK # OF MEMORY DISK RDSECTOR EQU 0 WRTSECTOR EQU 1 CTRLPORT EQU 0B6H ;WAS 7 DATAPORT EQU 0B8H ;WAS 6 ; ;------- HARD DISK PARAMETERS -------------------------------------- ; MAXSEC EQU 32 ;SECTORS PER TRACK ON HARD DISK MAXCYL EQU 500 ;NUMBER OF CYLINDERS/HEAD LZONE EQU 656 BLKSIZ EQU 2048 ;BYTES PER BLOCK FOR HARD DISK CPMSPT EQU 2*MAXSEC ;CPM SECTORS PER TRACK FOR HARD DISK HSKCMD EQU 3 ;SEEK CMD FOR HARD DISK CONTROLLER SKOUT EQU 1 NOPC EQU 40H ;NO PRE-COMPENSATION LOWRT EQU 80H ;LOW WRITE CURRENT READY EQU 1 ;HARD DISK DRIVE READY WRTFLT EQU 2 ;HARD DISK WRITE FAULT TK00 EQU 4 ;HARD DISK TRACK ZERO RAWINDX EQU 20H ;HARD DISK RAW INDEX BANK0 EQU 0 ;BANK 0 SELECT ON XCOMP CONTROLLER BANK1 EQU 1 ;BANK 1 SELECT DBENB EQU 2 ;DATA BUFFER ENABLE CBENB EQU 4 ;COMPARE BUFFER ENABLE START EQU 8 ;START COMMAND FOR XCOMP CONTROLLER VSA EQU 8 ;SEEK VERIFY START ADDRESS VCA EQU 1BH ;SEEK VERIFY COMPARE ADDRESS CBASE EQU 70H ;BASE ADR OF THE XCOMP CONT PORTS DRCSR EQU CBASE ;DRIVE COMMAND/STATUS EXTCMD EQU CBASE+1 ;EXTENDED COMMNAND REGISTER LOSC EQU CBASE+2 ;SEEK COUNT, LSB HISC EQU CBASE+3 ;SEEK COUNT, MSB CTCSR EQU CBASE+4 ;CONTROLLER COMMAND/STATUS CTBFR EQU CBASE+5 ;CONTROLLER BUFFER ADDRESS CTDP EQU CBASE+6 ;CONTROLLER DATA PORT ; ;------ VERSAFLOPPY II DISK PARAMETERS --------------------------------- ; X EQU 60H ;BASE ADDRESS OF PORTS FOR 1791 RSET EQU X+0 ;CONTROLLER RESET ADDRESS SELECT EQU X+3 ;DRIVE SELECT PORT STATUS EQU X+4 ;STATUS PORT TRACK EQU X+5 ;TRACK PORT SECTOR EQU X+6 ;SECTOR PORT DATA EQU X+7 ;DATA PORT CMD EQU X+4 ;COMMAND PORT RDACMD EQU 0C0H ;READ ADDRESS CODE RDCMD EQU 088H ;READ SECTOR CODE WRCMD EQU 0A8H ;WRITE SECTOR CODE WRTCMD EQU 0F4H ;WRITE TRACK CODE RSCMD EQU 009H ;RESTORE COMMAND SKNCMD EQU 019H ;SEEK NO VERIFY SKCMD EQU 1DH ;SEEK WITH VERIFY STDSDT EQU 26 ;STANDARD 8" 26 SECTORS/TRACK STDDDT EQU 50 ;STANDARD DD 8" 50 SECTORS/TRACK NBYTES EQU 128 ;BYTES/SECTOR NTRKS EQU 77 ;TRACKS/DISK ; ; ; ASCII CHARACTERS ; CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED BELL EQU 7 ;DING ; ; CSEG ORG 0H CCP: ; ;============================================================================ ; ; THE CPM-86 CCP AND BDOS WILL GO HERE ( ABSOLUTE 500H TO 25FFH) ; ; {I leave 100h bytes for an 8089 below cpm for my system. so the ; org value is 2500h. You may want to use 2400h as DR does} ; ; NOTE WITH THIS 8089 VERSION I HAVE EVERYTHING 100H HIGHER ; THAN EVERYTHING IN THE DIGITAL RESEARCH MANUAL. ; SO THE CCP AND BDOS WILL BE FROM 500H TO 25FFH AND 8089 ; TABLE AT 400H TO 500H. ; ;============================================================================ ; ORG 2500H ;NOW THE START OF THE CUSTOM BIOS ;NOTE ACTUAL ADDRESS IS 2A00H BECAUSE ;OF [CS] OFFSET ; ---JUMP TABLE--- ; CPMINIT:JMP INIT ; 0 - COLD BOOT WBX: JMP WBOOT ; 1 - WARM BOOT JMP CSTS ; 2 - CONSOLE STATUS REQUEST ZCI: JMP CI ; 3 - CONSOLE INPUT ZCO: JMP CO ; 4 - CONSOLE OUTPUT ZLO: JMP LO ; 5 - LIST OUTPUT JMP POO ; 6 - PUNCH OUTPUT JMP RI ; 7 - READER INPUT JMP HOME ; 8 - TRACK ZERO SEEK JMP SETDR ; 9 - SET DRIVE # JMP SETTK ; 10 - SET TRACK ADR JMP SETSEC ; 11 - SET SECTOR ADR JMP SETDMA ; 12 - SET BUFFER ADDRESS JMP READ ; 13 - READ A SECTOR JMP WRITE ; 14 - WRITE A SECTOR ZLISTS: JMP LSTAT ; 15 - LIST OUTPUT READY TEST JMP SXR ; 16 - SECTOR XLATE ROUTINE JMP SETDMAB ; 17 - SET SEG BASE FOR BUFFER JMP GETSEGT ; 18 - GET MEM DESC TABLE OFFSET JMP GETIOBF ; 19 - RETURN IO BYTE JMP SETIOBF ; 20 - SET IO BYTE ; ; ===================== ; ** CBIOS FUNCTIONS ** ; ===================== ; ---COLD BOOT--- ; ; INIT: MOV AX,CS MOV SS,AX MOV DS,AX MOV ES,AX MOV SP, OFFSET STKBASE ;USE A LOCAL STACK CLD PUSH DS MOV AX,0 MOV DS,AX MOV ES,AX MOV INT0_OFFSET, OFFSET INT_TRAP ;INT0 TO ADDRESS TRAP ROUTINE MOV INT0_SEGMENT, CS MOV DI,4 MOV SI,0 MOV CX,510 ;TRAP VECTOR TO ALL 256 INTS REP MOVS AX,AX MOV BDOS_OFFSET, 0B06H ;BDOS OFFSET TO PROPER INT0 MOV BDOS_SEGMENT,CS MOV INT0_OFFSET, OFFSET INT0_TRAP MOV INT4_OFFSET, OFFSET INT4_TRAP POP DS ; CALL XTKZ ;BRING HEADS OF HDISK TO TRK 0 ; MOV BX,OFFSET FLAGS ;CLEAR RAM STORAGE AREA MOV CH, FLGSIZ XOR AL,AL INIT1: MOV BYTE PTR [BX],AL ;CLEAR FLAGS & VARIABLES INC BX DEC CH JNZ INIT1 MOV BYTE PTR IOBYT, AL ;CLEAR IOBYTE DEC AL ;0FFH IN AL MOV BYTE PTR ADRIVE, AL ;COME ON WITH B: & C: DENSITY UNKNOWN MOV BYTE PTR BDRIVE, AL OUT CENTSTROBE,AL ;CLEAR PRINTER PORT JUST IN CASE IN AL,DATAPORT ;CLEAR GARBAGE FROM PARALLEL PORT FOR ;MDISK in al,resetkey ;to insure cpm table in z80board MOV WORD PTR DMASEG, CS ;SET DEFAULT SEGMENT DMA TO HERE MOV BX,OFFSET SIGNON CALL PMSG MOV BX,OFFSET SPEAKON CALL SMSG MOV CL,0 ;DEFAULT TO DRIVE A: JMP CCP ; ; ---WARM BOOT--- ; WBOOT: in al,resetkey ;to insure cpm table in z80board XOR AL,AL DEC AL MOV BYTE PTR ADRIVE,AL ;PUT 0FFH IN FLOPPY A & B STORE MOV BYTE PTR BDRIVE,AL JMP CCP + 6 ;GOTO CPM ; ; ; --- INT TRAP ROUTINES --- INT0_TRAP: CLI MOV BX,OFFSET INT0_TRP ;DIVIDE TRAP HALT JMPS INT_HALT INT4_TRAP: CLI MOV BX,OFFSET INT4_TRP ;OVERFLOW TRAP HALT JMPS INT_HALT INT_TRAP: CLI MOV BX,OFFSET INT_TRP ;INTERRUPT TRAP HALT INT_HALT:MOV AX,CS MOV DS,AX CALL PMSG POP BX ;GET SEGMENT POP AX ;PRINT SEGMENT PUSH BX CALL PHEX MOV CL,':' CALL ZCO ;PRINT OFFSET POP AX CALL PHEX HLT ;HOLD EVERYTHING ; PHEX: PUSH AX MOV AL,AH CALL PHXB POP AX PHXB: PUSH AX MOV CL,4 SHR AL,CL CALL PHXD POP AX AND AL,0FH ;ISOLATE LOWER NIBBLE PHXD: ADD AL,90H ;DISPLAY A NIBBLE DAA ADC AL,40H DAA MOV CL,AL CALL ZCO RET ; GETIOBF: MOV AL,IOBYT RET ; SETIOBF: MOV IOBYT,CL RET ; PMSG: MOV AL,[BX] ;PRINT A STRING TEST AL,AL JZ RETURN MOV CL,AL CALL ZCO INC BX CALL PMSG RETURN: RET ; ---SECTOR TRANSLATE ROUTINE--- ; SXR: TEST DX,DX JNZ SXR1 ;IF Z THEN NO TRANSLATION IS REQ MOV BX,CX RET ; SXR1: MOV BX,CX ;TRANS SEC [CX] USING TABLE AT [DX] ADD BX,DX ;WILL HAVE NO TRANSLATION FOR MDISK MOV BL,[BX] RET ; ; ---HOME--- ; HOME: MOV AL,BYTE PTR RRDSK ;DRIVE # CMP AL,1 ;SET AT THE MOMENT FOR ONE HARD DISK JNB HOMEX JMP XSTZ ;JIF REZERO HARD DISK HOMEX: MOV CX,0 ;RETURN ZERO JUST IN CASE JMP SETTK ; ; ---READ--- ; READ: MOV AL,BYTE PTR RRDSK ;DRIVE # CMP AL,1 JNB LAB13 JMP HDREAD ;JIF READ FROM H/D LAB13: CMP AL,3 JNB LAB14 JMP FREAD ;JIF READ FROM F/D LAB14: CMP AL,12 ;CHECK IF MDISK JNZ SELERR ;IF M: THEN MDISK JMP MREAD ; SELERR: XOR AL,AL DEC AL RET ;RETURN WITH NZ FLAG FOR ERROR ; ; ---WRITE--- ; WRITE: MOV AL,BYTE PTR RRDSK ;DRIVE # CMP AL,1 JNB LAB15 JMP HDWRT ;JIF WRITE ONTO H/D LAB15: CMP AL,3 JNB LAB16 JMP FWRITE ;JIF WRITE ONTO F/D LAB16: CMP AL,12 ;CHECK IF MDISK JNZ SELERR ;IF F: THEM MDISK JMP MWRITE ; ; ---SET DRIVE NUMBER--- ; SETDR: MOV AL,CL ;A = NEW DRIVE # MOV BYTE PTR RRDSK,AL ; SAVE IT MOV BX,0 CMP AL,12 ;TEST FOR MDISK JE MDSELDSK CMP AL,3 JNAE LAB17 ;NOT M:, A:, B:, OR C: SO ERROR RET ;RIF INVALID DRIVE # WITH [BX]=0 ; LAB17: CMP AL,0 ;IF NOT 0 IE. [A:] MUST BE FLOPPYS JE LAB18 CALL FSELDSK ;RET WITH LOGICAL DRIVE OFFSET IN [A] LAB18: MOV BL,AL ;B: OR C: (OR FOR DD D: OR E:) MOV BH,0 MOV CL,4 SHL BX,CL ;TIMES 16 ADD BX,OFFSET DPHDR RET ; ; MDSELDSK: TEST DL,01 JZ GETMDSK ;UPDATE DPB MOV BX,OFFSET DPE12 ;HEADER FOR DISK WILL ALWAYS BE HERE RET ; GETMDSK:MOV CL,MAXTRK ;NEED MAXIMUM TRACK # FROM RAMDISK CALL MRDCMD ;SO SEND COMMAND TO RAMDISK JNB MDINIT1 ;SKIP NEXT IF COMMAND SENT OK MDINIT0:MOV BX,0 ;THIS WILL FLAG BDOS RET ; MDINIT1:CALL RDREAD ;WAIT FOR MAXIMUM TRACK BYTE CMP AL,-1 ;IF TRACK =-1 THEN NO MDISK AVAILABLE JZ MDINIT0 INC AL ;PUT TRACK INTO RANGE 1 - N MOV BL,AL ;MAKE TRACK DOUBLE PRECISION IN [HL] MOV BH,0 MOV DX,BX ;KEEP COPY IN [DX] MOV CL,5 SHL BX,CL ;X32 SUB BX,DX ;X31 SUB BX,DX ;X30 (THIS IS # 2K BLOCKS / TRACK) MOV AL,BH ;GET HI BYTE OF DSM TO [A] OR AL,AL ;IS IT > 0 ? MOV AL,0 ;ASSUME >= 256 BLOCKS JNZ MDINIT2 MOV AL,1 ;ELSE EXM MUST = 1 MDINIT2: MOV BYTE PTR DPB_EXM,AL ;STORE EXM BYTE INTO DPB DEC BX ;# 2K BLOCKS - 1 MOV WORD PTR DPB_DSM,BX ;UPDATE DPB DSM FIELD MOV BX,OFFSET DPE12 RET ; ; ---SET SECTOR ADR--- ; SETSEC: MOV WORD PTR RRSEC,CX ;SAVE SECTOR ADR (NEED CX BECAUSE THE ;MDISK HAS UP TO 480 SECTORS/"TRACK" ;SET REAL SEC ADR FOR THE HARD DISK AND CL,0FEH ;DRIVER. ROR CL,1 ;THERE ARE 2 CPM SECTORS PER H/D SECT MOV BYTE PTR RSA,CL ;SAVE REAL SECTOR ADR RET ; ; ---SET TRACK ADDRESS--- ; SETTK: MOV WORD PTR RRTRK,CX ;SAVE TRACK ADR RET ; ; ---SET DMA ADDRESS--- ; SETDMA: MOV WORD PTR DMADR,CX ;SAVE DMA ADR RET ; ; ---- SET DMA SEGMENT --- ; SETDMAB:MOV WORD PTR DMASEG,CX RET ; ; ---- GET MEMORY MAP --- GETSEGT:MOV BX, OFFSET SEG_TABLE RET ; ; ====================================== ; ** HARD DISK BLOCK/DEBLOCK ROUTINES ** ; ====================================== ; ; ---HARD DISK READ--- ; HDREAD: XOR AL,AL MOV BYTE PTR ERFLG,AL ;CLEAR THE ERROR FLAG MOV AL,BYTE PTR FLAGS ;SET READ OPERATION FLAG OR AL,00000001B ;SET 0,A MOV BYTE PTR FLAGS,AL AND AL,00000100B ;BIT 2,A JZ LAB19 CALL XWRT ;YES, WRITE DATA BEFORE READ LAB19: MOV AL,BYTE PTR FLAGS AND AL,11111011B ;RES 2,A RESET WIP FLAG MOV BYTE PTR FLAGS,AL CALL TSTHST ;HOST = REQ ? JNZ HDRD1 ;NO, READ A BLOCK MOV AL,BYTE PTR FLAGS AND AL,02H ;PRIOR BLOCK READ ? JNZ HDRD2 ;YES, JUST EXTRACT DATA FROM BFR HDRD1: CALL SETHST ;MAKE HOST=REQ CALL XREAD ;READ A BLOCK HDRD2: CALL GETDMA ;GET DMA ADR, SET POINTERS PUSH ES MOV ES, WORD PTR DMASEG ;GET CORRECT SEGMENT MOV DI,BX CLD ;SET DIRECTION FLAG IN AL,CTDP ;PRIME DATA INPUT HDRD3: IN AL,CTDP ;<<<<<<<<<<<<<< INPUT 128 BYTES >>>>> STOS AL ;NOTE POINTER IS [ES] & [DI] LOOP HDRD3 ;WILL HAVE AUTO INC OF [CX] & [DI] POP ES MOV AL,BYTE PTR FLAGS OR AL,00000010B ;SET 1,A SET READ-IN-PROGRESS FLAG MOV BYTE PTR FLAGS,AL MOV AL,BYTE PTR ERFLG ;ERROR FLAG RET ; ; ---HARD DISK WRITE--- ; ; HDWRT: XOR AL,AL MOV BYTE PTR ERFLG,AL ;CLEAR THE ERROR FLAG MOV AL,BYTE PTR FLAGS AND AL,11111101B ;RES 1,A CLEAR READ-IN-PROGRESS FLAG MOV BYTE PTR FLAGS,AL MOV AL,CL ;AL= 0 NORMAL = 1 DIR = 2 UNALLOCATED DEC AL JNZ LAB20 JMP WDIR ;DO DIRECTORY WRITE LAB20: JNS WUN JMP WNORM ;DO NORMAL WRITE ; ; UNALLOCATED WRITE ; WUN: MOV AL,BYTE PTR FLAGS AND AL,00000100B ;BIT 2,A WRITE IN PROGRESS ? JZ LAB21 CALL XWRT ;YES, WRITE DATA IN BFR LAB21: MOV AL,BLKSIZ/128 ;SET UNALLOC RECORD PARAMETERS MOV BYTE PTR URCNT,AL ;SET UNALLOC RECORD COUNT MOV BX,WORD PTR RRDSK MOV WORD PTR URDSK,BX ;UPDATE DRIVE & SECTOR MOV BX,WORD PTR RRTRK MOV WORD PTR URTRK,BX ;UPDATE TRACK ADR CALL SETHST ;SET HOST = REQ CALL BUMP ;BUMP UNALC PARMS FOR NEXT PASS ;XFER DATA TO CTLR BFR WXFER: MOV AL,BYTE PTR FLAGS AND AL,11111110B ;RES 0,A CLEAR READ OPER FLAG MOV BYTE PTR FLAGS,AL CALL GETDMA ;GET DMA ADR, SET FOR WRITE PUSH DS MOV DS, WORD PTR DMASEG ;GET CORRECT SEGMENT CLD MOV SI,BX WXFER1: LODS AL ;>>>>>>>>>OUTPUT 128 BYTES<<<<<<<<<<< OUT CTDP,AL ;POINTER WILL BE [DS] AND [SI] LOOP WXFER1 POP DS ;RESTORE [DS] MOV AL,BYTE PTR FLAGS OR AL,00000100B ;SET 2,A SET WRITE-IN-PROGRESS FLAG MOV BYTE PTR FLAGS,AL MOV AL,BYTE PTR ERFLG ;ERROR FLAG RET ; ; NORMAL WRITE ; WNORM: MOV AL,BYTE PTR URCNT ;UNALC RECORD COUNT OR AL,AL JZ WALC ;JIF DO ALLOC WRITE MOV BX,(OFFSET URTRK) CALL DSKCMP ;UNALC DSK/TRK = REQ DSK/TRK ? JNZ WALC ;NO, DO ALLOC WRITE MOV AL,BYTE PTR RRSEC CMP AL,BYTE PTR [BX] ;UNALC SECT = REQ SECT ? JNZ WALC ;NO, DO ALLOC WRITE CALL BUMP ;BUMP UNALC PARMS FOR NEXT PASS CALL TSTHST ;HOST = REQ ? JZ WN1 ;YES, CON'T TO FILL THE BFR MOV AL,BYTE PTR FLAGS AND AL,00000100B ;BIT 2,A WRITE IN PROGRESS ? JZ LAB22 CALL XWRT ;YES, WRITE OLD DATA ONTO DISK LAB22: CALL SETHST ;MAKE HOST = REQ ; WN1: MOV AL,BYTE PTR FLAGS AND AL,00000001B ;BIT 0,A INTERVENING READ ? JZ LAB23 CALL XREAD ;YES, READ OLD UNALC DATA LAB23: JMPS WXFER ;MOVE DATA TO BFR, EXIT ; ; ALLOCATED WRITE ; WALC: XOR AL,AL MOV BYTE PTR URCNT,AL ;CLEAR UNALC RECORD COUNT CALL TSTHST ;HOST = REQ ? JZ WXFER ;YES - MOVE DATA TO BFR, EXIT MOV AL,BYTE PTR FLAGS AND AL,00000100B ;BIT 2,A WRITE IN PROGRESS ? JZ LAB24 CALL XWRT ;YES, WRITE OLD DATA ONTO DISK LAB24: CALL SETHST ;MAKE HOST = REQ CALL XREAD ;READ IN ALLOCATED DATA JMPS WXFER ;MOVE NEW DATA IN BFR, EXIT ; ; DIRECTORY WRITE ; WDIR: XOR AL,AL MOV BYTE PTR URCNT,AL ;CLEAR UNALC RECORD COUNT MOV AL,BYTE PTR FLAGS AND AL,11111110B ;RES 0,A RESET 'RDOP' FLAG MOV BYTE PTR FLAGS,AL AND AL,00000100B ;BIT 2,A WRITE IN PROGRESS ? JZ LAB25 CALL XWRT ;YES, WRITE OLD DATA ONTO THE DISK LAB25: MOV AL,BYTE PTR FLAGS AND AL,11111011B ;RES 2,A CLEAR 'WIP' FLAG MOV BYTE PTR FLAGS,AL CALL SETHST ;MAKE HOST = REQ CALL XREAD ;READ DIR DATA JZ LAB26 RET ;RIF READ ERROR LAB26: CALL GETDMA ;GET DMA ADR, SET POINTERS PUSH DS MOV DS, WORD PTR DMASEG ;GET THE CORRECT SEGMENT FOR [BX] MOV SI,BX CLD WDIRX: LODS AL ;<<<<<<<<<<<< OUTPUT 128 BYTES >>>>>> OUT CTDP,AL LOOP WDIRX POP DS ;GET BACK OLD VALUE OF [DS] JMPS XWRT ;WRITE DIR DATA, EXIT ; ; ---TEST HOST--- ; ; DETERMINES IF THE HOST DISK ADDRESS IS ; THE SAME AS THE REQUESTED DISK ADDRESS. ; ; TSTHST: MOV BX,(OFFSET HHTRK) CALL DSKCMP ;TRACK & DRIVE THE SAME ? JZ LAB27 RET ;RIF NO LAB27: MOV AL,BYTE PTR RSA CMP AL,BYTE PTR [BX] ;SECTOR THE SAME ? RET ;IF A = 0 THEN THEY MATCH ; ; ---SET HOST--- ; ; SETS THE HOST DISK ADDRESS TO BE THE ; SAME AS THE REQUESTED DISK ADDRESS. ; ; SETHST: MOV AL,BYTE PTR RRDSK MOV BYTE PTR HHDSK,AL ;DRIVE # MOV BX,WORD PTR RRTRK MOV WORD PTR HHTRK,BX ;TRACK ADR MOV AL,BYTE PTR RSA MOV BYTE PTR HHSEC,AL ;SECTOR ADR RET ; ; ---BUMP--- ; ; BUMPS PARAMETERS FOR UNALLOCATED WRITES. ; PARMS ARE CHANGED FOR THE NEXT PASS THRU ; THE CODE (NOT THE CURRENT PASS). ; BUMP: MOV BX,(OFFSET URCNT) ;UNALC RECORD COUNT DEC BYTE PTR [BX] ; DECR IT DEC BX ;[BX] = URSEC INC BYTE PTR [BX] ; INCR IT MOV AL,BYTE PTR [BX] CMP AL,CPMSPT ;CPM SECTORS PER TRACK JNB LAB28 RET ;RIF STAY ON SAME TRACK LAB28: ;OVERFLOW TO NEXT TRACK MOV BYTE PTR [BX],0 ;RESET SECTOR ADR MOV BX,WORD PTR URTRK INC BX ;INC TRACK ADDRESS MOV WORD PTR URTRK,BX RET ; ; ---GET DMA ADDRESS--- ; ; SETS THE CONTROLLER BUFFER ADDRESS TO THE CORRECT ; STARTING POINT. ALSO SETS CX=128 & [BX] = DMADR. ; ; GETDMA: MOV BX,WORD PTR DMADR ;DMA ADR MOV CX,128 ;BYTE COUNT MOV AL,DBENB OUT CTCSR,AL ;ENB DATA BFR MOV AL,BYTE PTR RRSEC ;REQUESTED SECTOR ROR AL,1 MOV AL,0 JNB GET1 ;JIF USE 1ST HALF OF BFR MOV AL,CL ;[CL] =128 USE 2ND HALF OF BFR GET1: OUT CTBFR,AL ;SET CTLR DATA BFR ADR RET ; ; ; ====================================== ; ** HARD DISK I/O & SUPPORT ROUTINES ** ; ====================================== ; ---READ A BLOCK--- ; XREAD: MOV BX,(OFFSET RTBL) ;READ CMD TBL CALL DORW ;READ ; XR1: MOV AL,0 JNZ LAB29 RET ;RIF READ/WRITE OK LAB29: INC AL MOV BYTE PTR ERFLG,AL ;SET ERROR FLAG RET ; ; ---WRITE A BLOCK--- ; XWRT: MOV BX,(OFFSET WTBL) ;WRITE CMD TBL CALL DORW ;WRITE A SECTOR JMPS XR1 ;SET ERROR FLAG ; ; ---EXECUTE READ/WRITE COMMANDS--- ; DORW: MOV Word Ptr CTA,BX ;SAVE CMD TBL ADR CALL XSEK ;SEEK TO NEW TRACK (IF REQUIRED) JZ PAT1 RET ;RIF SEEK FAILED PAT1: CALL XSEL ;HEAD SELECT MOV BX,Word Ptr CTA ; DO0: MOV AL,Byte Ptr [BX] MOV Byte Ptr RETRY,AL ;SET RETRY COUNT INC BX MOV AL,Byte Ptr [BX] OUT CTCSR,AL ;ENB CMP BFR INC BX MOV AL,Byte Ptr [BX] OUT CTBFR,AL ;SET CMP BFR ADR INC BX MOV Word Ptr CTA,BX ;SAVE CMD TBL ADR ; MOV BX,(Offset RCA) ;REAL TK ADR MOV CH,3 DO1: MOV AL,Byte Ptr [BX] OUT CTDP,AL ;PUT HDR INFO INTO CMP BFR INC BX DEC CH JNZ DO1 MOV AL,Byte Ptr HHSEC OUT CTDP,AL ;SET SECT ADR FOR COMPARE ; DO2: CALL XRDY ;DRIVE READY ? JZ PAT2 RET ; RIF NO PAT2: MOV BX,Word Ptr CTA ;CMD TBL ADR MOV AL,Byte Ptr [BX] ;A = CNTL BANK INC BX MOV CH,AL OUT CTCSR,AL ;SLCT CNTL BANK MOV AL,Byte Ptr [BX] OUT CTBFR,AL ;SET START ADR INC BX MOV AL,CH OR AL,START OUT CTCSR,AL ;START R/W CMD ; DO3: CALL WFD ;WAIT FOR READ/WRITE TO FINISH JNB PAT3 RET ;ABORT IF TIMEOUT PAT3: AND AL,Byte Ptr [BX] ;TEST CTLR STATUS (0=OK) MOV CH,AL IN AL,DRCSR ;DRIVE STATUS AND AL,WRTFLT JZ PAT4 CALL CLRDF ;CIF CLEAR DRIVE FAULT PAT4: OR AL,CH ;SET/CLEAR ERROR FLAG (0=OK) JNZ PAT5 RET ;RIF READ/WRITE OK PAT5: MOV BX,(Offset RETRY) DEC BYTE PTR [BX] ;DECR RETRY COUNT JNZ DO2 ;JIF RETRY READ/WRITE ; ; SET ERROR FLAG ; SEF: MOV AL,1 ;A = ERROR FLAG OR AL,AL ;SET 8080 FLAGS RET ;TAKE ERROR EXIT ; ; ---WAIT FOR DONE--- ; WFD: PUSH BX MOV BX,0 ;TIMEOUT DELAY COUNT ; WFD1: IN AL,CTCSR ;CTLR STATUS ROR AL,1 JB WFD2 ;WAIT FOR DONE DEC BX MOV AL,BH OR AL,BL JNZ WFD1 ; OUT CTCSR,AL POP BX MOV AL,1 OR AL,AL STC RET ; WFD2: POP BX IN AL,CTCSR ;GET NON-CHANGING STATUS MOV CH,AL XOR AL,AL OUT CTCSR,AL ;STOP CTLR MOV AL,CH RET ; ; ---REZERO--- ; XTKZ: MOV BX,0 MOV Word Ptr RCA,BX CALL TZT ;TEST IF TRK 0 JNZ PAT6 RET PAT6: MOV BX,511 ;#OF CYL WE CAN COUNT ON CONTROLLER CALL RTZ ;SEEK OUT JNB PAT7 RET ;ABORT DRIVE NOT READY PAT7: JNZ PAT8 RET ;IS AT 0 PAT8: MOV BX,LZONE+10-511 CALL RTZ ;TRY SECOND PUMP JNB PAT9 RET PAT9: JNZ PAT10 RET PAT10: JMPS SEF ;ABORT RESTORE FAILED ; ; SEEK OUTWARD ; RTZ: CALL XRDY STC JZ PAT11 RET PAT11: MOV AL,BL OUT LOSC,AL ;SET LSB OF SEEK COUNT MOV AL,BH OUT HISC,AL ;SET MSB MOV AL,SKOUT OUT EXTCMD,AL ;SET SEEK DIRECTION OUTWARD MOV AL,HSKCMD OUT DRCSR,AL ;ISSUE SEEK CALL WSC JNB TZT RET ; TZT: IN AL,DRCSR ;GET DRIVE STATUS AND AL,TK00 XOR AL,TK00 RET ; XSTZ: MOV AL,BYTE PTR FLAGS AND AL,00000100B JNZ XSTZ1 MOV BYTE PTR FLAGS,AL XSTZ1: MOV BX,0 MOV WORD PTR RRTRK,BX XOR AL,AL RET ; ; ; ---SEEK--- ; XSEK: MOV AL,3 MOV Byte Ptr SKRTC,AL ;SET SEEK RETRY COUNT ; XSEK1: MOV BX,Word Ptr HHTRK ;REQUESTED TRACK SHR BX,1 CMP BX,MAXCYL JNAE XSEK2 JMP SEF ;ABORT IF INVALID ADDRESS ; XSEK2: MOV DX,Word Ptr RCA ;LOAD UP CURRENT REAL ADR MOV Word Ptr RCA,BX ;SAVE NEW ADDRESS XCHG BX,DX SUB BX,DX JNZ PAT14 RET ;RETURN IF SAME PAT14: MOV CH,1 ;DIR = OUT JNB XSEK3 ;OK SEEK OUTWARD ; MOV CH,3 ;SEEK INWARD MOV AL,BL NOT AL ;MAKE SEEK POSITIVE MOV BL,AL MOV AL,BH NOT AL MOV BH,AL INC BX ; XSEK3: MOV AL,CH ;GO TO SEEKING INWARD MOV Byte Ptr SKDIR,AL MOV DX,512 CMP BX,DX JNB XSEK4 ;JIF DOUBLE PUMP IS REQ CALL PSK ;DO PARTIAL SEEK JZ PAT15 RET PAT15: JMPS XSEK5 ; XSEK4: DEC DX ;DX = 511 SUB BX,DX MOV Word Ptr RSKNT,BX ;SAVE RESIDUAL COUNT XCHG BX,DX CALL PSK JZ PAT16 RET ;ABORT IF SEEK FAILED PAT16: MOV BX,Word Ptr RSKNT CALL PSK ;SEND THE REST JZ XSEK5 RET ; ; ;SEEK VERIFY XSEK5: MOV AL,3 MOV Byte Ptr VSRTC,AL ;SET RETRY COUNT MOV AL,CBENB OUT CTCSR,AL ;ENABLE BANK ZERO CMP BFR MOV AL,VCA OUT CTBFR,AL ;SET CMP BFR ADR MOV BX,Word Ptr RCA ;REAL (CURR) CYL ADR MOV AL,BL OUT CTDP,AL ;SET CYL ADR, LSB MOV AL,BH OUT CTDP,AL ;SET CYL ADR, MSB XSEK6: MOV AL,VSA OUT CTBFR,AL ;SET M/CODE START ADR MOV AL,START OUT CTCSR,AL ;START VERIFY CALL WFD ;WAIT FOR DONE AND AL,0CH ;TEST CTLR STATUS JNZ PAT18 RET ;RIF VERIFY OK PAT18: MOV BX,(Offset VSRTC) DEC BYTE PTR [BX] ;DECR RETRY COUNT JNZ XSEK6 ;JIF RETRY SEEK VERIFY ; VERIFY FAILED CALL XTKZ ;RESTORE MOV BX,(Offset SKRTC) DEC BYTE PTR [BX] ;DECR RETRY COUNT JZ PAT19 JMP XSEK1 ;JIF RETRY SEEK PAT19: OR AL,1 ;SET ERROR FLAG RET ;ABORT ; ; PARTIAL SEEK ; PSK: CALL XRDY ;DRIVE READY ? JZ PAT20 RET PAT20: MOV AL,BL OUT LOSC,AL ;SET SEEK COUNT, LSB MOV AL,BH OUT HISC,AL ; * MSB MOV AL,Byte Ptr SKDIR OUT EXTCMD,AL ;SET SEEK DIRECTION MOV AL,3 OUT DRCSR,AL ;ISSUE SEEK CMD ; ; ---> FALL THRU TO 'WSC' <--- ; ; ---WAIT FOR SEEK COMPLETE--- ; ; WSC: PUSH BX ;SAVE REGS PUSH CX MOV BX,0 ;TIME-OUT DELAY COUNT MOV CH,6 ;WAS 3 FOR XCOMP;..DITTO ; WSC1: IN AL,DRCSR ;DRIVE STATUS RCL AL,1 JB WSC2 ;JIF SEEK DONE DEC BX ;DECR DELAY COUNT MOV AL,BH OR AL,BL JNZ WSC1 ;JIF CON'T WAITING DEC CH JNZ WSC1 ; TIME-OUT ERROR POP CX ;RESTORE REGS POP BX MOV AL,1 OR AL,AL ;SET CPM ERROR FLAG STC ;SET INTERNAL ERROR FLAG RET ; WSC2: POP CX ;RESTORE REGS POP BX XOR AL,AL ;SET FLAG = OK RET ; ; ; ; ---CLEAR DRIVE FAULT--- ; CLRDF: XOR AL,AL OUT EXTCMD,AL ;DE-SELECT (FALL THRU TO 'XSEL' TO ;RE-SELECT THE DRIVE) ; ; ---HEAD SELECT--- ; XSEL: MOV AL,Byte Ptr HHTRK ;REQUESTED TRACK AND AL,1 ;2 HEADS MOV Byte Ptr RHD,AL ;SAVE REAL HEAD # ADD AL,AL ;SHIFT HEAD # LEFT TWICE FOR H/W ADD AL,AL OR AL,1 ;TO MAINTAIN DRIVE SLCT OUT EXTCMD,AL ;SELECT HEAD 0 OR 1 RET ; ; ---DRIVE READY TEST--- ; XRDY: IN AL,DRCSR ;DRIVE STATUS AND AL,1 ;DRIVE RDY BIT XOR AL,1 ; MAKE IT LO-TRUE JNZ PAT21 RET ;RIF DRIVE READY PAT21: OR AL,1 ;SET ERROR FLAG RET ; DSKCMP: MOV DX,(OFFSET RRTRK) ;GET REQUESTED TRACK MOV CH,3 DC1: MOV SI,DX MOV AL,[SI] CMP AL,BYTE PTR [BX] JZ LAB43 RET LAB43: INC BX INC DX DEC CH JNZ DC1 RET ; ; ; ====================================== ; FLOPPY DISK ROUTINES ; ====================================== ; FSELDSK:DEC AL ;FOR FLOPPY MAKE B:=A: (OR C:== B:) MOV CL,AL ; (NOTE A:, B: & C: DRIVES ONLY) OR AL,AL ;IF REQ DRIVE IS A: THEN [A] = 0 JNZ BBBB ;MUST BE B: DRIVE MOV AL,BYTE PTR ADRIVE ;IS IT THE FIRST TIME FOR THIS DRIVE CMP AL,0FFH JNZ LAB44 CALL GETTYPE LAB44: MOV BYTE PTR ADRIVE,AL ;STORE DENSITY FLAG JMPS ALLOK BBBB: MOV AL,BYTE PTR BDRIVE ;IS IT THE FIRST TIME FOR THIS DRIVE CMP AL,0FFH JNZ LAB45 CALL GETTYPE LAB45: MOV BYTE PTR BDRIVE,AL ;STORE DENSITY FLAG ; ALLOK: OR AL,CL ;MIX DRIVE TYPE WITH DRIVE# MOV BYTE PTR UNIT,AL ;STORE IT FOR SECTOR R/W ROUTINES ETC TEST AL,40H ;BIT 6,A JNZ LAB46 MOV AL, BYTE PTR RRDSK ;GET ORRIGIONAL DISK REQUESTED RET ;RET WITH TABLE OFFSET B:=B: & C:=C: ; LAB46: MOV AL,00000011B ;FOR DOUBLE DENS DISKS WE MUST USE ADD AL,CL ;THE LOOKUP TABLE FOR DRIVES D: & E: RET ;RETURNS TABLE OFFSET B:=D: & C:=E: ; GETTYPE:MOV AL,CL ;FIND OUT TYPE OF DRIVE CALL UNITSL JNZ HB101 ;IF NZ PROBLEMS ABORT MOV AL,BYTE PTR UNIT AND AL,01000000B ;GET DENSITY FLAG RET ; HB101: MOV BX,0 ;ABORT BECAUSE CANNOT GET DISK TYPE POP AX ;DROP STACK BACK ONE LEVEL XOR AL,AL ;JUST IN CASE DEC AL RET ; THIS ROUTINE SETS UP THE FLOPPY DISK UNIT BYTE ; THE REQUIRED DRIVE IS IN [A] ; UNITSL: MOV CH,5 ;WILL TRY 5 TIMES AND AL,0FH OR AL,40H ;COME UP DEFALT IN 8" DD MOV BYTE PTR UNIT,AL MOV BX,WORD PTR DMADR MOV WORD PTR TEMP2,BX CALL USL1 MOV BX,WORD PTR TEMP2 MOV WORD PTR DMADR,BX MOV AL,BYTE PTR UNIT RET ; USL1: PUSH CX PUSH BX MOV WORD PTR SPSV,SP ;TEMP SAVE SP IN SPSV POP BX CALL DRVSET ;SELECT DRIVE IN HARDWARE CALL IDRD ;TRY READING TRACK ID POP CX JNZ LAB48 RET ;IF CORRECT DENSITY WILL BE Z LAB48: DEC CH ;DECREASE 5.......0 IF Z THEN ERROR JZ SPECIAL CALL CHGTYP JMPS USL1 ; SPECIAL:XOR AL,AL ;MAY FOR SPECIAL SECTOR SIZE ETC DEC AL RET ;RET NZ SO SELDSK KNOWS WAS PROBLEM ; CHGTYP: MOV AL,BYTE PTR UNIT ADD AL,01000000B ;TOGGLE DENSITY BIT AND AL,01111111B ;CLEAR BIT 7 MOV BYTE PTR UNIT,AL RET ; ; READ A SECTOR FREAD: MOV CX,301H READ1: PUSH CX CALL RDSC POP CX JNZ LAB49 RET LAB49: CALL FRETRY JMPS READ1 ; ; WRITE A SECTOR FWRITE: MOV CX,301H ;RTRY= 3 RSEEK = 1 WRITE1: PUSH CX CALL WRSC POP CX JNZ LAB50 RET LAB50: CALL FRETRY JMPS WRITE1 ; FRETRY: DEC CH JNZ RETRY2 MOV AL,BYTE PTR RTRY MOV CH,AL DEC CL JNS RETRY1 POP AX ;DROP STACK BACK ONE LEVEL XOR AL,AL ;IF PROBLEM INC AL RET ; RETRY1: PUSH CX CALL HOME1 POP CX RETRY2: RET ; HOME1: MOV WORD PTR SPSV,SP MOV AL,RSCMD CALL SEEK4 XOR AL,AL RET ; ; SELECT DRIVE IN HARDWARE ; DRVSET: MOV DX,OFFSET UNIT PUSH SI MOV SI,DX MOV AL,[SI] AND AL,0E0H MOV CL,AL ;STORE DRIVE TYPE IN [CL] MOV SI,DX MOV AL,[SI] AND AL,03 MOV CH,AL ;STORE DRIVE # IN [CH] MOV AL,1 JZ DRVSEL CKDRV1: ROL AL,1 DEC CH JNZ CKDRV1 DRVSEL: OR AL,CL ;COMBINE TYPE & DRIVE# AND AL,7FH MOV CH,AL ;[CH] CONTAINS INFO FOR HARDWARE MOV AL,STDSDT ;SETUP FOR SD MOV BYTE PTR COUNT,AL ;STORE AS 26 SECTORS/TRACK MOV AL,40H ;WAS IT DD DRV1: CMP AL,CL JNZ CKDRV MOV AL,STDDDT ;SETUP FOR DD MOV BYTE PTR COUNT,AL ;SET TO 50 SECTORS/TRACK CKDRV: MOV AL,CH ;GET HARDWARE SELECT DATA NOT AL ;HARDWARE IS INVERTED OUT SELECT,AL MOV SI,DX MOV AL,[SI] MOV BYTE PTR UNITCK,AL CALL DELAY POP SI RDYCK: IN AL,STATUS AND AL,80H JNZ END2X RET END2X: JMP END2 ; ; READ PRESENT DISK ADDRESS IDRD: CALL WAIT MOV BX,OFFSET IDSV ;WILL STORE THE 6 ID BYTES HERE MOV CX,6 ;READ 6 BYTES MOV AL,0F8H MOV BYTE PTR ERMASK,AL CALL SWEB MOV AL,RDACMD ;DO THE ID READ CALL RDSCO MOV AL,BYTE PTR IDSV CMP AL,NTRKS ;IS IT REASONABLE JNAE LAB51 JMP SEEK0 LAB51: OUT TRACK,AL XOR AL,AL RET ; DELAY: MOV AL,040H ;DELAY ~32 MS (SEEMS NOT CRITICAL) DELAY1: MOV CH,0 M0: DEC CH JNZ M0 DEC AL JNZ DELAY1 RET ; ; READ SECTOR COMMAND RDSC: CALL DRINIT MOV AL,RDCMD RDSCO: MOV BYTE PTR CMDSV,AL CLI OUT CMD,AL PUSH ES PUSH DI MOV ES,WORD PTR DMASEG ;GET CORRECT SEGMENT MOV DI,BX CLD RDSCX: IN AL,DATA ;>>>>>>>>>>READ 128 BYTES<<<<<<<<<<<< STOS AL ;NOTE POINTER IS [ES] [DI] LOOP RDSCX POP DI POP ES ;GET BACK OLD VALUE OF [DS] STI JMPS ENDX ; ; ; WRITE SECTOR COMMAND WRSC: CALL DRINIT MOV AL,WRCMD MOV BYTE PTR CMDSV,AL CLI OUT CMD,AL PUSH DS PUSH SI MOV DS, WORD PTR DMASEG ;GET CORRECT SEGMENT MOV SI,BX CLD WRSCX: LODS AL ;>>>>>>>>> WRITE 128 BYTES <<<<<<<<< OUT DATA,AL LOOP WRSCX POP SI POP DS ;GET BACK OLD VALUE OF [DS] STI ; ; END OF COMMAND ENDX: CALL WAIT IN AL,STATUS MOV DH,AL MOV AL,BYTE PTR ERMASK AND AL,DH JNZ END1 RET END1: MOV AL,DH END2: MOV BYTE PTR ERSTAT,AL CALL DELAY MOV SP,WORD PTR SPSV XOR AL,AL DEC AL ;RETURN NZ TO INDICATE AN ERROR MOV BYTE PTR UNITCK,AL RET ; ; ; DRIVE INITIALIZATION ; DRINIT: POP BX MOV WORD PTR SPSV, SP PUSH BX MOV AL,BYTE PTR UNIT MOV DH,AL MOV AL,BYTE PTR UNITCK CMP AL,DH JZ DINIT1 CALL DRVSET CALL IDRD DINIT1: CALL SEEK MOV AL,0FEH MOV BYTE PTR ERMASK,AL ; TRINT: MOV BX,WORD PTR DMADR ;SETUP DMA ADDRESS AND BYTE COUNT MOV AL,BYTE PTR RRSEC OUT SECTOR,AL MOV CX,NBYTES ;USED BY LOOP INST IN SEC RD/WRT ; SWEB: IN AL,SELECT ;ENABLE WAIT STATES AND AL,7FH OUT SELECT,AL RET ; ; SEEK TRACK ; SEEK: CALL RDYCK MOV CL,NTRKS ;MUST BE REASONABLE TRACK # MOV AL,BYTE PTR RRTRK ;ALWAYS < 0FFH TRACKS FOR FLOPPY CMP AL,CL JB SEEK1 SEEK0: MOV AL,0FH JMPS END2 SEEK1: MOV CL,AL IN AL,TRACK CMP AL,CL JNZ LAB53 RET ;IF SAME TRACK NO NEED TO SEEK LAB53: MOV AL,SKCMD SEEK4: MOV BYTE PTR CMDSV,AL MOV CH,210 S0: DEC CH JNZ S0 CALL WAIT MOV AL,BYTE PTR RRTRK OUT DATA,AL MOV AL,80H MOV BYTE PTR ERMASK,AL MOV AL,BYTE PTR CMDSV OUT CMD,AL MOV CH,10 D0: DEC CH JNZ D0 CALL ENDX CALL DELAY MOV AL,BYTE PTR CMDSV CMP AL,RSCMD ;NO NEED TO CHECK RESTORE COMMAND JNZ LAB54 RET LAB54: IN AL,STATUS AND AL,10H JNZ SEEK2 IN AL,TRACK CMP AL,CL JNZ SEEK2 RET SEEK2: MOV AL,20H END2JP: JMP END2 ; WAIT: MOV DL,0 PUSH CX MOV CL,2 WAIT2: IN AL,STATUS AND AL,1 JZ DWAIT DEC CH JNZ WAIT2 DEC DL JNZ WAIT2 DEC CL JNZ WAIT2 POP CX IN AL,SELECT ;IF BY THIS TIME NOT READY FORCE OR AL,80H ;A HARDWARE RESET OUT RSET,AL F0: DEC CH JNZ F0 IN AL,RSET CALL FRCINT MOV AL,RSCMD CALL SEEK4 MOV AL,0FEH JMPS END2JP ; ; DISABLE WAIT STATES DWAIT: POP CX ;TO BALANCE THE ABOVE PUSH IN WAIT IN AL,SELECT OR AL,80H OUT SELECT,AL RET ; ; ; ; FORCE CHIP INTERUPT FRCINT: MOV AL,0D0H OUT CMD,AL MOV AL,10 FRC1: DEC AL JNZ FRC1 IN AL,STATUS RET ; ;>>>>>>>>>>>>>>>> MDISK SECTOR READ AND WRITE ROUTINES <<<<<<<<<<<<<<<<< ; MREAD: MOV CL,RDSECTOR ;[CL] = READ SECTOR COMMAND CALL MRDCMD ;SEND IT TO THE RAMDISK JNB MRDERR JMP RWERR ;IF FAIL TO SEND THEN ERROR ROUTINE. MRDERR: CALL SEND@TRKSEC ;ELSE SEND TRACK AND SECTOR TO RAMDSK ;SET UP REGS FOR SECTOR TRANSFER: MOV BX,WORD PTR DMADR ;[BX] = DMA ADDRESS PUSH ES ;CPM86 DOES NOT SAVE ES IN BDOS MOV ES,WORD PTR DMASEG MOV CX,NBYTES ;[CX] = 128 = # BYTES TO READ MOV DI,BX ;>>>>>>>>> INPUT 128 BYTES <<<<<<<< RDLOOP: CALL RDREAD ;GET NEXT SECTOR BYTE STOS AL ;DEPOSIT INTO MEMORY LOOP RDLOOP ;LOOP FOR ALL BYTES [CX TO 0] POP ES ;GET BACK ES CALL RDREAD ;GET THE RESULT BYTE OR AL,AL ;SHOULD BE ALL 0 BITS IF GOOD R/W JZ MDONE JMP RWERR ;[A] = 0 ON RETURN IF GOOD R/W MDONE: RET ; ; MWRITE: MOV CL,WRTSECTOR ;[CL] = WRITE SECTOR COMMAND CALL MRDCMD MOV BX,(OFFSET MD@OFFLINE) ;IF RAMDISK OFFLINE SAY SO JNB MWNER JMP RWERR1 MWNER: CALL SEND@TRKSEC ;ELSE SEND TRACK AND SECTOR TO RAMDSK ;SET UP REGS FOR SECTOR TRANSFER: MOV BX,WORD PTR DMADR ;[BX] = DMA ADDRESS PUSH DS MOV DS,WORD PTR DMASEG MOV CX,NBYTES ;[CX] = 128 = # BYTES TO READ MOV SI,BX ;>>>>>>>>> OUTPUT 128 BYTES <<<<<<<< WRLOOP: LODS AL MOV AH,AL ;TEMP STORE DATA HERE WRLOOP1:IN AL,CTRLPORT ;GET STATUS BYTE AND AL,1 ;CHECK FOR RAMDISK READY TO RECEIVE JZ WRLOOP1 MOV AL,AH OUT DATAPORT,AL LOOP WRLOOP ;LOOP FOR ALL BYTES [CX TO 0] POP DS ;GET BACK DS CALL RDREAD ;GET THE RESULT BYTE OR AL,AL ;SHOULD BE ALL 0 BITS IF GOOD R/W JZ MDONE JMP RWERR ;[A] = 0 ON RETURN IF GOOD R/W ; ;SENDS THE TRACK AND SECTOR FOR THE NEXT R/W OPERATION TO THE SEND@TRKSEC: MOV CX,WORD PTR RRSEC ;GET THE SECTOR TO [BC] CALL RDWRITE ;SEND THE LOW BYTE FIRST MOV CL,CH ;THEN THE HIGH BYTE CALL RDWRITE MOV CX,WORD PTR RRTRK ;GET TRACK # TO [CL] JMPS RDWRITE ;SEND IT AND RETURN... ; ; ROUTINE SENDS A CHARACTER TO THE RAMDISK: RDWRITE: IN AL,CTRLPORT ;GET STATUS BYTE AND AL,1 ;CHECK FOR RAMDISK READY TO RECEIVE JZ RDWRITE MOV AL,CL ;GET OUTPUT BYTE OUT DATAPORT,AL ;SEND IT RET ; ; ROUTINE READS 1 CHARACTER FROM THE RAMDISK: RDREAD: IN AL,CTRLPORT ;WAIT UNTIL PORT IS READY AND AL,80H JZ RDREAD ;LOOP UNTIL INPUT STATUS IS TRUE IN AL,DATAPORT ;GET CHARACTER WAITING RET ; ; ROUTINE GETS RAMDISK INPUT STATUS: RDINSTAT:IN AL,CTRLPORT ;GET STATUS BYTE AND AL,80H ;SEE IF DATA WAITING RET ;WITH STATUS Z FLAG ; ; ROUTINE SENDS A COMMAND TO THE RAMDISK: MRDCMD: CALL RDWRITE ;SEND COMMAND TO THE RAMDISK CALL RDWAIT ;WAIT FOR ECHO JNB LM4 RET ;RETURN ON TIMEOUT OR NO BYTE MATCH.. LM4: MOV AL,CL ;GET COMMAND JUST SENT NOT AL ;AND COMPLEMENT IT MOV CL,AL CALL RDWRITE ;SEND IT CALL RDWAIT ;WAIT FOR ECHO RET ;WITH FLAGS SET ; ; ROUTINE WAITS FOR ECHO RESPONSE FROM HOST FOR A SPECIFIED DELAY ; TIME AND IF NO RESPONSE IS GOTTEN IT RETURNS WITH AN ERROR FLAG: RDWAIT: PUSH CX ;SAVE [CX] MOV CX,CMDDLY ;LOAD DELAY CONSTANT RDW0: CALL RDINSTAT ;GET INPUT STATUS JNZ RDW2 ;Z = 0 MEANS WE GOT SOMETHING DEC CX ;ELSE DROP DELAY COUNT MOV AL,CL ;CHECK FOR DELAY TIMEOUT OR AL,CH JNZ RDW0 ;KEEP CHECKING HOST IF NO TIMEOUT RDW1: POP CX ;SYNCHRONIZE STACK RDW1A: STC ;SET ERROR FLAG RET RDW2: CALL RDREAD ;GET ECHOED CHARACTER POP CX ;CHARACTER SENT BACK TO [CX] CMP AL,CL ;IS ECHOED CHAR = CHAR SENT ? JNZ RDW1A ;NO -- RETURN ERROR... RET ; ; R/W ERROR HERE TO INSPECT RESULT BYTE BITS FOR MESSAGE TO DISPLAY: RWERR: TEST AL,01000000B JZ RW3 MOV BX,(OFFSET MD@WP) RWERR1: CALL PMSG ;DISPLAY MESSAGE IF SO RWERR2: MOV AL,1 ;RETURN ONLY 0 OR 1 FOR CPM86 RET ; RW3: TEST AL,10000000B ;CHECK FOR TRACK / SECTOR ERROR MOV BX,(OFFSET MD@TRKSEC) JNZ RWERR1 ; TEST AL,00100000B ;CHECKSUM ERROR ? MOV BX,(OFFSET MD@CKSUM) JNZ RWERR1 ; JMP RWERR2 ;UNKNOWN ERROR ; ; ;<<<<<<<<<<<<<<<<<<<<<< MAIN CONSOL OUTPUT ROUTINE >>>>>>>>>>>>>>>>>>>>>>>>> ; NOTE THIS CODE IS SPECIFIC FOR MY SYSTEM ; CO: IN AL,IOBYTE TEST AL,1H ;BIT 0,A CHECK IF OUTPUT TO LIST IS ALSO REQ JZ LOX TEST AL,8H ;BIT 3,A CHECK IF PRINTER IS CONSOL JNZ COX1 JMP LO COX1: TEST AL,10H ;BIT 4,A KILL LF'S IF THIS IS 0 JNZ SDCONO MOV AL,CL CMP AL,LF JZ SDCON5 ;KILL LF'S PUSH CX ;ALL OTHERE CHARACTRS SEND EOL THEN CHARACTER MOV CL,']'-40H ;FOR CLEAR TO END OF LINE CALL SDCONO ;BECAUSE EOL IS SENT FOR EACH CHARACTER THE POP CX ;TYPE RATE IS NICELY SLOWED DOWN TO ~ 60 BAUD JMPS SDCONO ;AT NO FURTHER EXPENSE | SDCON5: MOV AL,CL RET ; LOX: CALL SDCONO ;OUTPUT TO BOTH PRINTER & CONSOLE JMP LO ; SDCONO: IN AL,SDSTAT ;SD SYSTEMS VIDIO BOARD PORT AND AL,4H JZ SDCONO MOV AL,CL CMP AL,07H ;IS IT A BELL JZ BELL1 CMP AL,0H ;SD BOARD CANNOT TAKE A NULL JNZ LX2 RET LX2: OUT SDDATA,AL IN AL,IOBYTE TEST AL,20H ;BIT 5,A SEE IF TIME DELAY REQ WITH CO: JNZ LX3 MOV AL,20 CALL TDELAY LX3: MOV AL,CL ;BE SURE TO RETURN WITH [AL] CONTAINING CHAR RET ; BELL1: MOV AL,06H ;SEND A BELL OUT SDDATA,AL MOV AL,3FH CALL TDELAY MOV AL,CL OUT SDDATA,AL RET ; ; TDELAY: DEC AL ;GENERAL COUNT DOWN TIME DELAY JNZ LX4 RET ;LENGTH SET IN [A] LX4: PUSH AX MOV AL,05H MORE: DEC AL PUSH AX XOR AL,AL MORE2: DEC AL JNZ MORE2 POP AX JNZ MORE POP AX JMPS TDELAY ; ; ;<<<<<<<<<<<<<<<<<<< MAIN CONSOL STATUS ROUTINE >>>>>>>>>>>>>>>>>>>>>> ; CSTS: IN AL,KEYSTAT AND AL,02H JNZ CST1 RET ;RETURN WITH 0 IN [A] IF NOTHING THERE CST1: DEC AL RET ;RETURN WITH 0FFH IN [A] IF SOMETHING ; ; ;<<<<<<<<<<<<<<<<<<<< MAIN CONSOL INPUT ROUTINE >>>>>>>>>>>>>>>>>>>> ; CI: CALL CSTS ;NEED CONSTAT TO CLEAN UP SHIFT KEYS ETC JZ CI IN AL,KEYIN AND AL,7FH RET ; ;<<<<<<<<<<<<<<<<<<<<<< MAIN PRINTER STATUS ROUTINE >>>>>>>>>>>>>>>>>>>>>>>>> ; LSTAT: IN AL,CENTSTAT ;FIRST FIND WHICH PRINTER IS SELECTED TEST AL,2 JNZ CENSTAT TEST AL,20H JNZ TRANSTAT XOR AL,AL ;NONE SELECTED DEC AL RET CENSTAT:AND AL,00001111B ;XXXX0110 IS READY (BIT 3=PAPER BIT 2=FAULT CMP AL,00000110B ;BIT 1=SELECT BIT 0=BUSY JZ LSTAT1 XOR AL,AL RET TRANSTAT:AND AL,11110000B ;0110XXX IS READY (BIT 7=ALERT BIT 6=FAULT CMP AL,01100000B ;BIT 5=SELECT BIT 4=BUSY JZ LSTAT1 XOR AL,AL RET LSTAT1: XOR AL,AL ;PUT 0FFH IN [A] IF READY & NO ZERO FLAG DEC AL RET ; ;<<<<<<<<<<<<<<<<<<<<<< MAIN PRINTER OUTPUT ROUTINE >>>>>>>>>>>>>>>>>>>>>>>>> ; LO: CALL LSTAT JZ LO MOV AL,0FFH OUT CENTSTROBE,AL MOV AL,CL OUT CENTOUT,AL IN AL,CENTSTAT TEST AL,2 JNZ LCENT TEST AL,20H JNZ LTRANS RET ;NO STROBE SINCE NOT SELECTED ; LCENT: MOV AL,11111110B ;STROBE FOR CENTRONICS JMPS OVERLS LTRANS: MOV AL,11111101B OVERLS: OUT CENTSTROBE,AL MOV AL,0FFH OUT CENTSTROBE,AL RET ; ; POO: RET ;NO PUNCH OUTPUT AT THE MOMENT RI: MOV AL,1AH ;NO READER AT THE MOMENT RET ; SCO: MOV AL,15H ;SEND CHARACTER TO TALKER OUT TALKSTAT,AL IN AL,TALKSTAT AND AL,02H JZ SCO MOV AL,CL OUT TALKOUT,AL RET ; SMSG: MOV AL,[BX] ;SPEAK A STRING TEST AL,AL JZ RETURS MOV CL,AL CALL SCO INC BX JMP SMSG RETURS: MOV CL,CR JMP SCO ; ; ; LAB57 EQU $ ; ;---------------------> START OF DATA SEGMENT <--------------------- ; ; DSEG ORG OFFSET LAB57 ; ; ; ---MESSAGES--- ; ; SIGNON DB 1AH,1H,10H,11H,LF,09H,09H DB '128K CP/M-86 V1.1 (With Intelladisk)',CR,LF CLEANUP DB 1H,10H,11H,17H,07H,0H SPEAKON DB '1 HUNDRED AND TWENTY EIGHT KAY C P M EIGHTY SIX ',0 DRNRDY DB CR,LF,'DRIVE NOT READY',0 INT_TRP DB CR,LF,'INTERRUPT TRAP HALT AT:- ',0H INT0_TRP DB CR,LF,'DIVIDE TRAP HALT AT:- ',0H INT4_TRP DB CR,LF,'OVERFLOW TRAP HALT AT:- ',0H ; ; MEMORY DISK ERROR MESSAGES: MD@OFFLINE DB ' MEMORY DISK APPEARS TO BE OFFLINE',0 MD@WP DB ' MEMORY DISK WRITE-PROTECTED',0 MD@CKSUM DB ' MEMORY DISK CHECKSUM ERROR',0 MD@TRKSEC DB ' MEMORY DISK TRACK / SECTOR OUT OF RANGE',0 ; ; ; ---MICROCODE COMMAND TABLES FOR XCOMP CONTROLLER--- ;WRITE WTBL DB 5 ;RETRY COUNT DB 5 ;CMP BFR ENB DB 0E6H ;CMP BFR ADR DB BANK1 ;CNTL BANK DB 0D3H ;START ADR DB 0EH ;STATUS MASK ; ;READ RTBL DB 10 ;RETRY COUNT DB 4 ;CMP BFR ENB DB 0EAH ;CMP BFR ADR DB BANK0 ;CNTL BANK DB 0D7H ;START ADDRESS DB 0EH ;STATUS MASK ; ---PROGRAM STORAGE--- ; SEGTABLE DB 1 ;SYSTEM MEMORY TABLE DW TPASEG ;FIRST SEGMENT STARTS AFTER BIOS DW TPALEN ;AND GOES UP TO 01FFFH ; ; --- DISK DEFINITIONS TABLE --- ; ; DISKS 6 DPHDR EQU $ ;BASE OF DISK PARAMETER BLOCKS DPE0 DW 0000,0000H ;TRANSLATE TABLE (NONE FOR HARD DISK) DW 0000H,0000H ;SCRATCH AREA DW DIRBUF,DPB0 ;DIR BUFF, PARM BLOCK DW CSV0,ALV0 ;CHECK, ALLOC VECTORS DPE1 DW XLT1,0000H ;TRANSLATE TABLE (SD FLOPPY) DW 0000H,0000H ;SCRATCH AREA DW DIRBUF,DPB1 ;DIR BUFF, PARM BLOCK DW CSV1,ALV1 ;CHECK, ALLOC VECTORS DPE2 DW XLT2,0000H ;TRANSLATE TABLE (SD FLOPPY) DW 0000H,0000H ;SCRATCH AREA DW DIRBUF,DPB2 ;DIR BUFF, PARM BLOCK DW CSV2,ALV2 ;CHECK, ALLOC VECTORS DPE3 DW 0000,0000H ;TRANSLATE TABLE (DD FLOPPY) DW 0000H,0000H ;SCRATCH AREA DW DIRBUF,DPB3 ;DIR BUFF, PARM BLOCK DW CSV3,ALV3 ;CHECK, ALLOC VECTORS DPE4 DW 0000,0000H ;TRANSLATE TABLE (DD FLOPPY) DW 0000H,0000H ;SCRATCH AREA DW DIRBUF,DPB4 ;DIR BUFF, PARM BLOCK DW CSV4,ALV4 ;CHECK, ALLOC VECTORS DPE12 DW 0000,0000H ;TRANSLATE TABLE (NOT USED FOR RAMDISK) DW 0000,0000H ;SCRATCH AREA DW DIRBUF,MD@DPB ;DIR BUFFER PARM BLOCK DW CSV12,ALV12 ;CHECK, ALLOC VECTORS FOR RAMDISK ; ; ; DISKDEF 0,0,63,0,2048,3992,1024,0,2 ; DPB0 EQU OFFSET $ ;DISK PARAMETER BLOCK DW 64 ;SECTORS PER TRACK DB 4 ;BLOCK SHIFT DB 15 ;BLOCK MASK DB 0 ;EXTNT MASK DW 3991 ;DISK SIZE - 1(1000-2tracks x 4blks/track -1) DW 1023 ;DIRECTORY MAX DB 255 ;ALLOC0 DB 255 ;ALLOC1 DW 0 ;CHECK SIZE DW 2 ;OFFSET ; ; DISKDEF 1,1,26,6,1024,243,64,64,2 ; DPB1 EQU OFFSET $ ;DISK PARAMETER BLOCK DW 26 ;SECTORS PER TRACK DB 3 ;BLOCK SHIFT DB 7 ;BLOCK MASK DB 0 ;EXTNT MASK DW 242 ;DISK SIZE - 1 (75tracks x 3.25bkks/trk -1) DW 63 ;DIRECTORY MAX DB 192 ;ALLOC0 DB 0 ;ALLOC1 DW 16 ;CHECK SIZE DW 2 ;OFFSET XLT1 EQU OFFSET $ ;TRANSLATE TABLE DB 1,7,13,19 DB 25,5,11,17 DB 23,3,9,15 DB 21,2,8,14 DB 20,26,6,12 DB 18,24,4,10 DB 16,22 ; ; DISKDEF 2,1 ; DPB2 EQU DPB1 ;EQUIVALENT PARAMETERS XLT2 EQU XLT1 ;SAME TRANSLATE TABLE ; ; DISKDEF 3,1,50,0,2048,234,64,64,2 ; DPB3 EQU OFFSET $ ;DISK PARAMETER BLOCK DW 50 ;SECTORS PER TRACK DB 4 ;BLOCK SHIFT DB 15 ;BLOCK MASK DB 1 ;EXTNT MASK DW 233 ;DISK SIZE - 1 DW 63 ;DIRECTORY MAX DB 128 ;ALLOC0 DB 0 ;ALLOC1 DW 16 ;CHECK SIZE DW 2 ;OFFSET ; ; ; DISKDEF 4,3 ; DPB4 EQU DPB3 ;EQUIVALENT PARAMETERS ; ; DISKDEF 12,1,480,1,2048,960,128,128,0 ; MD@DPB equ offset $ ;Disk Parameter Block dw 480 ;Sectors Per Track db 4 ;Block Shift db 15 ;Block Mask DPB_EXM RS 1 ;Extnt Mask DPB_DSM RS 2 ;Disk Size - 1 (WHEN FULL RAM 959) dw 127 ;Directory Max db 192 ;Alloc0 db 0 ;Alloc1 dw 32 ;Check Size dw 0 ;Offset ; ; Uninitialized Scratch Memory Follows: ; ; FLAGS RS 1 ;BIT FLAGS ;BIT 0 SET FOR READ OPERATION ;BIT 1 SET FOR READ IN PROGRESS ;BIT 2 SET FOR WRITE IN PROGRESS ; RRTRK RS 2 ;CP/M REQUESTED TRACK ADDRESS RRDSK RS 1 ;CP/M REQUESTED DRIVE # RRSEC RS 2 ;CP/M REQUESTED SECTOR ; URTRK RS 2 ;UNALLOCATED TRACK ADDRESS URDSK RS 1 ; DRIVE # URSEC RS 1 ; SECTOR ADDRESS URCNT RS 1 ; RECORD COUNT ; HHTRK RS 2 ;HOST (SCRIBE & SHUGART) TRACK ADDRESS HHDSK RS 1 ; DRIVE # HHSEC RS 1 ; SECTOR ADDRESS ; RCA RS 2 ;REAL TRACK ADDRESS RHD RS 1 ; HEAD RSA RS 1 ; SECTOR ; RETRY RS 1 ;RETRY COUNT CTA RS 2 ;COMMAND TABLE ADDRESS ERFLG RS 1 ;ERROR FLAG DMADR RS 2 ;BUFFER (DMA) ADDRESS WRTMODE RS 1 ;WRITE MODE SKRTC RS 1 ;SEEK RETRY COUNT VSRTC RS 1 ;SEEK VEREFY RETRY COUNT SKDIR RS 1 ;SEEK DIRECTION RSKNT RS 2 ;RESIDUAL SEEK COUNT TEMP RS 2 ;TEMPORARY STORAGE IOBYT RS 1 ;STORAGE FOR IOBYTE DMASEG RS 2 ;STORAGE FOR CURRENT SEGMENT ADDRESS ;--- UNIT RS 1 ;STORE FOR FLOPPY NEW UNIT BYTE ERMASK RS 1 ;FLOPPY ERROR MASK ERSTAT RS 1 ;STORE OF ERROR FLAG CMDSV RS 1 ;FLOPPY COMMAND STORE SPSV RS 2 ;SP SAVE TEMP2 RS 2 ; COUNT RS 1 ;SECTORS/TRACK SORE UNITCK RS 1 ;OLD FLOPPY STORE BYTE RSEEK RS 1 ;NBR OF RESEEKS RTRY RS 1 ;NBR OF RTRYS ADRIVE RS 1 ;STORE OF A: TYPE BDRIVE RS 1 ;STORE OF B: TYPE MDINIT RS 1 ;FLAG FOR MDISK INITILIZATION IDSV RS 6 ;STORE FOR TRACK ID DETREMINATION SPARE RS 2 ; FLGSIZ EQU (OFFSET $)-(OFFSET FLAGS) ;DEFINES SIZE OF VARIABLE STORAGE ; LOC_STK RW 64 ;LOCAL STACK FOR INITILIZATION STKBASE EQU OFFSET $ ; ; ; UNINITIALIZED SCRATCH MEMORY FOLLOWS: ; BEGDAT EQU OFFSET $ ;START OF SCRATCH AREA DIRBUF RS 128 ;DIRECTORY BUFFER ALV0 RS 500 ;ALLOC VECTOR CSV0 RS 0 ;CHECK VECTOR ALV1 RS 31 ;ALLOC VECTOR CSV1 RS 16 ;CHECK VECTOR ALV2 RS 31 ;ALLOC VECTOR CSV2 RS 16 ;CHECK VECTOR ALV3 RS 30 ;ALLOC VECTOR CSV3 RS 16 ;CHECK VECTOR ALV4 RS 30 ;ALLOC VECTOR CSV4 RS 16 ;CHECK VECTOR alv12 rs 120 ;Alloc Vector csv12 rs 32 ;Check Vector ENDDAT EQU OFFSET $ ;END OF SCRATCH AREA DATSIZ EQU OFFSET $-BEGDAT ;SIZE OF SCRATCH AREA DB 0 ;MARKS END OF MODULE ; ; XLAST EQU OFFSET $ ; TPASEG EQU (XLAST + 0400H+15)/16 ; TPALEN EQU 01FFFH - TPASEG ;<---- TOP PARAGRAPH OF RAM FOR CP/M DB 0 ;FOR GENCMD ; ; ----- LOW MEMORY ------- DSEG 0H ORG 0H ;AT LOW MEMORY ; INT0_OFFSET RW 1 INT0_SEGMENT RW 1 ;PAD TO OVERFLOW TRAP VECTOR RW 6 INT4_OFFSET RW 1 INT4_SEGMENT RW 1 ;PAD TO SYSTEM CALL VECTOR ; ORG 380H ; BDOS_OFFSET RW 1 BDOS_SEGMENT RW 1 ; END