Category : System Diagnostics for your computer
Archive   : EMMTEST.ZIP
Filename : NJRAMT.ASM

Output of file : NJRAMT.ASM contained in archive : EMMTEST.ZIP

; Nifty James' Famous Expanded Memory Tester
; (C) Copyright 1987 by Mike Blaszczak. All Rights Reserved.

; Version 1.00 of 21 Oct 1987

; Shareware $5 Please register!

; Assemble with:

; for enhanced processor version:



; ---------------------------------------------------------------------------

; ASCII Characters

bell equ 7 ; bell character
tab equ 9 ; tab character
lf equ 10 ; linefeed
cr equ 13 ; carriage return
space equ 32 ; space
eos equ '$' ; end of DOS string

; ---------------------------------------------------------------------------

EMM equ 067h ; the E/EMS memory manager

; ---------------------------------------------------------------------------
; Structure Definitions

; The structures defined here are used to find information in the
; various request header formats. Of course, being structures, they
; don't take up space... they are used to define offsets for the
; addressing of the request header.

donestat equ 00000000100000000b ; done status bit flag

rq equ es:[bx] ; base address used in routines

; -- Request Header (General Format)

inithead struc
rlen db ? ; length of the structure
unitn db ? ; unit number
command db ? ; command code
status dw ? ; status code (returned by us)
db 8 dup(?); reserved bytes
units db ? ; number of units
ndadro dw ? ; ending address offset
ndadrs dw ? ; ending address segment
bpboff dw ? ; BPB offset pointer
bpbseg dw ? ; BPB segment pointer
taglet db ? ; drive tag letter
inithead ends

; ---------------------------------------------------------------------------
; DOS Calls

; These are DOS functions used by the driver.

DisplayOut equ 002h ; call to print a single character

PrintString equ 009h ; call to print a '$' string
CheckKeyboard equ 00Bh ; call to check for a key
GetDOSVersion equ 030h ; call to get the DOS version #

; ---------------------------------------------------------------------------
; I/O Ports

Speak equ 061h ; speaker port
SpeakMask equ 011111110b ; mask for speaker set bit
SpeakToggle equ 000000010b ; toggle bit for the speaker

; ---------------------------------------------------------------------------
; E/EMM Routines

; These are the E/EMM functions that we use. (These are specific functions
; of the EMM interrupt.)

E_PageBase equ 041h ; determine the Page Fram Base Addr
E_Counts equ 042h ; determine free/total mem
E_Open equ 043h ; open, allocate, obtain handle ID
E_MapPage equ 044h ; map a logical page into window
E_Close equ 045h ; close handle and free pages
E_Version equ 046h ; get the E/EMM version number

ifdef V286
%OUT Enhanced processor version
ifdef PCL
%OUT for the PC's Limited 286/386
%OUT Standard Version

; This macro is used during debugging. It prints a single character
; via the BIOS screen interface, and leaves the registers unchanged.

ifdef DEBUG

%OUT DEBUG Version
PrintChar macro Char
ifdef PCL

push ax
mov al,Char
out 095h,al ; put it digit 3 of smartvu
pop ax


push ax ; save the regs
push bx
push dx
mov ah,15
int 010h ; get the current page
mov al,Char
mov ah,14 ; print the character
int 010h

xor dx,dx
mov ah,0 ; also to printer
mov al,Char
int 017h

pop dx
pop bx ;restore the regs
pop ax


PrintChar macro Char ; if not debugging, blow it off

; ---------------------------------------------------------------------------

tester segment para public
assume cs:tester,ds:tester,es:tester,ss:tester

org 0 ; begin at zero

; ---------------------------------------------------------------------------
; Device Header

; This area contains the header information. It is used by DOS when loading
; the device driver, and it contains information used to describe the
; driver to the DOS environment.

NextPlace dw -1,-1 ; pointer to next driver
Attrib dw 00010000000000000b ; attribute word

; device is non-ibm and block mode
; doesn't support IOCTL, is not
; a network device

dw offset Strategy ; the strategy entry
dw offset Interrupt ; the interrupt entry
db 1,'NJ_DISK' ; Nifty James' Disk!

; ---------------------------------------------------------------------------

JumpTable label word

; This area is a "Jump Table" that is used to dispatch the code.
; Only the init function is implemented. This driver will only
; run during the CONFIG.SYS file. After that, it entirely clears
; itself from memory.

dw offset Init ; 0 * initialize

; (The commands above init are all not implemented -- we don't
; make entries for them to optimize for space (and speed).
; The equate TopCommand must be set to the last used
; command code.)

TopCommand equ 1 ; highest valid command

RBPoint label dword ; Pointer to request buffer
RBPointOff dw 0 ; offset part
RBPointSeg dw 0 ; segment part

