title	ramdvr 01-01-84        [01-01-84]
;-------------------------------------------------------------------------------
; RAMDVR.SYS -- Modification to Dan O'Brien's excellent program by
;		Tom Perry, CIS 70455,751 or FORUM ][ 305/772-4444.
;
;		This modified version performs the same function described
;		below.	The only difference is that it runs as a "device
;		driver" on DOS 2.0 and up.  This means not only that it gets
;		control earlier and thus works faster, but also that it will
;		not cripple the system if you want to install a device that
;		takes a fair amount of memory.	For instance, I had a virtual
;		disk driver that uses 180K.  With switches set for 64K, it
;		could not be installed.  To get around this with MORRAM.COM,
;		you have to put logic in AUTOEXEC.BAT to switch between two
;		CONFIG.SYS files; it can be done (I did it for a while), but
;		it's messy and takes more disk space -- a LOT more if you're
;		working with a hard file with its large allocation unit.
;
;		To use this version, simply create a file on your boot disk
;		named CONFIG.SYS containing the line DEVICE=RAMDVR.SYS
;		and copy RAMDVR.SYS onto the boot disk.  If you already have
;		a CONFIG file, enter DEVICE=RAMDVR.SYS as its first line.
;		Set your switches for 64K, turn on the machine, and notice
;		the difference.  To learn how it works, read Dan's description
;		below.
;
;		There IS a penalty for doing it this way: Part of the program
;		remains permanently installed in the system as a device driver,
;		eating up a few bytes of precious RAM.	I have left enough to
;		keep the system from crashing if the device driver is driven
;		again (for instance, by a MODE RAMCHECK command).  More bytes
;		could be saved if you're willing to take that slight risk;
;		probably the minimum you'd need to keep is the four bytes
;		constituting the device driver chain at label "next_dev";
;		uncomment the indicated line if you want to try this.


; MORERAM.COM - by Daniel M. O'Brien (v 1.0) 21 Dec 1983
;
;	      - freely adapted from a PC-WORLD User-to-User column program
;		of the same name (object disassembled using ASMGEN) and from
;		a program shown in a DR. DOBBS Journal article
;		(16 bit Toolkit) called MEMSIZE.
;
; This program has two (or three) purposes.
;
;	1) Allow a PC to use more memory than is allowed via the motherboard
;	memory switches (544 K bytes for the 64K motherboard and 640 K bytes
;	for the newer 256K motherboard). And because of 1)...
;
;	2) Allow faster power-up sequence by setting the motherboard memory
;	switch settings to 64 K bytes installed.
;
;	And as long as we are in the neighborhood...
;
;	3) Patch the ROM BIOS data area to indicate that this PC has four
;	floppy diskettes installed (instead of the normal two). This is for
;	ram disk emulation programs that require the motherboard equipment
;	options switch to be set to include the number of ram disks.
;	This is most notably required by the AST RESEARCH ramdisk program
;	called SUPERDRV. This code is commented out. To use it you must
;	uncomment out the code and reassemble. Search for the string:
;
;			;stub***
;
; Using MORERAM.
;
;	First, copy MORERAM.COM to your boot device (floppy or fixed).
;	Next, create or edit your AUTOEXEC.BAT file found on your
;	boot device to include MORERAM as the **FIRST** program that
;	will be executed. This is important as results are not guaranteed
;	if MORERAM is not the first command executed at boot time.
;	Next, open the covers of your PC and set the memory switches
;	to indicate that your PC only has 64K.
;
;	Now try rebooting your PC using the Alt-Ctrl-Del sequence.
;
;	MORERAM will first display a hello banner and the amount of
;	memory DOS thinks your PC has (should be 64K). Next, MORERAM
;	will pause a second or two while it determines how much memory
;	your PC really has. (It also clears this memory in the process
;	to eliminate PARITY 2 errors later).
;	Once the physical memory limit is determined, MORERAM will display
;	that amount and then automatically re-boot. (Don't get excited,
;	this won't loop indefinitely, because...) The next time MORERAM
;	is again executed from your AUTOEXEC.BAT it will find that the amount
;	of memory DOS thinks you have will be the same as that installed, and
;	a reboot will be avoided!
;
; I use this program on my PC that has 576K (64K + 512K) worth of memory.
; Also, I have successfully tested it with 704K (64K + 512K + 128K) of memory,
; but this requires placing memory into the semi-forbidden zone (segment A000)
; designated by IBM as "reserved". But that's ok, as long as you don't install
; memory beyond this into the B000 segment where monochrome and graphics display
; memory live!
;
; Questions or comments should be left for me (DAN OBRIEN) on Gene Plantz'
; BBS in Chicago, IL (312-882-4227). I will attempt to fix bugs that may
; crop up, but I make no guarantees. You use this at your own risk (just like
; I do!). If you break something valuable, it's your own fault.
;
;-------------------------------------------------------------------------------


lf	equ	0ah
cr	equ	0dh
;
;initial values :	cs:ip	0000:0100
;			ss:sp	0000:ffff

s0000	segment
	assume ds:s0000, ss:s0000 ,cs:s0000 ,es:s0000
	org	$+0000h
;
;	device driver header and logic added 1-1-84 by Tom Perry.
;
next_dev	dd	-1
		dw	8000h	       ;char device
strategy	dw	dstrategy
interrupt	dw	dinterrupt
whatcall	db	'RAMCHECK'      ;name

dstrategy	proc	far

	mov	cs:rh_seg,es
	mov	cs:rh_off,bx		;save ptr to request header
	ret

dstrategy	endp

rh_off	dw	0
rh_seg	dw	0

dinterrupt	proc	far

	cld
	push	ds
	push	es
	push	ax
	push	bx
	push	cx
	push	dx
	push	di
	push	si

	mov	al,switch
	cmp	al,0ffh
	je	continue
	mov	al,0ffh
	mov	switch,al

	call	memdrvr

	mov	bx,rh_off
	mov	ax,rh_seg
	mov	es,ax		;pt to req hdr
	mov	ds,ax
	mov	ax,offset last_place
;*risk	mov	ax,offset strategy ;USE THIS LINE TO SAVE RAM AT SOME RISK!
	mov	14[bx],ax	;set ending address
	mov	ax,cs
	mov	16[bx],ax	; including segment
continue:
	mov	ax,0100h
	or	3[bx],ax	;set device status as DONE with NO ERROR

	pop	si
	pop	di
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	pop	es
	pop	ds

	ret

switch	db	0,0,0		;one time switch & bug protection
last_place db	'LAST PLACE'

dinterrupt	endp


memdrvr proc	near

;	end of device driver modifications by Tom Perry
;	(except as noted below).

start:	jmp	begin

hello	db	"Device driver to use MORE RAM than switches (v 1.1) ",cr,lf
	db	"by Daniel M. O'Brien and Tom Perry (1 Jan 1984)",cr,lf,lf,'$'
inmem	db	" Current memory is $"
kbytes	db	" K bytes. $"
findmem db	cr,lf," Physical memory is $"
analyze db	" Analyzing & Clearing...$"
reboot	db	" Re-Booting...",cr,lf,'$'
done	db	cr,lf," Memory size is set correctly.",cr,lf,'$'

begin:
	mov	dx,offset hello 	; say hello
	mov	ah,9
	int	21h

	mov	dx,offset inmem 	; how much memory?
	mov	ah,9
	int	21h

; next 3 lines of code added 1-1-84 by Tom Perry for device driver environment.

	int	12h		; ask bios how much memory
	mov	cl,6
	shl	ax,cl		;shift left 6 times to look like PSP+2

;	mov	ax,ds:2 	; get top segment number from program prefix

	push	ds		; save ds for later

	push	ax		; save top segment number for later
	mov	cl,6		; convert to K bytes
	shr	ax,cl
	call	decout		; and display

	mov	dx,offset kbytes	; display "K bytes"
	mov	ah,9
	int	21h

	mov	dx,offset analyze	; display analyzing message
	mov	ah,9
	int	21h

	xor	ax,ax		; stop parity errors while we poke around
	out	0a0h,al

	pop	ax		; recover top segment number

loop:	mov	bx,0		; look into this 16 byte "segment"
;	cmp	ax,0a000h	; is ax = beginning of "reserved" addrs?
				; stop at display memory instead!
	cmp	ax,0b000h	; is ax = beginning of "reserved" addrs?
	je	ramend		; yes, so end of ram
	mov	ds,ax		; no, so use this as segment
	mov	[bx],ax 	; write contents of ax to ds:bx...
	mov	cx,[bx] 	;... and read it back to cx
	cmp	ax,cx		; does data read = data written?
	jne	ramend		; if it not, then ran out of ram!

	mov	cx,8		;    else - reset this 16 byte area
	mov	es,ax
	xor	ax,ax		;      reset means 0000h
	xor	di,di
	rep	stosw		;    to prevent parity errors when used

	mov	ax,ds		; copy ds to ax...
	inc	ax		;... increment it...
	jmp	loop		;... and loop

ramend:
	mov	bx,ax		; found real end of ram - save it

	mov	al,80h		; enable parity errors for the future
	out	0a0h,al

	mov	ax,bx		; convert segments to K bytes
	mov	cl,6
	shr	ax,cl

	mov	bx,40h		; point to bios data area
	mov	ds,bx
	mov	bx,13h		; and to memory size word in particular

	cmp	[bx],ax 	; same size?
	je	exit		; yes-then we must have done this before

	mov	[bx],ax 	; else - update and
	push	ax

; remove comments to patch equipment flag to indicate 4 floppies attached.
; especially useful for AST RESEARCH's SUPERDRV.

;stub** mov	bx,10h		; point to equipment flag
;stub** mov	ax,[bx] 	; get equipment flag
;stub** or	ax,00c0h	; set installed floppy count to 4
;stub** mov	[bx],ax 	; and restore to proper spot

	pop	ax		; get ds back but save ax on stack
	pop	ds
	push	ax

	mov	dx,offset findmem	; tell how much memory we found
	mov	ah,9
	int	21h

	pop	ax		; get K byte count
	call	decout

	mov	dx,offset kbytes
	mov	ah,9
	int	21h

	mov	dx,offset reboot	; tell them about reboot
	mov	ah,9
	int	21h

	int	19h		; re-boot

exit:
	pop	ds
	mov	dx,offset done
	mov	ah,9
	int	21h

; exit via return to caller instead of int 20h exit to DOS.
; changed 1-1-84 by Tom Perry for device driver environment.

	ret


; quick and probably dirty - display decimal in ax routine

decout:
	push	ax
	push	bx
	push	cx
	push	dx

	xor	cx,cx		;counter of digits
	mov	bx,10		;divide by 10 for conversion

decimal$loop:
	xor	dx,dx		;clear for divide
	div	bx		;get remainder and quotient
	add	dx,'00'         ;make remainder ascii
	push	dx		;save it
	inc	cx		;and count it
	or	ax,ax		;out of digits?
	jnz	decimal$loop	;no-loop on the decimal

decimal$out:
	pop	dx		;get digit
	mov	ah,2		;print digit
	int	21h
	loop	decimal$out	;and loop

	pop	dx
	pop	cx
	pop	bx
	pop	ax
	ret

memdrvr endp

s0000	ends

	end
