title 'RAMDISK - A Memory-Based Virtual Drive' ; THIS PROGRAM IS HEREBY PLACED IN THE PUBLIC DOMAIN, ; AND MAY BE FREELY COPIED AND DISTRIBUTED. ; program: RAMDISK ; ; created by Context Sensitive Inc. ; 4200 Aurora Ave. N. ; Seattle, WA 98103 ; (206) 632-0301 ; ; version: 1.1 October 28, 1983 ; author: Ron Blanford ; ; The handler code for the RAM disk takes approximately 250h bytes, ; or just over 1/2 kbyte. In versions of CP/M-86 which include ; hard disk support, the hard disk initialization code is only ; executed once at cold boot, so this program can overlay it with the ; handler code to save on memory usage. To enable the overlay ; logic, terminate the allocation size with a 'K', for example: ; RAMDISK 128K ; Otherwise the handler code will be placed at the beginning of ; the TPA, reducing the available memory by a small amount. ; ; In the standard CP/M the default interrupt vector does nothing but ; an IRET and return to the program, effectively making all unplanned ; interrupts (such as arithmetic exceptions and pressing the keyboard ; reset button) invisible. This program causes any such interrupt ; to perform a warm boot, returning the user to the CP/M prompt. BIOS_segment equ 0040h BIOS_jumptable equ 2500h cseg org 100h mov dx,offset T_GETSEGT ;get available memory size for messages mov cl,50 int 224 mov ax,BIOS_segment mov es,ax mov ax,es:3[bx] mov cl,6 ;convert from pages to kbytes shr ax,cl push ax mov bx,offset h1_size+2 call binasc pop ax push ax mov bx,offset h4_size+2 call binasc pop ax mov bx,offset nm_size+2 call binasc mov dx,offset company_name ;print company name message mov cl,9 int 224 mov bx,80h ;check command buffer mov cl,[bx] ; if no command tail was entered, or cl,cl ; display help screens jnz RD04 mov dx,offset help1 mov cl,9 int 224 mov cl,1 int 224 cmp al,ctrl_C jnz $+5 jmp exit1 mov dx,offset help3 mov cl,9 int 224 mov cl,1 int 224 cmp al,ctrl_C jnz $+5 jmp exit1 mov dx,offset help4 jmp exit RD04: mov dx,offset T_SELDSK ;see if drive already exists mov cl,50 int 224 or bx,bx jz RD05 mov dx,offset I_exists jmp exit RD05: mov bx,80h ;get allocation size from command buffer mov cl,[bx] sub ch,ch sub ax,ax RD10: inc bx ;convert ascii digits to binary cmp byte ptr [bx],' ' jbe RD20 cmp byte ptr [bx],'0' jb RD21 cmp byte ptr [bx],'9' ja RD21 mul ten mov dl,byte ptr [bx] sub dl,'0' add ax,dx RD20: loop RD10 RD21: or ax,ax ;make sure size specification is in range jnz RD30 mov dx,offset nosize jmp exit RD30: mov CBOOT_overlay,1 ;if nnnK entered, then put handlers or byte ptr [bx],20h ; in space occupied by CBOOT code cmp byte ptr [bx],'k' jz RD35 mov CBOOT_overlay,0 RD35: cmp ax,512 ;max RAMDISK size is 512K jbe RD40 mov ax,512 RD40: push ax ;put allocation in 'created' message mov bx,offset cr_size+2 call binasc pop ax mov cl,6 cmp ax,256 ;if >256K, then change parameters jbe RD45 ; to block at 2048 mov byte ptr BSH,4 ; rather than default 1024 mov byte ptr BLM,15 mov byte ptr EXM,1 mov word ptr DRM,127 shr ax,1 mov cl,7 RD45: mov word ptr DSM,ax dec word ptr DSM shl ax,cl mov disk_pages,ax RD50: mov dx,offset T_GETSEGT ;see if enough memory exists mov cl,50 int 224 mov ax,BIOS_segment mov es,ax mov dx,es:3[bx] ;number of pages available cmp CBOOT_overlay,1 jz RD55 mov ax,offset end_Kdrive ;this code puts the RAMDISK handlers sub ax,offset init_Kdrive ; at the beginning of the TPA mov cl,4 ; rather than overlaying CBOOT code. shr ax,cl inc ax sub dx,ax RD55: sub dx,disk_pages ja RD60 mov dx,offset nomem jmp exit RD60: mov es:3[bx],dx ;save new TPA length mov di,es:.BIOS_jumptable+1 add di,BIOS_jumptable+3 cmp CBOOT_overlay,1 jz RD65 mov di,es:1[bx] ;this code puts the RAMDISK handlers add es:1[bx],ax ; at the beginning of the TPA mov ax,es ; rather than overlaying CBOOT code. sub di,ax mov cl,4 shl di,cl RD65: mov init_addr,di add dx,es:1[bx] mov disk_seg,dx mov bx,BIOS_jumptable+18h ;move BIOS jumptable to local table mov di,offset BIOS_HOME ; after converting from relative mov cx,10 ; to absolute addressing RD70: inc bx mov ax,es:[bx] inc bx inc bx add ax,bx mov [di],ax inc di inc di loop RD70 mov dx,init_addr ;move my entry points to BIOS jump table sub dx,2 sub dx,offset init_Kdrive mov di,BIOS_jumptable+18h inc di mov ax,offset HOME add ax,dx sub ax,di mov es:[di],ax add di,3 mov ax,offset SELDSK add ax,dx sub ax,di mov es:[di],ax add di,3 mov ax,offset SETTRK add ax,dx sub ax,di mov es:[di],ax add di,3 mov ax,offset SETSEC add ax,dx sub ax,di mov es:[di],ax add di,3 mov ax,offset SETDMA add ax,dx sub ax,di mov es:[di],ax add di,3 mov ax,offset READ add ax,dx sub ax,di mov es:[di],ax add di,3 mov ax,offset WRITE add ax,dx sub ax,di mov es:[di],ax add di,6 ;skip list status jump mov ax,offset SECTRAN add ax,dx sub ax,di mov es:[di],ax add di,3 mov ax,offset SETDMAB add ax,dx sub ax,di mov es:[di],ax sub ax,ax ;set up interrupt handler mov es,ax ; by replacing normal IRET mov di,es:.0 ; with JMP to my handler mov ax,es:.2 mov es,ax mov al,0E9h ;JMP instruction mov es:[di],al inc di mov ax,offset inttrap add ax,dx sub ax,di mov es:[di],ax add dx,2 ;change local addresses to new location mov adj_offset,dx add DPH_offset,dx add DIRBUF_offset,dx add DPB_offset,dx add CSV_offset,dx add ALV_offset,dx mov di,init_addr ;move code and data into BIOS mov si,offset init_Kdrive mov cx,offset end_Kdrive sub cx,si shr cx,1 inc cx cld rep movs ax,ax mov dx,offset created mov cl,9 int 224 jmpf dword ptr init_addr ;go execute disk initialization routine init_addr dw BIOS_jumptable+100h dw BIOS_segment ; BINASC converts an unsigned binary number to ascii representation. ; Input registers: ax = number to convert ; bx = ptr to memory location ; for least significant digit binasc: mov byte ptr [bx],'0' mov cx,10 ba10: mov dx,0 ;convert ax to ascii div cx or ax,ax jnz ba15 or dx,dx jz ba20 ba15: or dl,'0' mov byte ptr [bx],dl ;store ascii digit in display area dec bx jmps ba10 ba20: ret exit1: mov dx,offset abort_msg exit: mov cl,9 int 224 mov dx,0 mov cl,0 int 224 eject ctrl_C equ 03h cr equ 0Dh lf equ 0Ah esc equ 1Bh ten dw 10 CBOOT_overlay db 1 ;1=overlay CBOOT code, 0=use part of TPA T_SELDSK db 9 ;direct BIOS call for disk selection dw 10 dw 0 T_GETSEGT db 18 ;direct BIOS call for memory extents dw 0 dw 0 company_name db esc,'[1;1H',esc,'[J',cr,lf,' ',esc,'[2;3m ',esc,'[3;23m' db ' RAMDISK 1.1 ' db esc,'[2m ',esc,'[m',cr,lf,' ',esc,'[2;4m ',esc,'[4;20m' db ' Context Sensitive Inc. Seattle, Washington (206) NEC-0301 ' db esc,'[2m ' db esc,'[m',cr,lf,'$' help1 db cr,lf,esc,'[19m' db cr,lf,' Thank you for choosing RAMDISK from Context Sensitive Inc.' db cr,lf,esc,'[20m' db cr,lf,' This program creates a pseudo disk drive using part of the' db cr,lf,' random access memory (RAM) of your computer. Your computer' db cr,lf,' has ' h1_size db ' ' db ' kbytes of memory available for program execution.' db cr,lf,' Most programs require less than 64 kbytes, so any remaining' db cr,lf,' memory would otherwise be unused.' db cr,lf db cr,lf,' The main advantage of using a RAM disk is its speed. The' db cr,lf,' main drawback is that it is not permanent. Each time the' db cr,lf,' computer is turned off or CP/M-86 rebooted using the' db cr,lf,' CTRL-FNC-BREAK sequence, all files stored on the RAM disk' db cr,lf,' are deleted and the RAM disk itself is eliminated. Therefore' db cr,lf,' be sure to save all modified files on a permanent disk at' db cr,lf,' the end of every session with the computer. In an emergency' db cr,lf,' press the reset button behind the rubber stopper in the key-' db cr,lf,' board to return to CP/M-86 without erasing the RAM disk.' db cr,lf db esc,'[25;1H',esc,'[21m Press any key to continue...',esc,'[m$' help3 db esc,'[7;1H',esc,'[J' db cr,lf,' The RAM disk created by this program is called drive K.' db cr,lf,' Drive K is used the same way as any other disk drive. To' db cr,lf,' list the directory of files, type:' db cr,lf,esc,'[23m DIR K:',esc,'[20m' db cr,lf,' (Initially drive K is empty and this command will give the' db cr,lf,' NO FILE message.) To copy programs and data files to' db cr,lf,' drive K, type:' db cr,lf,esc,'[23m PIP K:=filename.typ',esc,'[20m' db cr,lf,' To select drive K as the default drive, just type:' db cr,lf,esc,'[23m K:',esc,'[20m' db cr,lf,' in response to the CP/M-86 prompt.' db cr,lf db esc,'[25;1H',esc,'[21m Press any key to continue...',esc,'[m$' help4 db esc,'[7;1H',esc,'[J' db cr,lf,' To create the RAM disk, type:' db cr,lf,esc,'[23m RAMDISK nnn',esc,'[20m' db cr,lf,' where nnn is the number of kbytes of memory to allocate for' db cr,lf,' drive K. Remember, this must be less than ' h4_size db ' ' db ' kbytes.' db cr,lf,esc,'[m$' abort_msg db 0Bh,esc,'[m',esc,'[J$' nosize db cr,lf,esc,'[19m' db cr,lf,' A size must be specified for RAMDISK drive K' db cr,lf,esc,'[21m' db cr,lf,' for example: ''RAMDISK 128'' allocates 128K of memory' db esc,'[m',cr,lf,'$' nomem db cr,lf,esc,'[19m' db cr,lf,' RAMDISK drive K not created - not enough memory' db cr,lf,esc,'[21m' db cr,lf,' Your computer only has ' nm_size db ' ' db ' kbytes of memory available' db esc,'[m',cr,lf,'$' I_exists db cr,lf,esc,'[19m' db cr,lf,' RAMDISK drive K not created - it already exists' db cr,lf,esc,'[21m' db cr,lf,' CTRL-FNC-BREAK deletes all files and removes the drive' db esc,'[m',cr,lf,'$' created db cr,lf,esc,'[19m' db cr,lf,' RAMDISK drive K has been created (' cr_size db ' ' db ' kbytes)' db cr,lf,esc,'[21m' db cr,lf,' CTRL-FNC-BREAK deletes all files and removes the drive' db esc,'[m',cr,lf,'$' title 'RAMDISK initialization and handler code' eject init_Kdrive: call adjust mov es,disk_seg[bx] mov ax,disk_pages[bx] init1: push ax ;format the disk area mov cx,8000h cmp ax,1000h ja init2 mov cl,3 shl ax,cl mov cx,ax init2: mov di,0 mov ax,0E5E5h cld rep stos ax mov ax,es add ax,1000h mov es,ax pop ax sub ax,1000h ja init1 mov dx,0 mov cl,0 int 224 HOME: call adjust cmp byte ptr sek_dsk[bx],10 jz $+7 jmp BIOS_HOME[bx] ret SELDSK: call adjust mov byte ptr sek_dsk[bx],cl cmp cl,10 jz $+7 jmp BIOS_SELDSK[bx] mov bx,DPH_offset[bx] ret SETTRK: call adjust cmp byte ptr sek_dsk[bx],10 jz $+7 jmp BIOS_SETTRK[bx] mov sek_trk[bx],cx ret SETSEC: call adjust cmp byte ptr sek_dsk[bx],10 jz $+7 jmp BIOS_SETSEC[bx] mov sek_sec[bx],cl ret SETDMA: call adjust mov DMA_offset[bx],cx jmp BIOS_SETDMA[bx] READ: call adjust cmp byte ptr sek_dsk[bx],10 jz $+7 jmp BIOS_READ[bx] pushf push ds push es mov es,DMA_seg[bx] mov di,DMA_offset[bx] mov ax,sek_trk[bx] mov cl,6 shl ax,cl add al,sek_sec[bx] mul one_twenty_eight[bx] mov cl,12 shl dx,cl add dx,disk_seg[bx] mov ds,dx mov si,ax mov cx,64 cld rep movs ax,ax pop es pop ds popf sub ax,ax ret WRITE: call adjust cmp byte ptr sek_dsk[bx],10 jz $+7 jmp BIOS_WRITE[bx] pushf push ds push es mov ax,sek_trk[bx] mov cl,6 shl ax,cl add al,sek_sec[bx] mul one_twenty_eight[bx] mov cl,12 shl dx,cl add dx,disk_seg[bx] mov es,dx mov di,ax mov si,DMA_offset[bx] mov ds,DMA_seg[bx] mov cx,64 cld rep movs ax,ax pop es pop ds popf sub ax,ax ret SECTRAN: call adjust cmp byte ptr sek_dsk[bx],10 jz $+7 jmp BIOS_SECTRAN[bx] mov bx,cx ret SETDMAB: call adjust mov DMA_seg[bx],cx jmp BIOS_SETDMAB[bx] inttrap: cli pop ax ;pop old IP, CS, and flags pop ax pop ax or ax,0200h ;enable interrupts on return push ax mov ax,BIOS_segment ;return to WBOOT push ax mov ax,BIOS_jumptable+3 push ax iret adjust: nop ;all variables to be offset db 0BBh ; by the amount the program moved adj_offset dw 0 ;this is a MOV BX,nnnn instruction ret eject BIOS_HOME DW 0 BIOS_SELDSK DW 0 BIOS_SETTRK DW 0 BIOS_SETSEC DW 0 BIOS_SETDMA DW 0 BIOS_READ DW 0 BIOS_WRITE DW 0 BIOS_LISTST DW 0 BIOS_SECTRAN DW 0 BIOS_SETDMAB DW 0 sek_dsk db 0 sek_sec db 0 sek_trk dw 0 DMA_offset dw 0 DMA_seg dw 0 disk_pages dw 0 disk_seg dw 0 one_twenty_eight dw 128 DPH_offset dw offset DPH DPH dw 0 ;no sector translation dw 0 dw 0 dw 0 DIRBUF_offset dw offset DIRBUF DPB_offset dw offset DPB CSV_offset dw offset CSV ALV_offset dw offset ALV DIRBUF rs 128 CSV rs 0 ALV rs 32 ;disk size: <256K >256K DPB dw 64 ;SPT BSH db 3 ;BSH 3 4 BLM db 7 ;BLM 7 15 EXM db 0 ;EXM 0 1 DSM dw 0 ;DSM #K-1 (#K/2)-1 DRM dw 63 ;DRM 63 127 db 0C0h ;AL0 db 0 ;AL1 dw 0 ;CKS dw 0 ;OFF end_Kdrive db 0 end