TITLE "SPEEDUP Disk Directory Buffer" ;================================================================= ; The format and much of the code for standardized RSX modules are ; adapted from Bridger Mitchell's code fragments and published ; articles detailing the Plu*Perfect Systems' standard extension ; format. For further details, contact: ; ; Plu*Perfect Systems ; 410 23d St. ; Santa Monica, CA 90402 ; ; This SPEEDUP program is likewise released for non-commercial ; use to show that CP/M is NOT dead, and can PERFORM! ; 9 Aug 1989 ; Harold F. Bower ; P.O. Box 313 ; Ft. Meade, MD 20755 ; ; * CP/M is a Trademark of Digital Research, Inc. ;------------------------------------------------------------------- ; This module is the core for SPEEDUP.COM which is a program to read ; a disk directory into RAM and access the RAM-based directory when- ; ever a directory access is required. It relocates itself below ; the CCP or ZCPR, or any other modules and will remain resident ; until a cold boot, or explicitly removed. ; The program requires a modified Plu*Perfect loader (SPEEDLDR) to ; provide the necessary installation and relocation to high memory. ; No ORG statement is used in this module. The LINKPRL MAP-generat- ; ing linker is used to produce a .PRL-type header record followed ; by program code ORG'ed at 100H, and a relocation bit map. ; Steps required to produce the executable program are: ; 1) Assemble SPEEDLDR.Z80 and SPEED22.Z80 to Microsoft .REL images ; 2) Link SPEEDLDR.REL to COM file Org'ed to 100H with LINKPRL.COM ; 3) Link SPEED22.REL to PRL file Org'ed to 100H with LINKPRL.COM ; 4) Use DDT or other debugger to combine as: ; A0>DDT SPEEDLDR.COM ; NEXT PC ; 0500 0100 ; -ISPEED22.PRL ; -R400 ; NEXT PC ; 0A80 0100 ; -^C ; A0>SAVE 10 SPEEDUP.COM ; LIMITATIONS: ; 1) Only one drive is supported. ; 2) 1 to 8K (32 to 256 entries) are buffered. (default is 4K) ; History: ; 9 Aug 89 2.2. Cleanup of RSX Header structure. ; 10 Mar 89 2.1. First public dissemination. ; 1987, 1988 various bug fixes, enhancements, revisions to conform to ; Plu*Perfect RSX standards. ; 15 Sep 86 Initial test release, derived from unique 1983 program ;..... ; Program-Unique values VER EQU 22 ; Version number of this program REV EQU ' ' ; Revision level of version NJUMPS EQU 8 ; Number of BIOS "jump" vectors saved ; CP/M Memory locations WBOOT EQU 0000H ; CP/M Warm Boot entry Address BDOS EQU 0005H ; CP/M BDOS Entry Address DEFDRV EQU 0004H ; CP/M default drive location FCB EQU 005CH ; CP/M default File Control Block ; Common character constants BELL EQU 07H CR EQU 0DH LF EQU 0AH ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ;+ The remainder of the installation code goes here. The code up to + ;+ the standard header structure is not required after control is + ;+ passed to the resident RSX, and can be overwritten. This initial + ;+ table is used to transfer addresses to the resident part of the RSX. + ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ZSTART: JP PATCHIN ; Finish up the installation ZWBENT: JP XWBOOT ; Warm Boot Trap JP XREMOV ; Remove This Module ZWBADR: DEFW $-$ ; Original WB Address from loc'n 0001H ZPROT: DEFW $-$ ; Lowest Protected Address in this module DEFW RSXNAM ; -> Module name string ZRSXNX: JP $-$ ; Jump to Next RSX Warm Boot or CCP Entry ZNEXT: JP $-$ ; Jump to Next RSX or Bdos Entry ZNXTWB: DEFW $-$ ; Original BIOS+4 Address HDRLEN EQU $-ZSTART WBMSG: DEFB 0 ; Flag for WB Message ; Install the specific parameters for this module and transfer control ; to the resident RSX when complete. ; The following steps are performed here: ; 1) Install original BIOS addresses into module routines. ; 2) Set BIOS traps. ; 3) Calculate and save addresses of data areas in module. PATCHIN: LD A,(FCB+1) ; Check for size argument CP ' ' LD HL,4 ; Default is 4K JR Z,PATCH9 CP '1' ; Error if Not 1 >= n <= 8 JP C,SIZERR CP '8'+1 JP NC,SIZERR SUB '0' LD L,A ; Position in registers LD A,(FCB+2) ; Was a number > 10 entered? CP ' ' JP NZ,SIZERR ; ..jump error if so LD H,0 PATCH9: LD A,L ADD A,'0' ; Put # K in prompt line LD (PMTSIZ),A ADD HL,HL ; 8 sectors per K ADD HL,HL ADD HL,HL LD A,L LD (DMAX),A ; Store value LD HL,(ZWBADR) ; Move BIOS table to local INC HL ; Point to address PUSH HL ; ..hold address til after move LD E,(HL) ; Load Warmboot address INC HL LD D,(HL) LD (ZNXTWB),DE ; .save in Header LD (NEXTWB),DE ; ..and in Remove code LD DE,22 ; Offset to select disk vector ADD HL,DE PUSH HL ; ..and save for later LD DE,BSDSKE ; Move BIOS routines LD BC,NJUMPS*3 LDIR LD L,12 ; Set address for Conout jump.. LD (BCONS),HL ; ..and store in code POP HL ; Restore BIOS seldsk addr INC HL LD DE,SELDSK CALL SAVE LD DE,SETTRK CALL SAVE LD DE,SETSEC CALL SAVE LD DE,SETDMA CALL SAVE LD DE,READ CALL SAVE LD DE,WRITE CALL SAVE LD A,(WBMSG) ; Get WB Print flag from header LD (WBMSG0),A ; ..and place in resident module LD HL,(BDOS+1) LD (ZSTART+1),HL ; Save BDOS vector at header start LD (ZNEXT+1),HL ; .in Next module vector LD (NEXT),HL ; ..and in Remove code LD HL,RSXNAM ; Calculate lower buffer limit LD A,(DMAX) LD E,A ; Calculate sector map start LD D,0 XOR A SBC HL,DE LD (SECTBL),HL ; ..and store LD D,E ; Multiply number of sectors.. LD E,00 ; ..by 128, and.. SRL D RR E XOR A ; ..subtract from module base SBC HL,DE LD (DIR),HL ; This is directory start loc'n LD BC,-HDRLEN ; Subtract header length.. ADD HL,BC ; ..from Start of Directory LD (ZPROT),HL ; Store as protect address in Hdr LD (XPROT),HL ; ..and in Warm Boot code POP DE ; Restore dest for BIOS WB Vector PUSH HL ; Save the addr INC HL INC HL INC HL ; Point to ZWBENT LD (XWBENT),HL ; .and save in Warm Boot code LD A,L LD (DE),A ; ..and in BIOS table INC DE LD A,H LD (DE),A LD BC,6 ADD HL,BC ; Point to ZWBADR LD (XREMOV+1),HL ; .save in Remove Code LD (XWBOOT+1),HL ; ..and Warm Boot Code LD BC,6 ADD HL,BC ; Point to Next RSX or CCP LD (RSXNXT),HL ; ..and store in Warm Boot code POP DE ; Restore the Header Address LD HL,ZSTART ; .set the Source Addr LD BC,HDRLEN ; ..set Length LDIR ; ...and move the header struc. LD A,(FCB) ; Get specified drive # OR A ; Anything entered? JR NZ,PATCH0 ; ..jump if so LD A,(DEFDRV) ; else load current drive AND 0FH ; Mask any uneeded bits JR PATCH1 ; ..and continue PATCH0: DEC A PATCH1: LD (LDISK),A ; ..put in code ADD A,'A' LD (PMTDRV),A ; ..and prompt CALL SAYMOD ; Say name of this module.. JP XWBOOT ; ..and jump to warm boot entry ; Save address in DE at memory addressed by HL. Bypass next jump instr. SAVE: LD (HL),E INC HL LD (HL),D INC HL INC HL RET ; Print Module name and "Loaded" message SAYMOD: LD HL,CRLF CALL WRTLIN LD HL,RSXNAM CALL WRTLIN LD HL,LOADMSG JP WRTLIN ; Print error if size is in ivalid range SIZERR: LD HL,SERRMG CALL WRTLIN JP 0 ; Exit with Warm Boot SERRMG: DEFB CR,LF,'Invalid Size. Must be 1-8 K',BELL,CR,LF,0 LOADMSG: DEFB ' ... loaded.' CRLF: DEFB CR,LF,0 ;================== End of Disposable Code ======================== ; The remainder stays resident and protected. ;==================================================================== RSXNAM: DEFB 'SPEEDUP Directory Buffer v ' DEFB VER/10+'0','.',VER MOD 10+'0',REV,0 WBMSG0: DEFB 0 ; WB Print flag (0=No print, FF=Print) ;..... ; Remove module by re-installing original arguments in code ; Exit with Warm Boot. XREMOV: LD HL,($-$) ; Move BIOS Warm Boot back to position LD (WBOOT+1),HL INC HL ; ..and insert old address in BIOS NEXTWB EQU $+1 LD DE,$-$ LD (HL),E INC HL LD (HL),D LD DE,22 ; Offset to rest of jumps ADD HL,DE EX DE,HL ; ..as destination LD HL,BSDSKE ; Move the BIOS table back LD BC,NJUMPS*3 LDIR NEXT EQU $+1 LD HL,$-$ ; ..Restore BDOS vector LD (BDOS+1),HL SCF ; Flag action done for REMOVE utility RET ;..... ; Part of the original BIOS jump table is relocated here BSDSKE: JP 0 ; BIOS values filled in by Start BSTTRK: JP 0 BSETSC: JP 0 BSTDMA: JP 0 BREAD: JP 0 BWRITE: JP 0 DEFS 3 ; list status BSCTRN: JP 0 ;....... ; Warm Boot trap for this module. (Re)Protect the module. XWBOOT: LD HL,($-$) ; Always restore 0001H LD (WBOOT+1),HL INC HL ; Point at addr in Bios Jmp to warmboot XWBENT EQU $+1 LD DE,$-$ ; ..if it points at us LD A,E CP (HL) JR NZ,XWB1 INC HL LD A,D CP (HL) JR NZ,XWB1 XPROT EQU $+1 LD HL,$-$ ; ..(re)install our protect address LD (BDOS+1),HL ; Set main call vector XWB1: LD (STACK),SP LD SP,STACK LD HL,BANNER ; Say this module is active LD A,(WBMSG0) ; .after testing flag OR A CALL NZ,WRTLIN ; ..if permission granted LD SP,(STACK) LD A,(DEFDRV) ; Get drive in case this is top module LD C,A ; Put in correct register RSXNXT EQU $+1 JP $-$ ; Jump to next warm-boot addr in chain ; ..or to CCP/ZCPR entry if top module. ;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ;@ M O D U L E B O D Y @ ;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ; BIOS Select disk function modified to load directory buffer at logon SELDSK: LD A,(LDISK) ; Is it this drive ? CP C LD A,0 ; Deselect first... LD (FSEL),A JR NZ,BSDSKE ; ..jump if not here DEC A ; Else select this by storing 0FFH LD (FSEL),A BIT 0,E ; Is this a logon request? JR NZ,BSDSKE ; ..jump if not to BIOS select & exit CALL BSDSKE ; Else Do BIOS select & return here PUSH HL ; Save Registers for routine PUSH BC PUSH AF LD E,(HL) ; Get skew addr INC HL LD D,(HL) LD (SKWTBL),DE LD DE,9 ADD HL,DE ; DPB is at DPH+10 LD E,(HL) INC HL LD D,(HL) EX DE,HL LD DE,SPTRK ; Move SPB to local area LD BC,15 LDIR LD HL,(DIRMAX) ; Load # directory entries - 1 INC HL ; Correct dirmax SRL H ; Convert DIRMAX to # of sectors.. RR L ; ..by dividing by 4 SRL H RR L EX DE,HL ; Save in DE LD HL,(DMAX) ; ..while we compare to avail # LD H,0 PUSH HL OR A SBC HL,DE POP HL JR C,SMALR ; Jump if this won't fit EX DE,HL ; ..else save whole disk directory SMALR: LD A,L ; Get LS Byte LD (NDIRS),A ; ..and save it LD DE,-1 ; Preset counter LD BC,(SPTRK) ; ..and get Sectors per Track CALCLP: INC DE XOR A SBC HL,BC ; How many tracks for directory? JR NC,CALCLP ; Fall thru if DE = # of tracks LD HL,(OFFSET) ; Get reserved track count ADD HL,DE ; ..add # of directory tracks LD (TOPTRK),HL ; ..and save top directory track LD HL,(SECTBL) LD A,(DMAX) ; Space for this many entries LD B,A XOR A ; Fill table with Zero CLRLP: LD (HL),A INC HL DJNZ CLRLP LD (CURSEC),A ; Set current logical sector to 0 LD HL,(OFFSET) LD (TRK),HL ; Set starting track LD HL,(SECTBL) ; Get start of sector ID table LD (TEMP),HL ; ..and save LD HL,(DIR) ; Get start of sector buffer LD A,(NDIRS) ; Get number of Dir sectors to buffer LD B,A ; ..to count register ; Load translated sector table and sector data buffer SETTBL: PUSH BC ; Save count and address registers PUSH HL LD DE,(SKWTBL) ; Set up for translation LD A,(CURSEC) ; ..on current sector LD C,A LD B,0 INC A ; Bump logical sector number LD (CURSEC),A CALL BSCTRN ; Find translated sector LD A,L LD HL,(TEMP) LD (HL),A ; Store translated sector INC HL ; ..and bump table address LD (TEMP),HL LD C,A CALL BSETSC ; Set sector number POP BC ; Retrieve buffer address PUSH BC ; ..and keep on stack CALL BSTDMA ; Set DMA address to buffer sector LD BC,(TRK) CALL BSTTRK ; Set the physical track number CALL BREAD ; Now read the disk sector to memory POP HL ; Restore registers POP BC LD DE,128 ; Increment cache address ADD HL,DE LD A,(CURSEC) LD DE,(SPTRK) CP E ; Check for track overflow JR C,SETTB0 ; ..jump if same track LD DE,(TRK) INC DE ; Else bump track #.. LD (TRK),DE XOR A ; ..and zero sector number LD (CURSEC),A SETTB0: DJNZ SETTBL JR WEXIT ; Restore exit parameters & Exit ; BIOS Set Track routine keeping local copy SETTRK: LD (TRK),BC ; Save local track copy JP BSTTRK ; BIOS Set Sector routine keeping local copy SETSEC: LD (SCTR),BC ; Save local sector copy JP BSETSC ; BIOS Set DMA Address routine keeping local copy SETDMA: LD (DMADDR),BC ; Save local DMA address copy JP BSTDMA ; BIOS Read sector routine. If sector in memory, simply move data ; else jump to real BIOS and get data from disk READ: LD DE,(TRK) ; Directory track? LD HL,(TOPTRK) ; See if trk <= toptrk OR A SBC HL,DE JP C,BREAD ; if not dir, read disk CALL SETUP JP NZ,BREAD LD HL,0 ; Set "good read" return status PUSH HL ; ..once for HL PUSH HL ; ...and once for BC XOR A ; Show this is a Read PUSH AF ; ..with good return status ; Calculate address of desired sector in RAM buffer ; ENTRY: Reg C has relative sector number ; EXIT: HL register pair has buffer absolute address RAMW: PUSH AF ; Save flag status PUSH DE LD D,C LD E,0 SRL D RR E LD HL,(DIR) ADD HL,DE POP DE POP AF LD DE,(DMADDR) OR A ; Check which operation JR Z,RAM0 ; ..jump if read EX DE,HL ; Swap direction if Write RAM0: LD BC,128 LDIR WEXIT: POP AF POP BC POP HL RET ; BIOS Write Sector routine. If sector resident, update memory ; image in addition to disk data WRITE: LD A,C DEC A ; directory write? JP NZ,BWRITE ; ..jump if not CALL BWRITE PUSH HL ; save status PUSH BC PUSH AF CALL SETUP JR NZ,WEXIT OR 0FFH ; Show this is a Write JR RAMW ;-------------------------------------------------------; ; S U P P O R T R O U T I N E S ; ;-------------------------------------------------------; ; Check for presence of requested sector in memory buffer ; ENTRY: None ; EXIT: Found - Zero flag set ; Reg C has relative 128-byte sector offset ; Not Found - Zero flag cleared (reset) ; Reg A has 0FFH SETUP: LD A,(FSEL) ; Is this drive selected? OR A JR Z,SETUP8 ; ..indicate error return if not LD BC,(OFFSET) ; Find out how many tracks from 1st LD HL,(TRK) XOR A ; Get offset from Directory start SBC HL,BC LD A,L ; ..should be < 255 LD HL,0 ; Convert to # of sectors offset LD DE,(SPTRK) SETUP2: OR A JR Z,SETUP3 ADD HL,DE DEC A JR SETUP2 ; ..loop til finished SETUP3: LD C,L ; Copy # sectors to BC LD B,H EX DE,HL ; ..and store in DE LD HL,(NDIRS) ; Get # of dir sectors actually stored LD H,0 XOR A ; Subtract offset sectors SBC HL,BC JR C,SETUP8 ; Return Not Found if overflow LD B,L ; Put 8-bit sector count in B ; ..Sector offset stays in C LD HL,(SECTBL) ; Set address from table start ADD HL,DE LD A,(SCTR+1) ; Is it calling for sctr > 256? OR A JR NZ,SETUP8 ; ..not here if so LD A,(SCTR) ; See if sectors match RL1: CP (HL) JR Z,SETUP9 ; ..jump if found INC C INC HL DJNZ RL1 SETUP8: DEFB 0F6H ; Set Error w/"OR 0AFH" & Return SETUP9: XOR A RET ; Write a null-terminated string to the console device WRTLIN: LD A,(HL) ; Print null-terminated string OR A INC HL RET Z PUSH HL LD C,A BCONS EQU $+1 CALL 0000 POP HL JR WRTLIN BANNER: DEFB CR,LF,'(SPEEDUP ' PMTSIZ: DEFB '4 k, Drive ' PMTDRV: DEFB '0:)',0 ;---------------------------------------; ; D A T A A R E A ; ;---------------------------------------; ; Storage for data passed to BIOS SCTR: DEFS 2 ; Sector passed to BIOS TRK: DEFS 2 ; Track passed to BIOS DMADDR: DEFS 2 ; DMA Address passed to BIOS ; DPB and Skew Table address for active disk SPTRK: DEFS 2 ; Sectors per track DEFS 5 ; Room for BSH, BLM etc DIRMAX: DEFS 2 ; Directory maximum # entries DEFS 4 ; Room for CHK & ALV OFFSET: DEFS 2 ; Track offset SKWTBL: DEFS 2 ; Skew table address ; General Purpose pointer and buffer area FSEL: DEFS 1 ; drive selected flag LDISK: DEFS 1 ; Disk # active in RAM DIR: DEFS 2 ; Start of directory buffer RAM SECTBL: DEFS 2 ; Address of table of sector #s TOPTRK: DEFS 2 ; Top track that has directory CURSEC: DEFS 1 ; Current working sector DMAX: DEFS 1 ; Storage for maximum # dir sectors NDIRS: DEFS 1 ; Number of DIR sectors actually stored TEMP: DEFS 2 ; Temp pointer area DEFS 32 ; Local stack space STACK: DEFS 2 ; Storage for entry stack END