;------THIS IS A BIOS FOR CPM 2.2 USEING A HARD DISK & 2 FLOPPY DISKS---------- ; ;THE FLOPPY'S CAN BE EITHER SINGLE OR DOUBLE DENSITY THE BIOS WILL FIGURE IT ;OUT AUTOMATICALLY. IT IS SETUP AT THE MOMENT FOR ONE SEGATE ST-506 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 AND THE XCOMP HARD DISK CONTROLLER ; (BOTH OF THESE ARE FIRST CLASS BORDS IN MY OPINION) ; ; AUTHOR: JOHN J. MONAHAN (201)779-0635 8/6/81 ; ;NOTE THIS BIOS IS ~2.5K LONG SO ONE COMPLETE TRACK OF THE 506 DRIVE IS REQ TO ;HOLD THE CP/M SYSTEM (IE 32 256 BYTE SECTORS). ALSO REMEMBER DUREING A SAVE OF ;A REBUILT MEMORY IMAGE (TO USE FOR EXAMPLE IN SYSGEN), SAVE 38 PAGES OF RAM. ;YOU WILL ALSO NEED TO WRITE A SYSGEN PROGRAM TO PUT THIS BIOS ON THE HARD DISK ;A BOOT (IN ROM) TO READ IN THE CPM LOADER (SECTOR 1) AND THE LOADER ITSELF. ;THESE PROGRAMS ARE SUPPLIED BY XCOMP. ; ZAPPLE EQU 0F000H ;SYSTEM MONITOR MSIZE EQU 60 ;MEMORY SIZE IN KBYTES. CPMBASE EQU (MSIZE-22)*1024 ;BIAS FOR CPM LARGER THAN 17K.(NOTE I ALLOW AN ;EXTRA 1K TO MAKE ROOM FOR EXTRA CODE REQ. CCP EQU CPMBASE+3400H ;START OF CPM BDOS EQU CCP+806H ;LINK TO BDOS BIOS EQU CCP+1600H ;START OF BIOS ; NSECT: EQU (BIOS-CCP)/128 ;NUMBER SECTORS TO WARM BOOT IOBYT: EQU 3 ;I/O SYSTEM CONFIGURATION CDISK: EQU 4 ;CURRENT DISK ADDRESS (USED BY CPM) BUFF: EQU 80H ;FCB BUFFER VSA: EQU 8 ;SEEK VERIFY START ADDRESS VCA: EQU 1BH ;SEEK VERIFY COMPARE ADDRESS ; ;------- HARD DISK PARAMETERS -------------------------------------- ; MAXSEC: EQU 32 ;NUMBER OF SECTORS PER TRACK ON HARD DISK MAXHED: EQU 4 ;NUMBER OF HEADS ON HARD DISK MAXCYL: EQU 153 ;NUMBER OF CYLINDERS/HEAD (ST-506) BLKSIZ: EQU 2048 ;NUMBER OF BYTES PER BLOCK FOR HARD DISK CPMSPT: EQU 2*MAXSEC ;NUMBER OF CPM SECTORS PER TRACK FOR HARD DISK HSKCMD: EQU 3 ;SEEK COMMAND FOR HARD DISK CONTROLLER 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 CBASE: EQU 70H ;BASE ADR OF THE XCOMP CONTROLLER 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 ; ;------ FLOPPY 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 ; UNIT EQU 40H ;STORE FOR FLOPPY NEW UNIT BYTE ERMASK EQU 41H ;FLOPPY ERROR MASK ERSTAT EQU 42H ;FLOPPY ERROR FLAG STORE CMDSV EQU 43H ;COMMAND SAVE SPSV EQU 44H ;SP SAVE TEMP2 EQU 46H ;2 BYTE TEMP RECORD COUNT EQU 48H ;SECTORS/TRACK STORE UNITCK EQU 49H ;OLD FLOPPY UNIT BYTE RSEEK EQU 4AH ;NBR OF RESEEKS RTRY EQU 4BH ;NBR OF RTRYS ADRIVE EQU 4CH ;STORE OF A: DRIVE DENSITY ETC TYPE BDRIVE EQU 4DH ;STORE OF B: DRIVE TYPE IDSV EQU 50H ;6 BYTES (USED FOR TRACK ID COMMAND) ; ; ASCII CHARACTERS ; CR: EQU 0DH ;CARRIAGE RETURN LF: EQU 0AH ;LINE FEED BELL: EQU 7 ;DING ; ; ORG BIOS ; ; ---JUMP TABLE--- ; ; JP BOOT ; 0 - COLD BOOT WBX: JP WBOOT ; 1 - WARM BOOT JP ZAPPLE+12H ; 2 - CONSOLE STATUS REQUEST ZCI: JP ZAPPLE+03H ; 3 - CONSOLE INPUT ZCO: JP ZAPPLE+09H ; 4 - CONSOLE OUTPUT ZLO: JP ZAPPLE+0FH ; 5 - LIST OUTPUT JP ZAPPLE+0CH ; 6 - PUNCH OUTPUT JP ZAPPLE+06H ; 7 - READER INPUT JP HOME ; 8 - TRACK ZERO SEEK JP SETDR ; 9 - SET DRIVE # JP SETTK ; 10 - SET TRACK ADR JP SETSEC ; 11 - SET SECTOR ADR JP SETDMA ; 12 - SET BUFFER ADDRESS JP READ ; 13 - READ A SECTOR JP WRITE ; 14 - WRITE A SECTOR ZLISTS: JP ZAPPLE+27H ; 15 - LIST OUTPUT READY TEST JP SXR ; 16 - SECTOR XLATE ROUTINE ; ; ====================== ; ** DISK DEFINITIONS ** ; ====================== ; DPHDR: DEFW 0,0 ;SEAGATE ST-506 DRIVE (DRIVE A:) DEFW 0,0 DEFW DIRBUF,HDBLK DEFW LAST,HALL0 ;LAST & FIRST LOCATIONS FOR BIT-MAP ; DEFW XLT0,0 ;FLOPPY 8" SD (DRIVE B:) DEFW 0,0 DEFW DIRBUF,DPB0 DEFW CSV0,ALV0 ; DEFW XLT0,0 ;FLOPPY 8" SD (DRIVE C:) DEFW 0,0 DEFW DIRBUF,DPB0 DEFW CSV1,ALV1 ; DEFW XLT1,0 ;FLOPPY 8" DOUBLE DEN (FOR CPM = D:) DEFW 0,0 ;(FOR HARDWARE DRIVE B: CF. ROM BIOS) DEFW DIRBUF,DPB1 DEFW CSV2,ALV2 ; DEFW XLT1,0 ;FLOPPY 8" DOUBLE DEN (FOR CPM = E:) DEFW 0,0 ;(FOR HARDWARE DRIVE C: CT. ROM BIOS) DEFW DIRBUF,DPB1 DEFW CSV3,ALV3 ; ; ---THE HARD DISK PARAMETER BLOCK IS SETUP AS FOLLOWS--- ; ; 1. THE SEAGATE ST-506 IS CONFIGURED AS A SINGLE 5.0 MEGABYTE DRIVE. ; ; 2. THE CPM LOGICAL BLOCK SIZE IS 2048 BYTES. ; ; 3. THERE ARE 1024 DIRECTORY ENTRIES. THIS IS THE MOST ; WE CAN GET WITH A BLOCK SIZE OF 2048. ; ; 4. THE FIRST TRACK IS RESERVED FOR THE SYSTEM. THIS WILL ; ALLOW AN AGGREGATE CCP/BDOS/CBIOS SIZE OF 8 K-BYTES. ; ; HDBLK: DEFW 64 ;SPT: (LOGICAL) SECTORS PER TRACK DEFB 4 ;BSH: BLOCK SHIFT FACTOR DEFB 15 ;BLM: BLOCK MASK DEFB 0 ;EXM: NULL MASK DEFW 2441 ;DSM: (DISK SIZE) - 1 DEFW 1023 ;DRM: (DIR SIZE) - 1 DEFB 0FFH ;AL0: DIRECTORY ALLOCATION BITS, MSB DEFB 0FFH ;AL1: * LSB DEFW 0 ;CKS: CHECK SIZE DEFW 2 ;OFF: TRACK OFFSET ; ;--- THE FLOPPYS CAN BE SD OR DD SO 2 LOGICAL DRIVE TYPES--- ; ; DRIVES B: & C: ; (DISKDEF 0,1,26,6,1024,243,64,64,2) ; DPB0: DW 26 ;SEC PER TRACK DB 3 ;BLOCK SHIFT DB 7 ;BLOCK MASK DB 0 ;EXTNT MASK DW 242 ;DISK SIZE-1 DW 63 ;DIRECTORY MAX DB 192 ;ALLOC0 DB 0 ;ALLOC1 DW 16 ;CHECK SIZE DW 2 ;OFFSET ; XLT0: DB 1,7,13,19,25,5,11,17,23,3,9,15,21,2,8 DB 14,20,26,6,12,18,24,4,10,16,22 ; ; ----- DRIVE D: & E: ARE DOUBLE DENSITY---- ; (DISKDEF 2,1,50,0,2048,234,64,64,2) ; DPB1: DW 50 ;SEC 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 ; XLT1: DB 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 DB 20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36 DB 37,38,39,40,41,42,43,44,45,46,47,48,49,50 ; ; ; ===================== ; ** CBIOS FUNCTIONS ** ; ===================== ; ---COLD BOOT--- ; ; BOOT: LD SP,BUFF ;USE LOW MEMORY LD HL,FLAGS ;CLEAR RAM STORAGE AREA LD B,FLGSIZ XOR A INIT1: LD (HL),A ;CLEAR FLAGS & VARIABLES INC HL DEC B JP NZ,INIT1 LD (CDISK),A ;FOR USE BY CPM LD (IOBYT),A ;CLEAR IOBYTE DEC A ;PUT 0FFH IN FLOPPY A & B STORE LD (ADRIVE),A LD (BDRIVE),A JP XIT ;GOTO CPM ; ; ---WARM BOOT--- ; ; WBOOT: LD SP,BUFF XOR A LD (RRDSK),A ;SLCT DRIVE ZERO DEC A LD (ADRIVE),A ;PUT 0FFH IN FLOPPY A & B STORE LD (BDRIVE),A CALL XSTZ ;SEEK TO TRACK ZERO LD HL,CCP ;CPM LOAD ADR LD (DMADR),HL ;SAVE IT LD C,2 CALL SETSEC ;SET SECTOR ADR LD A,NSECT ; # SECTORS TO WARM BOOT WB1: LD (SECNT),A ;SAVE THE SECTOR COUNT CALL HDREAD ;READ A SECTOR FROM THE HARD DISK OR A JP Z,WB2 ;JIF READ OK LD HL,MSG1 ; 'CAN'T BOOT' CALL PRNT ;PRINT ERROR MSG JP ZAPPLE WB2: LD HL,(DMADR) LD DE,128 ADD HL,DE ;BUMP DMA ADR LD (DMADR),HL LD HL,RRSEC LD C,(HL) INC C ;INCR SECT ADR CALL SETSEC ;SET NEW SECT ADR LD A,(SECNT) ;A = SECTOR COUNT DEC A JP NZ,WB1 ;JIF MORE TO READ ; ; ---EXIT TO CPM--- ; XIT: LD HL,BUFF LD (DMADR),HL ;INIT DMA ADR LD A,0C3H ;JMP INST LD (0),A LD HL,WBX LD (1),HL ;SET WARM BOOT LINK LD HL,BDOS LD (5),A LD (6),HL ;SET BDOS LINK LD A,(CDISK) ;CURRENT LOGGED-IN DISK & USER LD C,A JP CCP ;GOTO CPM ; ; ---SECTOR TRANSLATE ROUTINE--- ; SXR: EX DE,HL ;H/L = ADR OF XLATE TABLE LD A,L OR H ;TEST TABLE ADR JP NZ,SXR1 ;JIF DO XLATE ADD HL,BC ;DON'T XLATE -- USE SECT ADR AS IS RET ; SXR1: ADD HL,BC ;INDEX INTO THE TABLE LD L,(HL) ;L = XLATED SECTOR ADR LD H,0 ;H = 0 FOR 16-BIT VALUE RET ; ; ---HOME--- ; ; HOME: LD A,(RRDSK) ;DRIVE # CP 1 ;SET AT THE MOMENT FOR ONE HARD DISK JP C,XSTZ ;JIF REZERO HARD DISK CP 3 ;ALLOW TWO FLOPPYS JP C,FHOME ;JIF REZERO FLOPPY SELERR: LD A,1 ;SET ERROR FLAG RET ; ; ---READ--- ; READ: LD A,(RRDSK) ;DRIVE # CP 1 JP C,HDREAD ;JIF READ FROM H/D CP 3 JP C,FREAD ;JIF READ FROM F/D JP SELERR ;ABORT, SELECT ERROR ; ; ---WRITE--- ; ; WRITE: LD A,(RRDSK) ;DRIVE # CP 1 JP C,HDWRT ;JIF WRITE ONTO H/D CP 3 JP C,FWRITE ;JIF WRITE ONTO F/D JP SELERR ;ABORT, SELECT ERROR ; ; ---SET DRIVE NUMBER--- ; SETDR: LD A,C ;A = NEW DRIVE # LD (RRDSK),A ; SAVE IT LD HL,0 CP 3 RET NC ;RIF INVALID DRIVE # WITH [HL]=0 CP 1 ;IF NOT 1 MUST BE FLOPPYS CALL NC,FSELDSK ;RETURNS WITH LOGICAL DRIVE OFFSET IN [A] LD L,A ADD HL,HL ;SHIFT H/L LEFT 4 ADD HL,HL ; (HL = HL*16) ADD HL,HL ADD HL,HL LD DE,DPHDR ;DISK PARM HDR ADD HL,DE ;H/L = DPHDR FOR SELECTED DRIVE RET ; ; ---SET SECTOR ADR--- ; SETSEC: LD A,C LD (RRSEC),A ;SAVE SECTOR ADR ;SET REAL SECTOR ADR FOR THE H/D DRIVER AND NOT 1 ;CLEAR LOW ORDER BIT RRCA ;THERE ARE 2 CPM SECTORS PER H/D SECT LD (RSA),A ;SAVE REAL SECTOR ADR RET ; ; ---SET TRACK ADDRESS--- ; ; SETTK: LD H,B LD L,C LD (RRTRK),HL ;SAVE TRACK ADR RET ; ; ---SET DMA ADDRESS--- ; ; SETDMA: LD H,B LD L,C LD (DMADR),HL ;SAVE DMA ADR RET ; ; ====================================== ; ** HARD DISK BLOCK/DEBLOCK ROUTINES ** ; ====================================== ; ; ---HARD DISK READ--- ; HDREAD: XOR A LD (ERFLG),A ;CLEAR THE ERROR FLAG LD A,(FLAGS) ;SET READ OPERATION FLAG SET 0,A BIT 2,A ;WRITE IN PROGRESS ? LD (FLAGS),A CALL NZ,XWRT ;YES, WRITE DATA BEFORE READ LD A,(FLAGS) RES 2,A ;RESET 'WIP' FLAG LD (FLAGS),A CALL TSTHST ;HOST = REQ ? JP NZ,HDRD1 ;NO, READ A BLOCK LD A,(FLAGS) BIT 1,A ;PRIOR BLOCK READ ? JP NZ,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 IN A,CTDP ;PRIME DATA INPUT INIR ;BLOCK INPUT LD A,(FLAGS) SET 1,A ;SET READ-IN-PROGRESS FLAG LD (FLAGS),A LD A,(ERFLG) ;ERROR FLAG RET ; ; ---HARD DISK WRITE--- ; ; HDWRT: XOR A LD (ERFLG),A ;CLEAR THE ERROR FLAG LD A,(FLAGS) RES 1,A ;CLEAR READ-IN-PROGRESS FLAG LD (FLAGS),A LD A,C ;A = WRITE MODE DEC A JP Z,WDIR ;DO DIRECTORY WRITE JP M,WNORM ;DO NORMAL WRITE ; ; UNALLOCATED WRITE ; WUN: LD A,(FLAGS) BIT 2,A ;WRITE IN PROGRESS ? CALL NZ,XWRT ;YES, WRITE DATA IN BFR ;SET UNALLOC RECORD PARAMETERS LD A,BLKSIZ/128 LD (URCNT),A ;SET UNALLOC RECORD COUNT LD HL,(RRDSK) LD (URDSK),HL ;UPDATE DRIVE & SECTOR LD HL,(RRTRK) LD (URTRK),HL ;UPDATE TRACK ADR CALL SETHST ;SET HOST = REQ CALL BUMP ;BUMP UNALC PARMS FOR NEXT PASS ;XFER DATA TO CTLR BFR WXFER: LD A,(FLAGS) RES 0,A ;CLEAR READ OPER FLAG LD (FLAGS),A CALL GETDMA ;GET DMA ADR, SET FOR WRITE OTIR ;BLOCK OUTPUT LD A,(FLAGS) SET 2,A ;SET WRITE-IN-PROGRESS FLAG LD (FLAGS),A LD A,(ERFLG) ;ERROR FLAG RET ; ; NORMAL WRITE ; WNORM: LD A,(URCNT) ;UNALC RECORD COUNT OR A JP Z,WALC ;JIF DO ALLOC WRITE LD HL,URTRK CALL DSKCMP ;UNALC DSK/TRK = REQ DSK/TRK ? JP NZ,WALC ;NO, DO ALLOC WRITE LD A,(RRSEC) CP (HL) ;UNALC SECT = REQ SECT ? JP NZ,WALC ;NO, DO ALLOC WRITE CALL BUMP ;BUMP UNALC PARMS FOR NEXT PASS CALL TSTHST ;HOST = REQ ? JP Z,WN1 ;YES, CON'T TO FILL THE BFR LD A,(FLAGS) BIT 2,A ;WRITE IN PROGRESS ? CALL NZ,XWRT ;YES, WRITE OLD DATA ONTO DISK CALL SETHST ;MAKE HOST = REQ ; WN1: LD A,(FLAGS) BIT 0,A ;INTERVENING READ ? CALL NZ,XREAD ;YES, READ OLD UNALC DATA JP WXFER ;MOVE DATA TO BFR, EXIT ; ; ALLOCATED WRITE ; WALC: XOR A LD (URCNT),A ;CLEAR UNALC RECORD COUNT CALL TSTHST ;HOST = REQ ? JP Z,WXFER ;YES - MOVE DATA TO BFR, EXIT LD A,(FLAGS) BIT 2,A ;WRITE IN PROGRESS ? CALL NZ,XWRT ;YES, WRITE OLD DATA ONTO DISK CALL SETHST ;MAKE HOST = REQ CALL XREAD ;READ IN ALLOCATED DATA JP WXFER ;MOVE NEW DATA IN BFR, EXIT ; ; DIRECTORY WRITE ; WDIR: XOR A LD (URCNT),A ;CLEAR UNALC RECORD COUNT LD A,(FLAGS) RES 0,A ;RESET 'RDOP' FLAG LD (FLAGS),A BIT 2,A ;WRITE IN PROGRESS ? CALL NZ,XWRT ;YES, WRITE OLD DATA ONTO THE DISK LD A,(FLAGS) RES 2,A ;CLEAR 'WIP' FLAG LD (FLAGS),A CALL SETHST ;MAKE HOST = REQ CALL XREAD ;READ DIR DATA RET NZ ;RIF READ ERROR CALL GETDMA ;GET DMA ADR, SET POINTERS OTIR ;BLOCK OUTPUT JP XWRT ;WRITE DIR DATA, EXIT ; ; ---TEST HOST--- ; ; DETERMINES IF THE HOST DISK ADDRESS IS ; THE SAME AS THE REQUESTED DISK ADDRESS. ; ; TSTHST: LD HL,HHTRK CALL DSKCMP ;TRACK & DRIVE THE SAME ? RET NZ ;RIF NO LD A,(RSA) CP (HL) ;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: LD A,(RRDSK) LD (HHDSK),A ;DRIVE # LD HL,(RRTRK) LD (HHTRK),HL ;TRACK ADR LD A,(RSA) LD (HHSEC),A ;SECTOR ADR RET ; ; ---BUMP--- ; ; BUMPS PARAMETERS FOR UNALLOCATED WRITES. ; PARMS ARE CHANGED FOR THE NEXT PASS THRU ; THE CODE (NOT THE CURRENT PASS). ; BUMP: LD HL,URCNT ;UNALC RECORD COUNT DEC (HL) ; DECR IT DEC HL ;H/L = URSEC INC (HL) ; INCR IT LD A,(HL) CP CPMSPT ;CPM SECTORS PER TRACK RET C ;RIF STAY ON SAME TRACK ;OVERFLOW TO NEXT TRACK LD (HL),0 ;RESET SECTOR ADR LD HL,(URTRK) INC HL ;INCR TRACK ADR LD (URTRK),HL RET ; ; ---GET DMA ADDRESS--- ; ; SETS THE CONTROLLER BUFFER ADDRESS TO THE CORRECT ; STARTING POINT. ALSO SETS B=128 & H/L=DMADR. ; ; GETDMA: LD HL,(DMADR) ;DMA ADR LD C,CTDP ;FOR BLOCK I/O LD B,128 ;B = COUNT LD A,DBENB OUT CTCSR,A ;ENB DATA BFR LD A,(RRSEC) ;REQUESTED SECTOR RRCA LD A,0 JP NC,GET1 ;JIF USE 1ST HALF OF BFR LD A,B ; USE 2ND HALF OF BFR GET1: OUT CTBFR,A ;SET CTLR DATA BFR ADR RET ; ; ; ====================================== ; ** HARD DISK I/O & SUPPORT ROUTINES ** ; ====================================== ; ---READ A BLOCK--- ; XREAD: LD HL,RTBL ;READ CMD TBL CALL DORW ;READ ; XR1: LD A,0 RET Z ;RIF READ/WRITE OK INC A LD (ERFLG),A ;SET ERROR FLAG RET ; ; ---WRITE A BLOCK--- ; XWRT: LD HL,WTBL ;WRITE CMD TBL CALL DORW ;WRITE A SECTOR JP XR1 ;SET ERROR FLAG ; ; ---EXECUTE READ/WRITE COMMANDS--- ; DORW: PUSH HL ;SAVE CMD TBL ADR CALL XSEK ;SEEK TO NEW TRACK (IF REQUIRED) POP HL ;RESTORE CMD TBL ADR RET NZ ;RIF SEEK FAILED CALL XSEL ;HEAD SELECT ; DO0: LD A,(HL) LD (RETRY),A ;SET RETRY COUNT INC HL LD A,(HL) OUT CTCSR,A ;ENB CMP BFR INC HL LD A,(HL) OUT CTBFR,A ;SET CMP BFR ADR INC HL LD (CTA),HL ;SAVE CMD TBL ADR ; LD HL,RTK ;REAL TK ADR LD B,3 DO1: LD A,(HL) OUT CTDP,A ;PUT HDR INFO INTO CMP BFR INC HL DEC B JP NZ,DO1 LD A,(HHSEC) OUT CTDP,A ;SET SECT ADR FOR COMPARE ; DO2: CALL XRDY ;DRIVE READY ? RET NZ ; RIF NO LD HL,(CTA) ;CMD TBL ADR LD A,(HL) ;A = CNTL BANK INC HL LD B,A OUT CTCSR,A ;SLCT CNTL BANK LD A,(HL) OUT CTBFR,A ;SET START ADR INC HL LD A,B OR START OUT CTCSR,A ;START R/W CMD ; DO3: CALL WFD ;WAIT FOR READ/WRITE TO FINISH AND (HL) ;TEST CTLR STATUS (0=OK) LD B,A IN A,DRCSR ;DRIVE STATUS AND WRTFLT CALL NZ,CLRDF ;CIF CLEAR DRIVE FAULT OR B ;SET/CLEAR ERROR FLAG (0=OK) RET Z ;RIF READ/WRITE OK LD HL,RETRY DEC (HL) ;DECR RETRY COUNT JP NZ,DO2 ;JIF RETRY READ/WRITE ; ; SET ERROR FLAG ; SEF: LD A,1 ;A = ERROR FLAG OR A ;SET 8080 FLAGS RET ;TAKE ERROR EXIT ; ; ---WAIT FOR DONE--- ; WFD: IN A,CTCSR ;CTLR STATUS RRCA JP NC,WFD ;WAIT FOR DONE NOP ;DELAY FOR H/W IN A,CTCSR ;GET NON-CHANGING STATUS LD B,A XOR A OUT CTCSR,A ;STOP CTLR LD A,B RET ; ; ---REZERO--- ; XTKZ: CALL XRDY ;DRIVE READY ? RET NZ ; RIF NO LD HL,0 LD (CHDT),HL ;SET CURRENT TRACK = 0 LD B,0 ;SET RETRY COUNT = 256 ; XTKZ1: IN A,DRCSR ;DRIVE STATUS AND TK00 ;TRACK ZERO INDICATOR XOR TK00 ; MAKE IT LO-TRUE RET Z ;RIF AT TRACK ZERO DEC B ;DECR RETRY CNT JP Z,SEF ;JIF REZERO FAILED XOR A OUT HISC,A INC A OUT LOSC,A ;SET SEEK COUNT = 1 OUT EXTCMD,A ;SET SEEK DIRECTION = OUT LD A,HSKCMD OUT DRCSR,A ;START SEEK CALL WSC ;WAIT FOR SEEK DONE JP XTKZ1 ; ; ---SEEK TO TRACK ZERO--- ; XSTZ: LD A,(FLAGS) BIT 2,A JP NZ,XSTZ1 ;JIF WRITE IN PROGRESS LD (FLAGS),A ;MAKE HOST INACTIVE XSTZ1: LD HL,0 LD (RRTRK),HL ;SET TK ADR = 0 XOR A ;SET FLAG = NO ERRORS RET ; ; ---SEEK--- ; XSEK: CALL XRDY ;DRIVE READY ? RET NZ ; RIF NO LD A,3 LD (RETRY),A ;SET RETRY COUNT ; XSEK1: XOR A OUT HISC,A ;SET MSB OF SEEK COUNT = 0 LD HL,(HHTRK) ;REQUESTED TRACK LD B,2 CALL DRS ;SHIFT H/L RIGHT TWICE LD (RTK),HL ;SAVE REAL TK ADR LD A,L SUB MAXCYL AND 0FFH LD A,H SBC MAXCYL SHR 8 JP NC,SEF ;JIF INVALID CYL ADR LD A,L ;A = TARGET CYL ADR LD B,L ;FOR LATER USE LD C,3 ;DIRECTION = INWARD LD HL,CHDT ;CURR TK ADR SUB (HL) RET Z ;RIF AT REQUESTED TK LD (HL),B ;UPDATE CURR TK ADR JP NC,XSEK2 ;JIF SEEK INWARD CPL INC A ;MAKE SEEK CNT POSITIVE LD C,1 ;MAKE DIRECTION = OUTWARD XSEK2: OUT LOSC,A ;SET SEEK COUNT LD A,C OUT EXTCMD,A ;SET DIRECTION OF SEEK LD A,HSKCMD OUT DRCSR,A ;INITIATE SEEK CALL WSC ;WAIT FOR SEEK DONE ;SEEK VERIFY LD A,CBENB OUT CTCSR,A ;ENABLE BANK ZERO CMP BFR LD A,VCA OUT CTBFR,A ;SET CMP BFR ADR LD A,(CHDT) OUT CTDP,A ;SET CYL ADR, LSB XOR A OUT CTDP,A ;SET CYL ADR, MSB LD A,VSA OUT CTBFR,A ;SET M/CODE START ADR LD A,START OUT CTCSR,A ;START VERIFY CALL WFD ;WAIT FOR DONE AND 0CH ;TEST CTLR STATUS RET Z ;RIF VERIFY OK ;VERIFY FAILED CALL XTKZ ;RESTORE LD HL,RETRY DEC (HL) ;DECR RETRY COUNT JP NZ,XSEK1 ;JIF RETRY SEEK OR 1 ;SET FAIL FLAG RET ;ERROR EXIT ; ; ---WAIT FOR SEEK COMPLETE--- ; WSC: IN A,DRCSR ;DRIVE STATUS RLA JP NC,WSC ;WAIT FOR SEEK DONE IN A,DRCSR ;DRIVE STATUS AND WRTFLT ;TEST FOR DRIVE FAULT RET Z ;RIF OK ; ; ---CLEAR DRIVE FAULT--- ; CLRDF: XOR A OUT EXTCMD,A ;DE-SELECT THE DRIVE (FALL THRU TO 'XSEL' TO ;RE-SELECT THE DRIVE) ; ; ---HEAD SELECT--- ; XSEL: LD A,(HHTRK) ;REQUESTED TRACK AND 3 ;4 HEADS LD (RHD),A ;SAVE REAL HEAD # ADD A ;SHIFT HEAD # LEFT TWICE FOR H/W ADD A OR 1 ;TO MAINTAIN DRIVE SLCT LD B,A LD A,(CHDT) ;CURRENT CYLINDER ADR CP MAXCYL/2 ;HALF CYLINDER POINT ? LD A,0 ;PRE-COMP ST-506 ON ALL CYLS JP C,XSEL1 ;JIF 1ST HALF OF DISK LD A,LOWRT ;LOW WRITE CURRENT XSEL1: OR B ;B = HEAD SLCT INFO OUT EXTCMD,A ;SELECT HEAD 0...3 RET ; ; ---DRIVE READY TEST--- ; XRDY: IN A,DRCSR ;DRIVE STATUS AND 1 ;DRIVE READY BIT XOR 1 ;INVERT IT RET ;IF A = 0, DRIVE RDY ; ; ---COMMAND TABLES--- ; WRITE WTBL: DEFB 5 ;RETRY COUNT DEFB 5 ;CMP BFR ENB DEFB 0E4H ;CMP BFR ADR DEFB BANK1 ;CNTL BANK DEFB 0D1H ;START ADR DEFB 0EH ;STATUS MASK ; ; READ RTBL: DEFB 10 ;RETRY COUNT DEFB 4 ;CMP BFR ENB DEFB 0EAH ;CMP BFR ADR DEFB BANK0 ;CNTL BANK DEFB 0D7H ;START ADDRESS DEFB 0EH ;STATUS MASK ; ; ---DISK ADDRESS COMPARE--- ; ; COMPARES EITHER THE HOST DISK ADDRESS OR THE UNALLOCATED ; DISK ADDRESS AGAINST THE REQUESTED DISK ADDRESS. ; DSKCMP: LD DE,RRTRK ;REQUESTED TRACK LD B,3 DC1: LD A,(DE) CP (HL) RET NZ ;RIF ADRS NOT EQUAL INC HL INC DE DEC B JP NZ,DC1 RET ; ; ====================================== ; FLOPPY DISK ROUTINES ; ====================================== ; FHOME: XOR A ;NO NEED TO DO ACTUAL HOME AT THIS STAGE LD (RRTRK),A ;WILL ALWAYS BE < 0FF TRACKS ON FLOPPY RET ; FSELDSK:DEC A ;FOR FLOPPY MAKE B:=A: (OR C:) LD C,A ;AND C:=B: (OR D:) FOR FLOPPY PARAMETERS OR A ;IF REQUESTED DRIVE IS A: THEN [A] = 0 JP NZ,BBBB ;MUST BE B: DRIVE LD A,(ADRIVE) ;IS IT FIRST TIME TO GET THIS DRIVE CP 0FFH CALL Z,GETTYPE LD (ADRIVE),A ;STORE DENSITY FLAG JP ALLOK BBBB: LD A,(BDRIVE) ;IS IT FIRST TIME FOR THIS ONE CP 0FFH CALL Z,GETTYPE LD (BDRIVE),A ;STORE DENSITY FLAG ; ALLOK: OR C ;MIX DRIVE TYPE WITH DRIVE# LD (UNIT),A ;STORE IT FOR SECTOR R/W ROUTINES ETC INC A ;ADD BACK WHAT WE SUBTRACTED ABOVE BIT 6,A RET Z ;RETURNS WITH TABLE OFFSET B:=B: & C:=C: ;FOR DOUBLE DENSITY DISKS WE MUST USE THE ;LOOKUP TABLE FOR DRIVES D: & E: LD A,00000011B ;RETURNS FOR TABLE OFFSET B:=D: & C:=E: ADD C ;FOR DOUBLE DENSITY DISKS RET ; GETTYPE:LD A,C ;FIND OUT TYPE OF DRIVE CALL UNITSL JP NZ,HB101 ;IF NZ PROBLEMS ABORT LD A,(UNIT) AND 01000000B ;GET DENSITY FLAG RET ; ; THIS ROUTINE SETS UP THE FLOPPY DISK UNIT BYTE ; THE REQUIRED DRIVE IS IN [A] ; UNITSL: LD B,5 AND 0FH OR 40H ;COME UP DEFALT IN 8" DD LD (UNIT),A LD HL,(DMADR) LD (TEMP2),HL CALL USL1 LD HL,(TEMP2) LD (DMADR),HL LD A,(UNIT) RET ; USL1: PUSH BC PUSH HL LD (SPSV),SP POP HL CALL DRVSET ;SELECT DRIVE IN HARDWARE CALL IDRD ;TRY READING TRACK ID POP BC RET Z ;IF CORRECT DENSITY WILL BE Z DEC B ;DECREASE 5.......0 IF Z THEN ERROR JP Z,SPECIAL CALL CHGTYP JR USL1 ; SPECIAL:XOR A ;COULD BE LATER USED FOR SPECIAL SECTOR SIZE DEC A RET ;RET NZ SO SELDSK KNOWS THERE IS A PROBLEM ; CHGTYP: LD A,(UNIT) ADD 01000000B ;TOGGLE DENSITY BIT AND 01111111B ;CLEAR BIT 7 LD (UNIT),A RET ; ; READ A SECTOR FREAD: LD BC,301H READBT: LD (RSEEK),BC READ1: PUSH BC CALL RDSC POP BC RET Z CALL FRETRY JR READ1 ; ; WRITE A SECTOR FWRITE: LD BC,301H WRBT: LD (RSEEK),BC WRITE1: PUSH BC CALL WRSC POP BC RET Z CALL RETRY JR WRITE1 ; FRETRY: DJNZ RETRY2 LD A,(RTRY) LD B,A DEC C JP P,RETRY1 POP AF XOR A INC A RET ; RETRY1: PUSH BC CALL HOME1 POP BC RETRY2: RET ; HOME1: LD (SPSV),SP LD A,RSCMD CALL SEEK4 XOR A RET ; ; SELECT DRIVE IN HARDWARE ; DRVSET:LD DE,UNIT LD A,(DE) AND 0E0H LD C,A ;STORE DRIVE TYPE IN [C] LD A,(DE) AND 03 LD B,A ;STORE DRIVE # IN [B] LD A,1 JR Z,DRVSEL CKDRV1: RLCA DJNZ CKDRV1 DRVSEL: OR C ;COMBINE TYPE & DRIVE# AND 7FH LD B,A ;[B] CONTAINS INFO FOR HARDWARE LD A,STDSDT ;SETUP FOR SD LD (COUNT),A ;STORE AS 26 SECTORS/TRACK LD A,40H ;WAS IT DD DRV1: CP C JR NZ,CKDRV LD A,STDDDT ;SETUP FOR DD LD (COUNT),A ;SET TO 50 SECTORS/TRACK CKDRV: LD A,B ;GET HARDWARE SELECT DATA CPL ;HARDWARE IS INVERTED OUT (SELECT),A LD A,(DE) LD (UNITCK),A CALL DELAY RDYCK: IN A,(STATUS) AND 80H JP NZ,END2 RET ; ; READ PRESENT DISK ADDRESS IDRD: CALL WAIT LD HL,IDSV LD BC,600H+DATA ;READ 6 BYTES LD A,0F8H LD (ERMASK),A CALL SWEB LD A,RDACMD ;DO THE ID READ CALL RDSCO LD A,(IDSV) CP NTRKS ;IS IT REASONABLE JP NC,SEEK0 OUT (TRACK),A XOR A RET ; DELAY: LD A,40 ;DELAY ~32 MS (DOES NOT SEEM TO BE CRITICAL) DELAY1: LD B,0 M0: DJNZ M0 DEC A JR NZ,DELAY1 RET ; ; READ SECTOR COMMAND RDSC: CALL DRINIT LD A,RDCMD RDSCO: LD (CMDSV),A DI OUT (CMD),A JR M2 M2: JR MM2 MM2: INIR EI JR END ; ; ; WRITE SECTOR COMMAND WRSC: CALL DRINIT LD A,WRCMD LD (CMDSV),A DI OUT (CMD),A JR H2 H2: JR HM2 HM2: OTIR EI ; ; END OF COMMAND END: CALL WAIT IN A,(STATUS) LD D,A LD A,(ERMASK) AND D RET Z END1: LD A,D END2: LD (ERSTAT),A CALL DELAY OR 1 LD SP,(SPSV) CALL UNITFX RET ; ; ; DRIVE INITIALIZATION ; DRINIT: POP HL LD (SPSV),SP PUSH HL LD A,(UNIT) LD D,A LD A,(UNITCK) CP D JR Z,DINIT1 CALL DRVSET CALL IDRD DINIT1: CALL SEEK LD A,0FEH LD (ERMASK),A ; TRINT: LD HL,(DMADR) ;SETUP DMA ADDRESS AND BYTE COUNT LD A,(RRSEC) OUT (SECTOR),A LD BC,NBYTES*100H+DATA ; SWEB: IN A,(SELECT) ;ENABLE WAIT STATES AND 7FH OUT (SELECT),A RET ; ; SEEK TRACK ; SEEK: CALL RDYCK LD C,NTRKS ;MUST BE REASONABLE TRACK # LD A,(RRTRK) ;ALWAYS < 0FFH TRACKS FOR FLOPPY CP C JR C,SEEK1 SEEK0: LD A,0FH JR END2 SEEK1: LD C,A IN A,(TRACK) CP C RET Z ;IF SAME TRACK NO NEED TO SEEK LD A,SKCMD SEEK4: LD (CMDSV),A LD B,210 S0: DJNZ S0 CALL WAIT LD A,(RRTRK) OUT (DATA),A LD A,80H LD (ERMASK),A LD A,(CMDSV) OUT (CMD),A LD B,10 D0: DJNZ D0 CALL END CALL DELAY LD A,(CMDSV) CP RSCMD ;NO NEED TO CHECK RESTORE COMMAND RET Z IN A,(STATUS) AND 10H JR NZ,SEEK2 IN A,(TRACK) CP C RET Z SEEK2: LD A,20H END2JP: JP END2 ; WAIT: LD E,0 PUSH BC LD C,2 WAIT2: IN A,(STATUS) AND 1 JR Z,DWAIT DJNZ WAIT2 DEC E JR NZ,WAIT2 DEC C JR NZ,WAIT2 POP BC IN A,(SELECT) ;IF BY THIS TIME NOT READY FORCE OR 80H ;A HARDWARE RESET OUT (RSET),A F0: DJNZ F0 IN A,(RSET) CALL FRCINT LD A,RSCMD CALL SEEK4 LD A,0FEH JP END2JP ; ; DISABLE WAIT STATES DWAIT: POP BC ;TO BALANCE THE ABOVE PUSH IN WAIT IN A,(SELECT) OR 80H OUT (SELECT),A RET ; ; ; ; FORCE CHIP INTERUPT FRCINT: LD A,0D0H OUT (CMD),A LD A,10 FRC1: DEC A JR NZ,FRC1 IN A,(STATUS) RET ; UNITFX: LD A,0FFH LD (UNITCK),A RET ; ; ; ====================================== ; ** SUBROUTINES, MESSAGES, & STORAGE ** ; ====================================== ; ; ---DOUBLE RIGHT SHIFT--- ; ; SHIFTS THE CONTENTS OF H/L RIGHT 'N' TIMES. ; DRS: PUSH AF ;SAVE 'A' DRS1: LD A,H ;MSB OR A ;CLEAR CY RRA LD H,A LD A,L ;LSB RRA LD L,A DEC B ;B = SHIFT COUNT JP NZ,DRS1 POP AF ;RESTORE 'A' RET ; ; ---PRINT ROUTINE--- ; ; PRNT: LD A,(HL) ;PRINT CHAR INC HL ;FOR NEXT CHAR OR A RET Z ;RIF DONE LD C,A CALL ZCO ;PRINT A CHAR JP PRNT ;DO NEXT CHAR ; ; HB101: LD HL,0 ;ABORT BECAUSE CANNOT GET DISK TYPE POP AF ;DROP STACK BACK ONE LEVEL XOR A LD (CDISK),A ;SO WARMSTART WILL COME UP ON A INC A ;JUST IN CASE RET ; ; ---MESSAGES--- ; MSG1: DEFB CR,LF,BELL DEFB 'Warm boot read error' DEFB CR,LF,0 ; ; ---PROGRAM STORAGE--- ; FLAGS: DEFS 1 ;BIT FLAGS ;BIT 0 SET FOR READ OPERATION ;BIT 1 SET FOR READ IN PROGRESS ;BIT 2 SET FOR WRITE IN PROGRESS ; RRTRK DEFS 2 ;CP/M REQUESTED TRACK ADDRESS RRDSK DEFS 1 ;CP/M REQUESTED DRIVE # RRSEC DEFS 1 ;CP/M REQUESTED SECTOR ; URTRK: DEFS 2 ;UNALLOCATED TRACK ADDRESS URDSK: DEFS 1 ; DRIVE # URSEC: DEFS 1 ; SECTOR ADDRESS URCNT: DEFS 1 ; RECORD COUNT ; HHTRK: DEFS 2 ;HOST (SHUGART) TRACK ADDRESS HHDSK: DEFS 1 ; DRIVE # HHSEC: DEFS 1 ; SECTOR ADDRESS ; RTK: DEFS 2 ;REAL TRACK ADDRESS RHD: DEFS 1 ; HEAD RSA: DEFS 1 ; SECTOR ; SECNT: DEFS 1 ;SECTOR COUNT (FOR WARM BOOT) RETRY: DEFS 1 ;RETRY COUNT CTA: DEFS 2 ;COMMAND TABLE ADDRESS ERFLG: DEFS 1 ;ERROR FLAG DMADR: DEFS 2 ;BUFFER (DMA) ADDRESS WRTMODE:DEFS 1 ;WRITE MODE CHDT: DEFS 2 ;CURRENT HARD DISK TRACK TEMP: DEFS 2 ;TEMPORARY STORAGE ; FLGSIZ: EQU $-FLAGS ;DEFINES SIZE OF VARIABLE STORAGE ; ; ---BDOS STORAGE--- ; DIRBUF: DS 128 ;DIRECTORY ACCESS BUFFER ALV0: DS 31 CSV0: DS 16 ALV1: DS 31 CSV1: DS 16 ALV2: DS 30 CSV2: DS 16 ALV3: DS 30 CSV3: DS 16 HALL0: DS 306 ;BIT MAP FOR ST-506 LAST: EQU $ ;END