I am trying to create a 'main' program that calls a rng subprogram and displays the number it has generated. I have no examples in my book, so I'm sure things are pretty wrong...
;===================================================================
; RAND.ASM
; r a n d o m n u m b e r g e n e r a t o r
;
; GENERATES PSEUDO-RANDOM INTEGERS IN THE RANGE LOWER TO UPPER
; INPUT: TWO STACK PARAMETERS - LOWER AND UPPER ENDS OF RANGE
; OUTPUT: AX-REG CONTAINS RANDOM INTEGER
; CALLING SEQUENCE: PUSH <LOWER END OF RANGE>
; PUSH <UPPER END OF RANGE>
; CALL RANDOM
;===================================================================
EXTRN NEWLINE:FAR
EXTRN PUTDEC:FAR
EXTRN PUTSTRNG:FAR
;===================================================================
.MODEL SMALL,BASIC
;===================================================================
FALSE EQU 0 ;CONSTANT FALSE
TRUE EQU 1 ;CONSTANT TRUE
;===================================================================
; D A T A S E G M E N T D E F I N I T I O N
.FARDATA RAND_DATA
SEED DW ? ;SEED FOR RANDOM NUMBER GEN.
MULTIPLIER DW 25173 ;MULTIPLIER AND
ADDEND DW 13849 ;ADDEND FOR MIXED
;LINEAR CONGRUENTIAL METHOD
FIRST_CALL DB TRUE ;FIRST CALL FLAG
OUTPUT DB 'Random number: '
;===================================================================
; C O D E S E G M E N T D E F I N I T I O N
;
.CODE
ASSUME DS:RAND_DATA,ES:DGROUP
MAIN PROC
MOV AX,DGROUP
MOV ES,AX
MOV DS,AX
LEA DI, OUTPUT
MOV CX, 15
CALL NEWLINE
CALL PUTSTRNG
CALL RANDOM
CALL PUTDEC
MAIN ENDP
RANDOM PROC FAR PUBLIC USES CX DX DS,
LOWER:WORD, UPPER:WORD
;FUNCTION RANDOM(LOWER,UPPER)
;SAVE REGISTERS (USES LIST)
PUSHF ;SAVE FLAGS
MOV AX,SEG RAND_DATA ;SET DS-REGISTER TO POINT
MOV DS,AX ;TO LOCAL DATA SEGMENT
;
.IF FIRST_CALL == TRUE ;IF FIRST_CALL
;THEN
MOV FIRST_CALL,FALSE ; FIRST_CALL = FALSE
MOV AH,0 ; SEED = LOWER HALF OF
INT 1AH ; TIME OF DAY CLOCK
MOV SEED,DX
.ENDIF ;ENDIF
MOV AX,SEED ;X = SEED * MULTIPLIER mod
MUL MULTIPLIER ; 65536
ADD AX,ADDEND ;SEED = (X + ADDEND) mod 65536
MOV SEED,AX
MOV CX,UPPER ;RANGE = UPPER - LOWER + 1
SUB CX,LOWER
INC CX
MUL CX ;RANDOM = (SEED*RANGE)/65536
ADD DX,LOWER ; + LOWER
MOV AX,DX
POPF ;RESTORE FLAGS
;RESTORE REGISTERS (ASSEMBLER
; GENERATES INSTRUCTIONS TO
; RESTORE REGISTERS - USES)
RET ;RETURN (RANDOM)
RANDOM ENDP ;END RANDOM
END MAIN
For building the ASCIIz string to display you could use something like this:
;| |
;| Converts a 32 bit num value to a Dec, Hex, Oct or Bin ascii string. |
;|_____________________________________________________________________|
;
BaseAscii proc USES EBX ESI EDI InPut:DWORD, OutPut:DWORD, LEN:DWORD, Base:DWORD, Comma:DWORD, Fill:DWORD, TermA:DWORD
;---------------------------------------
LOCAL LBuff[32]: BYTE
;
pushad
xor esi, esi
mov eax, InPut ; Input
mov ebx, OutPut
mov byte ptr [ebx], '0'
.while (eax)
xor edx, edx
div Base ; Base 10, 16, 8, 2
.if dl > 9h
add dl, 37h ; Convert to hex ASCII
.else
add dl, 30h ; Convert to dec ASCII
.endif
mov LBuff[esi], dl
inc esi
.if Comma == 1 && Base == 10 && eax > 0
.if esi == 3 || esi == 7 || esi == 11
mov LBuff[esi], 2ch ; Insert commas
inc esi
.endif
.endif
.endw
xor edi, edi
mov ecx, esi
.if LEN > ecx && Fill == 1 ; Zero fill
xor eax, eax
.while (eax < LEN)
mov byte ptr [ebx+eax], '0'
inc eax
.endw
sub LEN, ecx
add edi, LEN
.endif
.while (ecx)
mov al, byte ptr LBuff[esi-1]
mov byte ptr [ebx+edi], al
inc edi
dec esi
dec ecx
.endw
.if TermA
mov byte ptr [ebx+edi], 0h
.endif
popad
ret
;---------------------------------------
BaseAscii endp
It is 32bit but still usable. why are you writing it as a DOS proggie? Why not 32bit console mode?
Paul
Thanks for answering. I am writing as DOS because it is a homework assignment and my crusty old teacher wants it that way!
::)
I totally understand. Good luck. I hope you continue on with assembly as the years go by. These teachers need to get with the program, we are moving into a 64bit world and they are still loicked into 16bit. Unbelievable!
Out of curiousity, what does PutDec look like?
Paul
My teacher can't even answer any 32bit questions. He spends all our time telling us stories about what it was like to program in the 1960's. Urgh.
Here's PutDec from my book:
INCLUDE PCMAC.INC
.MODEL SMALL
.CODE
PUBLIC PutUDec
PutUDec PROC
push ax ; Save Registers
push bx
push cx
push dx
mov cx, 0 ; Initialize digit count
mov bx, 10 ; Base of displayed number
PushDigs:
sub dx, dx ; Convert ax to unsigned double-word
div bx
add dl, '0' ; Compute the ASCII digit...
push dx ; ...push it (can push words only)...
inc cx ; ...and count it
cmp ax, 0 ; Don't display leading zeroes
jne PushDigs
;
PopDigs: ; Loop to display the digits
pop dx ; (in reverse of the order computed)
_PutCh dl
loop PopDigs
pop dx ; Restore registers
pop cx
pop bx
pop ax
ret
PutUDec ENDP
END
Okay, nothing looks strange to me except I do not understand the purpose of initializing CX to 15. Also, after the call to display the result in the main procedure you should have exit code. Right now you are causing an exit at the end of PUTDEC which is poor programming practice and in most cases would be undesirable.
Paul
I initialize CX to 15 because that's the length of my 'output' message. It's for putstrng.
Can you explain why the exit after putdec is a bad idea? And what exactly do you mean by 'exit code?'
The RET statement in PUTDEC causes the program to exit via a second invocation of the RANDOM procedure. This is awful (sorry to be blunt.
Correct methodology would be this:
MAIN PROC
MOV AX, DGROUP
MOV ES, AX
MOV DS, AX
LEA DI, OUTPUT
MOV CX, 15
CALL NEWLINE
CALL PUTSTRNG
CALL RANDOM
CALL PUTDEC
INT 4C00h
MAIN ENDP
Dio you see how you are crashing into the RANDOM procedure without that additional line? This causes the exit to DOS to happen when the RET statement in the RANDOM procedure is executed
Paul
Hi,
I don't see where you are pushing the upper and lower
values on the stack before calling random. And Paul is right
about the exit, but his code is a little off.
PUSH [Lower] ; Or fill a register and push it.
PUSH [Upper]
CALL RANDOM
CALL PUTDEC
MOV AX,04C00H ; DOS 2+ Exit
INT 21H
Thanks FORTRAN, it has been a while for me when it comes to 16 bit.
Paul
Hi Paul,
Right, and I should slap myself on the wrist for PUSHing stuff
on the stack, and then not balancing things with POPs. Not
that it would matter here, but it is poor programing style.
Cheers,
Steve N.
FORTRAN,
I thought about mentioning it but I did not see how it would matter here. Personally, I feel if someone is going to CALL a procedure they should not set it up as an INVOKE style of procedure. It works if attention is paid to the stack maintainance but as you said, it is poor programming practice.veronicak5678, I hope the instructor is not encouraginig this. If he is, he should be shown this entire set of postings.
Paul