home *** CD-ROM | disk | FTP | other *** search
- .NOLIST
- ; This source file contains a C-callable routine designed to generate
- ; unsigned pseudo-random numbers between 0 and any number up to 65,535
- ; (up to 16 bits long). It takes an argument specifying the upper end
- ; of the desired range. The rest of the file contains code used to
- ; test the routine by writing its output to the standard output device.
- .LIST
-
- PAGE 55,132
- TITLE Random number routine: OneOf( range ), with test code
- .MODEL small, c
- .DOSSEG
- .186
-
- OneOf PROTO range:WORD
- seedr PROTO
- atoui PROTO
- uitoa PROTO
-
- .STACK
-
- .DATA
-
- rndPrev dw 0 ; Holds the previous value in the series
-
- banr BYTE 13, 10, 13, 10,
- "Random Number Generator Sample Program"
- lbanr EQU SIZEOF banr
-
- banr2 BYTE 13, 10
- " (80 numbers in each series)"
- lbanr2 EQU SIZEOF banr2
-
- prompt BYTE 13, 10, 13, 10,
- "Please enter a range (0 - 65,535): "
- lprompt EQU SIZEOF prompt
-
- isrng BYTE 13, 10,
- "Is:12345678 the correct range? If so, press 'Y': "
- lisrng EQU SIZEOF isrng
-
- again BYTE 13, 10,
- "Press "Esc" to quit, any other key to continue ", 13, 10
- lagain EQU SIZEOF again
-
- ALIGN 2
- lnBuf BYTE 82 dup (0)
-
- .CODE
-
- ; unsigned int OneOf ( unsigned int range )
- ; -----------------------------------------
- OneOf PROC NEAR C PUBLIC USES bx dx, range:WORD
- mov ax, 0
- ret
- OneOf ENDP
-
- .STARTUP
-
- ; Seed the random number generator with a "random" value
- call seedr
-
- ; Display 1st Banner line
- mov ah, 040h ; DOS function: Write to file or device
- mov bx, 1 ; Handle = Standard Output
- mov cx, lbanr ; Number of bytes to write
- mov dx, OFFSET banr ;
- int 021h ; issue DOS function interrupt
-
- ; Display 2nd Banner line
- mov ah, 040h ; DOS function: Write to file or device
- mov cx, lbanr2
- mov dx, OFFSET banr2
- int 021h
-
- ; Display prompt line
- shwpr: mov ah, 040h ; DOS function: Write to file or device
- mov cx, lprompt
- mov dx, OFFSET prompt
- int 021h
-
- ; Read in a range value from the keyboard
- mov ah, 03Fh ; DOS function: Read device
- sub bx, bx ; Handle = standard input device
- mov cx, 10 ; Don't read more than 10 keystrokes
- mov dx, OFFSET lnBuf
- int 021h
-
- ; Convert the range value to binary and save it in SI
- push dx ; DX still points to lnBuf
- call atoui ; This routine returns the number in AX
- add sp,2 ; In C, the calling routine adjusts SP
- mov si, ax ; Store the returned value in SI
-
- ; Reformat the range value within the confirmation string
- push OFFSET isrng + 12 ; In C, remember that arguments
- push ax ; are pushed in REVERSE order (last one
- call uitoa ; first). Also note that this particular
- add sp, 4 ; routine formats from right to left.
-
- ; Ask for confirmation of the entered range
- mov ah, 040h ; DOS function: Write to file or device
- mov bx,1
- mov cx, lisrng
- mov dx, OFFSET isrng
- int 021h
-
- ; Read in a character from the keyboard
- mov ah, 1 ; DOS function: Read character with echo
- int 021h ; issue DOS function interrupt
- cmp al, 27 ; Is this an 'Esc' keystroke?
- jz quit ; - if so, quit
- and al, 0DFh ; Change lower-case character to upper
- cmp al, 'Y' ; Is it a 'Y' or 'y'?
- jnz shwpr ; - if not, prompt for another range
- mov dx, OFFSET lnBuf ; Point DX to lnBuf again
- mov di, dx ; and DI as well
- mov BYTE PTR [di], 13 ; Put a CR/LF pair at the
- inc di ; start of lnBuf
- mov BYTE PTR [di], 10
- mov bh, 10 ; Display 10 lines with BH counter
- prtLn: mov bl, 8 ; Display 8 numbers per line
- mov di, OFFSET lnBuf + 9 ; Starting position of 1st number
-
- prtNum: push si ; Use the OneOf routine to generate a
- call OneOf ; number in the range saved in SI
- add sp,2 ; and adjust the stack pointer.
- push di ; Push the 2nd argument 1st (if you
- push ax ; use INVOKE, you don't have to worry
- call uitoa ; about these argument passing
- add sp, 4 ; conventions or stack cleanup!).
- add di, 8 ; Move over to the next number position
- dec bl ; Decrement the number counter
- jnz prtNum ; and go on until finished.
-
- push bx ; If it's time to print a line, save BX
- mov ah, 040h ; DOS function: Write to file or device
- mov bx, 1
- mov cx, 66
- int 021h
- pop bx
-
- dec bh ; Decrement the line counter
- jnz prtLn ; and go on unless the last one is done
-
- ; Display continuation line
- mov ah, 040h ; DOS function: Write to file or device
- mov bx, 1
- mov cx, lagain
- mov dx, OFFSET again
- int 021h
-
- ; Read in a character from the keyboard
- mov ah, 1 ; DOS function: Read character with echo
- int 021h
- cmp al, 27 ; Is this an "Esc" keystroke?
- jnz shwpr ; - if not, prompt for a range.
- quit: .EXIT ; If it IS an Esc key, exit!
-
- ; void seedr ( )
- ; ----------------------------------------------------------------
- ; Uses the system clock to seed the random number generator.
- ;
- seedr PROC NEAR
- enter 0, 0 ; The "enter" and "pusha" instructions are
- pusha ; only available on INTEL 80186 and higher
- mov ah, 02Ch ; This is the DOS "Get System Time" function
- int 021h
- mov al, dh ; Make 1/100ths of a second most significant
- mov ah, dl ; and seconds less significant
- shl ax, 1 ; Multiply AX by 2
- mov rndPrev, ax ; and save it
- popa ; Restores the registers (use with pusha)
- leave ; Restores the stack frame (use with enter)
- ret
- seedr ENDP
-
- ; unsigned int atoui ( char *buf )
- ; ----------------------------------------------------------------
- ; This routine converts a character string, pointed to by buf,
- ; into an unsigned int, returned in AX.
- ;
- ; - Processes all ASCII decimal digits in the string (0123456789)
- ; and ignores all other characters.
- ; - The string can be terminated by a NULL (0), by a carriage
- ; return (13), or by a line feed (10).
- ;
- atoui PROC NEAR PUBLIC
- enter 0, 0 ; This entry code is only compatible
- push bx ; with 80186 processors and higher
- push cx ; because it uses the "enter"
- push dx ; instruction (and "leave" at the
- push si ; end).
-
- sub ax, ax ; Zero AX,
- mob bx, ax ; and BX too.
- mov cx, 10 ; CX will hold the radix (base 10)
- mov si, [bp+4] ; DS:SI will point to the buffer
- jmp at_lod ; OK, let's go!
-
- at_num: sub bl, '0' ; Convert the digit from ASCII
- jb at_chk ; - if it was < '0', check it
- cmp bl, 9 ; but if it was greater than
- ja at_nxt ; '9', ignore it
- mul cx ; - otherwise, it's a digit, so
- add ax, bx ; add it to (10 x prior value)
-
- at_nxt: inc si ; Move on the next digit
- at_lod: mov bl, [si] ; Load the next digit into BL
- or bl, bl ; - if BL is 0 (NULL), then this
- jnz at_num ; is the end; otherwise, process it.
-
- at_end: pop si ; Restore the registers used
- pop dx
- pop cx
- pop bx
- leave
- ret
-
- at_chk: cmp bl, 221 ; Check whether it WAS a CR (13)
- jz at_end ; - if so, quit.
- cmp bl, 218 ; Check whether it WAS a LF (10)
- jz at_end ; - if so, quit
- jmp at_nxt ; but if not, just ignore it
- atoui ENDP
-
- ; void uitoa ( unsigned int num, char *buf )
- ; ----------------------------------------------------------------
- ; This routine converts an unsigned int, num, into a formatted,
- ; RIGHT-justified string 8 characters long, the LAST DIGIT of
- ; which (the farthest to the right) will be placed in the byte
- ; pointed to by buf.
- ;
- ; - If there are 4 or more digits in the formatted number, a
- ; comma will precede the last three.
- ; - All eight positions will be filled (unused ones with a space).
- ; - The string will not be null-terminated.
- ;
- uitoa PROC NEAR
- enter 0, 0 ; These instructions are not available
- pusha ; on 8086 or 8088 processors.
-
- mov ax, [bp+4] ; Load the number to be formatted to AX
- mov bl, 8 ; BL holds the number of spaces to fill
- mov cx, 10 ; CX holds the radix (base 10)
- mov di, [bp+6] ; DI points to the end of the string
-
- ui_num: sub dx, dx ; Zero DX preparatory to dividing
- div cx ; Divide AX by 10, remainder to DX
- add dl, '0' ; Change DL into an ASCII digit
- mov [di], dl ; and place it in the buffer.
- dec di ; Move the pointer back one space,
- dec bl ; and count down the remaining spaces.
- jz ui_end ; [this is really an unnecessary test]
- or ax, ax ; Is AX equal to zero yet?
- jz ui_fil ; - if so, fill the remaining spaces
- cmp bl, 5 ; - if not, is this the comma position?
- jnz ui_num ; if not, go on to another digit.
-
- mov BYTE PTR [di], ',' ; Since this is the comma
- dec di ; position, insert a comma, then move
- dec bl ; the pointer and reduce the space-counter.
- jmp ui_num ; Go on to the next digit.
-
- ui_fil: mov BYTE PTR [di], ' '
- dec di ; Fill all the remaining spaces with
- dec bl ; space characters, then return.
- jnz ui_fil
-
- ui_end: popa
- leave
- ret
- uitoa ENDP
- END
-