SaveSS dw 0 ; save place for the SS register
SaveSP dw 0 ; save place for the SP register
SaveAX dw 0 ; save place for the accumulator

EMMHandle dw 0 ; our handle, as assigned by the EMM
EMMBase dw 0 ; base of the EMM physical window

; ---------------------------------------------------------------------------
; The local stack

even ; make the stack a word-aligned area
dw 64 dup (0DEADh)

; ---------------------------------------------------------------------------
; Strategy Entry Point For the Device Driver

; This routine simply stores the pointer to the request header
; so that request header has it. That's all it does. Really.

STRATPROC proc far

mov cs:RBPointOff,bx
mov cs:RBPointSeg,es ; just store the pointer
ret ; and get outta here!
; (isn't it ironic that the shortest routine is called "Strategy"?)

; ---------------------------------------------------------------------------
; Interrupt Entry Point For the Device Driver

; This routine executes the command contained in the passed request header.
; DOS has called STRATEGY, and that routine stored a pointer to the request
; header for our use. We will construct our own stack area because the
; EMM uses a great deal of stack space.

INTPROC proc far
PrintChar 'D'
mov CS:SaveSS,ss ; save the SS register
mov CS:SaveSP,sp ; save the SP register
mov CS:SaveAX,ax

mov ax,offset StackTop ; initialize our stack
mov sp,ax
mov ax,cs
mov ss,ax

ifdef V286
push bx ; save the other regs
push cx
push dx
push bp
push si
push di

pushf ; and the flags
cld ; set the string direction up
push es
push ds

; Note that during calls we use DS to point to our local data
; and ES to point to the request header.

les bx,cs:RBPoint ; get the request buffer

call Init

; ---------------------------------------------------------------------------
; This is the mass exit; everone splits through this point! When we
; arrive here, the AX reg will contain the word to be put into the
; status word. We'll do that:

PrintChar 'X'
les bx,cs:RBPoint ; point to the request block
NoRestore: or ax,donestat ; set the done status
mov rq.status,ax

; Now, we just undo the registers.

pop ds ; the seg regs
pop es

popf ; the flags
ifdef V286
pop di
pop si ; and the data regs
pop bp
pop dx
pop cx
pop bx

PrintChar 'd'
mov ax,CS:SaveAX
mov sp,CS:SaveSP ; restore the calling stack
mov ss,CS:SaveSS


; ---------------------------------------------------------------------------

testpage proc near

; This procedure tests the EMS block that is currently mapped
; at EMSBASE:0000 through EMSBASE:3FFF. The routine will return
; with AX set to 0000h if no error occurred. If an error occurs,
; it returns with AX set to 0FFFFh.

mov es,EMSBase

mov ax,0FFFFh ; write all ones
call testset
jne testfail ; nope, it failed

xor ax,ax ; write all zeros
call testset
jne testfail

mov ax,0AA55h ; write 1010101001010101 pattern
call testset
jne testfail

mov ax,055AAh ; write 0101010110101010 pattern
call testset
jne testfail

xor ax,ax ; test was successful,
ret ; return with AX = 0

testfail: mov ax,0FFFFh ; AX = 0FFFFh, test failed.

testpage endp

testset proc near

mov di,0
mov cx,8192 ; 8192 words
rep stosw

mov di,0 ; try to check them
mov cx,8190
testsetloop: cmp es:[di],ax
jne testsetexit
inc di
inc di
loop testsetloop

testsetexit: cmp cx,0 ; see if it's zero
ret ; and return with results of comparison

testset endp

; ---------------------------------------------------------------------------

PrintPage proc near

xor ax,ax ; print "page x tested"
mov si,offset TestingSpot
mov bx,CurrentPage
call Bin2Dec ; convert page # to ASCII

mov ah,PrintString ; print it
mov dx,offset TestingMsg
int 21h

in al,Speak ; and then make a click
and al,SpeakMask
xor al,SpeakToggle
out Speak,al


PrintPage endp

; ---------------------------------------------------------------------------

PrintError proc near

xor ax,ax ; print "error at page"
mov si,offset ErrorSpot ; message
mov bx,CurrentPage
call Bin2Dec ; convert page number to ASCII

mov ah,PrintString ; and print it
mov dx,offset ErrorMsg
int 21h


PrintError endp

; ---------------------------------------------------------------------------

Init proc near

mov ax,cs
mov ds,ax

mov ah,PrintString ;print the banner
mov dx,offset Banner
int 21h

push es
xor ax,ax ; point to the 0000 segment
mov es,ax
mov bx,(EMM*4)+2 ; find the EMM interrupt
mov ax,es:[bx]
mov es,ax ; point to the EMM device
mov di,10 ; header

mov si,offset EMMIDString ; point to the EMM identifier
mov cx,8
repz cmpsb ; compare a bunch of bytes
pop es
jz EMMPresent

mov dx,offset NoEMMThere ; point to our error
jmp InitFail ; the EMM isn't there!!

EMMPresent: mov ah,E_PageBase ; get the page base
int EMM
or ah,ah
jne GenFail

mov EMSBase,bx ; store it

mov ah,E_Counts ; get count of pages available
int EMM
or ah,ah
jne GenFail

cmp bx,dx ; is it all unused?
je AllMine

mov dx,offset NotAllMem
jmp InitFail

AllMine: push dx ; save count

mov ah,E_Open ; bx already has count
int EMM
and ah,ah
jne GenFail

mov EMSHandle,dx ; save the handle

pop cx ; retrieve count

PageLoop: push cx
mov ah,E_MapPage ; map the current page
mov al,0 ; into logical window 0
mov bx,CurrentPage
mov dx,EMSHandle
int EMM
and ah,ah
jne GenFail

call PrintPage
call TestPage ; test a page
cmp ax,0 ; is it zero?
je NoError

call PrintError

NoError: pop cx

mov ah,CheckKeyboard ; check for a keypress
int 21h
and al,al ; was there?
jne fallout ; yep, get out of here

inc CurrentPage
loop PageLoop

mov dx,offset TestedMsg ; print end message
mov ah,PrintString
int 21h

fallout: mov ah,E_Close ; release the EMS memory we took
mov dx,EMSHandle
int EMM
and ah,ah
jne GenFail

endit: les bx,cs:RBPoint ; get ES:BX back
xor ax,ax
mov rq.ndadro,ax ;ending address is CS:0000
mov rq.units,al ;don't take any unit numbers

mov ax,cs
mov rq.ndadrs,ax

ret ; return to the dispatcher routine

GenFail: mov dx,offset EMMError

InitFail: push dx

mov dx,offset General ;print error header
mov ah,PrintString
int 21h
pop dx

mov ah,PrintString ; and then the error itself
int 21h
jmp endit

Init endp

; ---------------------------------------------------------------------------

; This routine converts a binary number, in AX:BX, to decimal notation.
; It will convert up to 8 digits, and will supress leading zeros. The
; routine should be called with DS:SI set to point to the area to store
; the converted number.

Bin2Dec proc near

push es ; save the registers
push ds
push di
push si

mov WorkAreaL,bx
mov WorkAreaH,ax ; put the number on our scratchpad

mov ax,ds ; point to the answer with ES:DI
mov es,ax
mov di,si
add di,7

mov si,offset WorkAreaL ; point at scratchpad

Bin2DecLoop: push si

xor bx,bx ; done flag
mov cx,2 ; 2 words in our number
mov dx,bx ; clear remainder
add si,2 ; point to the high end

Bin2DecDigit: push cx ; save word count
mov ax,[si] ; get the digit
mov cx,10
div cx ; convert it
mov [si],ax ; store it back
or bx,ax ; set the done flag appropriately
sub si,2 ; point to next lower
pop cx
loop Bin2DecDigit

or dl,'0' ; make it into a decimal digit
mov [di],dl ; and store it
dec di ; adjust pointer

pop si ; get the pointer back
and bx,bx ; is the result zero?
jne Bin2DecLoop ; nope! Do more!

pop si ; retrieve the used registers
pop di
pop ds
pop es

WorkAreaL dw 0 ; low end of the work area
WorkAreaH dw 0 ; high side of the work area

Bin2Dec endp

; ---------------------------------------------------------------------------

EMSHandle dw ? ; our EMS handle number
EMSBase dw ? ; base segment of EMS
CurrentPage dw ? ; current page that we're testing

TestingMsg db 'Page '
TestingSpot db ' tested',cr,eos

TestedMsg db 'All Pages Tested! ',cr,lf,eos

ErrorMsg db 'Error on Page '
ErrorSpot db ' !',bell,cr,lf,eos

Banner db lf,"Nifty James' Famous EMS Memory Tester",cr,lf
db "Version 1.00 of 21 Oct 1987",cr,lf
ifdef V286
db "Enhanced Processor Version",cr,lf
db lf,eos


General db 'Device not installed.',cr,lf,eos

NoEMMThere db 'The EMM is not installed.',cr,lf,lf,eos

EMMError db 'EMM failure during testing.',cr,lf,lf,eos

NotAllMem db 'EMM Memory not entirely empty.',cr,lf,lf,eos

tester ends

  3 Responses to “Category : System Diagnostics for your computer
Archive   : EMMTEST.ZIP
Filename : NJRAMT.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: