TITLE RAMDRIVE.MAC ; ;*********************************************************************** ; ; RAMDRIVE - A program that permits extended memory to function as ; a fast disk drive. This program does not require modification ; of the existing BIOS. ; ; Copyright 1982, by ; Herbert B. Shore ; Department of Physics ; San Diego State University ; San Diego, CA 92182 ; (619) 265-6159 ; ; Released to the public domain for non-commercial use. ; ;*********************************************************************** ; ; RAMDRIVE has been extensively modified by Paul J. Gans. Changes ; are copyright (c) by Paul J. Gans, Department of Chemistry, New ; York University, New York, NY 10003 (212) 598-2515 ; ; New or modified features include: ; ; For RAMDRIVE5: ; ; 1. Code has been converted to Z80 code throughout. ; 2. The target assembler is now Microsoft's M80. ; 3. The code is now self-loading. The original RAMLD program is ; no longer required. ; 4. It is no longer required to have contiguous memory banks of ; the same size. Available memory is controlled by the ; BLEN table described below. ; 5. Track size is now a variable multiple of 1K and can be ; changed through an equate. ; 6. The original ALV parameter has been dropped in favor of ; TRAKLEN, the number of kilobytes per track. ; 7. The DRAM parameter has been dropped. Extended (bank) ; addresses are now contained in the BLEN table. ; 8. The program now uses both the directory buffer and the host ; buffer in the local BIOS instead of its own buffer. ; This requires that the user know the addresses of both ; of these buffers in his or her BIOS. To accomodate ; those who choose not to use the BIOS buffers, two DS ; definitions are required a few lines after the label ; WBOOT1. The proper spot is commented in the code ; below. ; ;*********************************************************************** ; ; June 1986 - Minor modifications to RAMDRIVE to facilitate its ; use with 83 series Kaypro computers fitted with 256K RAM chips. ; These changes (trivial as they are!) are hereby released to ; the public domain for non-commercial use. ; ; Dr Michael Liddle, ; 21 The Frostings, ; Grenoside, SHEFFIELD, ; England, S30 3NZ. ; ; The main changes in version 6 are as follows :- ; ; 1. Bank switching is carried out by a new routine 'SWAP'. This ; makes porting RAMDRIVE to different systems easier by further ; isolating hardware dependencies from the main code. ; ; 2. Initially set to install on a pre 84 series Kaypro II with ; the 256K RAM modification described by me in MicroCornucopia ; issue ??? and the CP/M relocated to 63K using MOVCPM. ; ; 3. References to the IMSAI Panel have been removed as few ; micros today have a hardware front panel! ; ; 4. RAMDRIVE assumes that no interrupts will occur and take ; control away - if your system uses interrupts them insert ; DI and EI opcodes as needed. ; ;*********************************************************************** ; ; INSTALLATION of RAMDRIVE6: ; ; RAMDRIVE assumes that the user's system has "extra" memory ; available beyond the normal 64K maximum directly addressable ; in Z80 systems. This memory may be either "bank select" or ; S-100 extended addressing. ; ; RAMDRIVE is installed by setting a number of equates and by ; properly configuring the BLEN table located near the end of ; the code. After the proper values have been set by equates and ; the BLEN table has been set up, the code should be assembled ; using M80. The commands for so doing are: ; ; >M80 =RAMDRIVE6/L <== /L optionally produces a .PRN file ; >L80 /P:100,RAMDRIVE6,RAMDRIVE6/N/E ; ; The equates for DIRBUF and RAMBUF must be set to reflect the ; location of these buffers in the user's BIOS. If this is not ; feasible, see the comments at the label WBOOT1. ; ; Equates that must be set are defined and explained below. ; ; In normal use the user must also configure the BLEN table for ; his or her system and recompile. There is one BLEN table entry ; for each bank of memory to be used by RAMDRIVE. It is assumed ; that each of these banks starts at address 0000 and proceeds ; upward to some value without any holes. It is also assumed that ; at least the upper 1K of system memory is global, thus no bank ; can exceed 63K. ; ; A BLEN table entry consists of two bytes for each bank of memory ; to be used by RAMDRIVE. The first byte is the number of kilo- ; bytes available for RAMDRIVE in that bank. This value is placed ; into the BLEN table as the value divided by TRAKLEN. The actual ; number of kilobytes of that bank used by RAMDRIVE is the integral ; part of the division. For instance a 30K bank of memory would ; be indicated to the system as 30/TRAKLEN. ; ; The second byte in the BLEN table entry is the extended (or ; bank) address byte for that bank of memory. There is one such ; entry pair for each bank. The table is terminated by a single ; zero byte. ; ; Thus a system with 20K at a bank addressed as 0DEH and 8K at a ; bank addressed as 70H could have a BLEN table as: ; ; BLEN: DB 20/TRAKLN,0DEH ; DB 08/TRAKLN,70H ; DB 0 ; ; while the same system in which the user wanted to reserve 4K on ; the board at 0DEH for some other purpose could have a BLEN table ; as: ; ; BLEN: DB 16/TRAKLN,0DEH ; DB 08/TRAKLN,70H ; DB 0 ; ; ;************************************************************************ ; ; The code and tables in this file will reside in high memory, above the ; existing BIOS. The system is self-loading. Typing RAMDRIVE6 from the ; console is sufficient to initiate RAMDRIVE6. ; .Z80 ; FALSE EQU 0 TRUE EQU NOT FALSE ; ; The following equates are system dependent. ; ; DIRBUF: This is the address of the CP/M directory buffer in the ; user's BIOS. CP/M 2.x systems are required to have such a buffer ; available. The address will vary in different implementations. ; ; RAMBUF: This is the address of the CP/M host buffer in the user's ; BIOS. In a normal CP/M 2.x system this buffer will be at least 1K ; long. The address will vary in different implementations. ; ; RAMDRIVE: Set to a memory location above BIOS. Less than 1K of ; GLOBAL memory is required at this location; i.e. the same block ; of memory must be accessible independent of the setting of the ex- ; tended address bus or any bank byte. ; ; PRAM: The extended address of regular program RAM. Usually this is ; 00H, but need not be. ; ; DNAME: The alphabetic designation of the RAM drive. ; ; TRAKLN: The number of kilobytes per track. This must be a minimum ; of 1K and a maximum no greater than the smallest bank of memory to ; be made available to RAMDRIVE. A good value to use is the greatest ; common divisor of each of the memory banks to be used by RAMDRIVE. ; ; DIRECT: The number of directory entries permitted on the RAM drive. ; The number specified must be a multiple of 32. I used 32 to leave ; the maximum space for program files. ; .Z80 ; ;DIRBUF EQU 0????H ; CP/M BIOS directory buffer address ;RAMBUF EQU 0????H ; CP/M BIOS host buffer RAMDRIVE EQU 0F800H ;START OF PROGRAM ABOVE BIOS. PRAM EQU 07H ;EXTENDED ADDR. OF MAIN RAM DNAME EQU 'D' ;DRIVE NAME OF RAMDRIVE. TRAKLN EQU 4 ; kilobytes per track DIRECT EQU 32 ;NO. OF DIRECTORY ENTRIES. ; ; These equates will normally not need to be changed. ; BDOS EQU 5 DELCHR EQU 0E5H ;DELETED DIRECTORY ENTRY. DNUMB EQU DNAME - 'A' ;RAMDRIVE DRIVE NUMBER CR EQU 0DH LF EQU 0AH ; ; ; The code below replaces the original loader code, since that ; mechanism will not work on a program compiled under M80. The ; M80 .PHASE commands have been used rather than the original ; ORG's. ; LD DE,SIGNON ; print signon message from loader LD C,9 CALL BDOS ; LD HL,(0001) ; check to see if BIOS modified INC HL ; point to jump vector LD E,(HL) INC HL LD D,(HL) EX DE,HL LD DE,RAMDRIVE AND A ; clear carry SBC HL,DE ; WBOOT minus RAMDRIVE JP C,CONTIN ; if carry we are OK LD DE,NOWAY LD C,9 CALL BDOS JP 0 ; SIGNON: DB 'RAMDRIVE Version 6 - Mike Liddle June 1986' DB CR,LF,'$' NOWAY: DB 'Cannot load RAMDRIVE',CR,LF DB 'Cold boot system and try again' DB CR,LF,'$' ; CONTIN: LD HL,SETUP LD DE,RAMDRIVE LD BC,ENDRAM-RAMDRIVE ; 1023 LDIR JP RAMDRIVE ; .PHASE RAMDRIVE ; ; ORIGINAL JUMP TABLE FROM BIOS ; WBOOT1: DS 48 WCK: ;END OF BIOS TABLE. ; CSV: DS DIRECT/4 ; this should probably be zero since no ; checking is done ALV: DS 72 ; this is allocation vector space which ; must have 1 bit available per block. ; this value corresponds to 576 1K ; blocks. ; ; If the user does not wish to (or cannot) use the directory and host ; buffers in the system BIOS, the buffers can alternatively be defined ; here. In this case the following lines should be uncommented and the ; corresponding equates above commented. ; DIRBUF: DS 128 ; directory buffer RAMBUF: DS 128 ; bank communication buffer ; ENDTBL: ;END OF DATA TABLES. ; .DEPHASE ; ; The following code is executed once to set up the RAMDRIVE system. In ; order to conserve space it will be overwritten by data buffers during ; actual access to RAMDRIVE. ; ; SETUP: ; .PHASE RAMDRIVE ; ; Determine the amount of available RAMDRIVE memory ; XOR A LD C,A LD HL,BLEN ; RAMDRIVE memory table LD DE,0002 ; table entry increment BCHEK0: LD A,(HL) ; get bank kilobytes a OR A ; zero means end of table JR Z,BCHEK1 ADD A,C ; accumulate count LD C,A ; and save it ADD HL,DE ; point to next BLEN entry JR BCHEK0 ; BCHEK1: CP C ; is there any ram available at all? JR NZ,RAMOK ; jump if there is LD DE,NORAM ; no ram, tell the user LD C,9 CALL BDOS RET ; avoid warm boots! ; NORAM: DB 'Cannot activate RAMDRIVE. No available RAM.' DB CR,LF,'$' ; RAMOK: XOR A ; clear counter LD B,TRAKLN ; the count must be multiplied ; by TRAKLN to yeild kilobytes RAMOK1: ADD A,C ; multiply by repeated adding DJNZ RAMOK1 ; DEC A ; RAMDRIVE kilobytes minus 1 LD (DSM),A ; maximum block number to DPB ; ; MODIFY BIOS JUMP TABLES ; IF $ LT WCK ;MAKE SURE THAT WBOOT1 TABLE JP BJUMP ;WILL NOT OVERWRITE ENDIF ;BJUMP ROUTINE. IF $ LT WCK DEFS WCK - $ ENDIF ; BJUMP: LD HL,(1) ;GET ADDRESS OF WARM BOOT LD DE,WBOOT1 ;TRANSFER TABLE FROM BIOS UP HERE LD BC,48 ;48 BYTES LDIR LD HL,WBOOT2 ;TRANSFER OUR TABLE TO BIOS LD DE,(0001) LD BC,48 LDIR ; ; PRINT MESSAGE AND ASK QUESTION ; LD DE,QUEST LD C,9 ;PRINT STRING CALL BDOS LD C,1 ;GET CHARACTER CALL BDOS RES 5,A ;CONVERT TO UPPER CASE. CP 'Y' JP NZ,QUIT ; ; CLEAR DIRECTORY OF RAMDRIVE ; LD BC,0000 ; directory on track 0 sector 0 CALL MAP CALL SWAP EX DE,HL ; HL = base location of directory LD DE,32 ;EVERY 32 BYTES LD B,DIRECT ;NO. OF ENTRIES. LD A,DELCHR CLEAR: LD (HL),A ADD HL,DE DJNZ CLEAR LD A,PRAM ;RESET EXT. ADDR. CALL SWAP ; QUIT: LD DE,CRLF LD C,9 CALL BDOS JP 0 ;BACK TO CP/M. ; QUEST: DB CR,LF DB 'RAMDRIVE active on drive ',DNAME DB CR,LF DB 'Should directory of drive ',DNAME DB ' be cleared (Y/N)? $' CRLF: DB CR,LF,'$' ; ; NEW TABLE COPIED INTO BIOS ; WBOOT2: JP WBOOT JP WBOOT1+3 JP WBOOT1+6 JP WBOOT1+9 JP WBOOT1+12 JP WBOOT1+15 JP WBOOT1+18 JP HOME ;21 JP SELDSK ;24 JP SETTRK ;27 JP SETSEC ;30 JP SETDMA ;33 JP READ ;36 JP WRITE ;39 JP WBOOT1+42 JP SECTRN ;45 ; ; IMPLEMENT BIOS FUNCTIONS ; IF $ LT ENDTBL ;MAKE SURE THAT BIOS DEFS ENDTBL - $ ; FUNCTIONS BEGIN ENDIF ; AFTER TABLES. ; WBOOT: LD HL,80H ;SET INITIAL DMA ADDR. LD (DMAADR),HL JP WBOOT1 ;BACK TO BIOS ; ; HOME: LD A,(DISK) ;CHECK DISK NUMBER. CP DNUMB ;IS IT THE RAMDRIVE? JP NZ,WBOOT1+21 ;IF NOT, LET BIOS HANDLE IT. LD A,0 ;SET "TRACK" TO 0 LD (XTRAK),A RET ; ; SELDSK: LD A,C ;CHECK REQUESTED DISK, LD (DISK),A CP DNUMB JP NZ,WBOOT1+24 LD HL,DPH ;RETURN DISK PAR. HEADER. RET ; ; DISK PARAMETER HEADER FOR RAMDRIVE ; DPH: DW 0 ;NO SECTOR TRANSLATION DW 0,0,0 ;SCRATCH DW DIRBUF ;LOC. OF SCRATCHPAD AREA. DW DPB ;DISK PARAMETER BLOCK DW CSV ;DIR. CHECK AREA DW ALV ;ALLOC. VECTOR. ; ; DISK PARAMETER BLOCK ; DPB: DW (1024*TRAKLN)/128 ;SECTORS PER TRACK DB 3 ;BSH DB 7 ;BLM DB 0 ;EXM DSM: DW 62 ;MAX BLOCK NO. DW DIRECT-1 ;HIGHEST DIRECT. NO. ; AL0 EQU LOW (0FFH SHL (8-DIRECT/32)) AL1 EQU 0 ; DB AL0,AL1 ;DIRECTORY BLOCKS. ; CKS EQU 0 ;CHECK DIRECT. ENTRIES. ; DW CKS DW 0 ;NO SKIPPED TRACKS. ; ; SETTRK: LD A,(DISK) CP DNUMB JP NZ,WBOOT1+27 LD A,C ;TRACK NO. LD (XTRAK),A RET ; ; SETSEC: LD A,(DISK) CP DNUMB JP NZ,WBOOT1+30 LD (SECTOR),BC RET ; ; SETDMA: LD (DMAADR),BC ;SAVE DMA ADDR. BOTH HERE JP WBOOT1+33 ;AND IN BIOS. ; ; READ: LD A,(DISK) CP DNUMB JP NZ,WBOOT1+36 LD BC,(SECTOR) ; but we asssume sector fits in one byte LD A,(XTRAK) ;SET EXTENDED ADDRESS. LD B,A CALL MAP ; to compute bank and offset CALL SWAP EX DE,HL LD DE,RAMBUF ;TEMPORARY BUFFER. LD BC,128 ;SECTOR=128 BYTES. LDIR LD A,PRAM ;RESET ADDR. CALL SWAP LD HL,RAMBUF ;MOVE FROM BUFFER LD DE,(DMAADR) ; back to main ram LD BC,128 LDIR XOR A ; show no errors RET ; ; WRITE: LD A,(DISK) CP DNUMB JP NZ,WBOOT1+39 LD HL,(DMAADR) ;DMA --> BUFFER LD DE,RAMBUF LD BC,128 LDIR ; LD BC,(SECTOR) ; but we assume sector < 256 LD A,(XTRAK) LD B,A CALL MAP CALL SWAP LD HL,RAMBUF ;BUFFER --> RAMDRIVE. LD BC,128 LDIR ; LD A,PRAM CALL SWAP XOR A ; show no error RET ; ; SECTRN: LD A,(DISK) CP DNUMB JP NZ,WBOOT1+45 LD H,B LD L,C RET ; ; ; Subroutine to calculate RAM address and bank ; ; called with B = track number (starts from 0) ; C = sector number (starts from 0) ; ; returns with A = extended address byte ; DE = offset into bank for start of sector ; MAP: XOR A ; clear A LD A,B ; track number to A LD DE,2 ; increment for BLEN table LD HL,BLEN ; MAP1: SUB (HL) ; subtract bank length in K's JR C,MAP2 ; jump if track in this bank ADD HL,DE ; point to next BLEN entry JR MAP1 ; repeat till done ; MAP2: ADD A,(HL) ; A = relative track number in bank RLCA ; multiply by 4K RLCA RLCA RLCA LD E,D ; clear E LD D,C ; multiply sector number by 128 RR D RR E ADD A,D ; add to track starting address LD D,A ; DE = sector start in bank INC HL LD A,(HL) ; A = extended (bank) address RET ; ;******************************************************************* ; ; This is where banks are switched. Register A contains the ; bank to be selected. ; ;******************************************************************* ; PIOData EQU 01EH ; SYSPIO port B data PIOCtrl EQU 01FH ; SYSPIO port B control Mode3 EQU 0CFH ; Mode3 = Control IOMask EQU 0F8H ; Bits 0,1,2 as output. Rest as input. SWAP: LD C,A ; Save bank LD A,Mode3 ; Set up PIO for bank select OUT (PIOCtrl),A ; Mode 3 LD A,IOMask OUT (PIOCtrl),A ; Bits 0,1,2 are output LD A,C ; Bank 7 selected for TPA OUT (PIOData),A RET ; ;******************************************************************* ; BLEN: DB 32/TRAKLN,00H DB 32/TRAKLN,01H DB 32/TRAKLN,02H DB 32/TRAKLN,03H DB 32/TRAKLN,04H DB 32/TRAKLN,05H DB 0 ; end of table ; ; DATA STORAGE AREA ; DISK: DB 0 XTRAK: DB 0 DMAADR: DW 80H SECTOR: DW 0 ; ENDRAM EQU $ ; .DEPHASE ; END