News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Subprograms

Started by veronicak5678, October 01, 2009, 06:12:32 PM

Previous topic - Next topic

veronicak5678

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

PBrennick

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
The GeneSys Project is available from:
The Repository or My crappy website

veronicak5678

Thanks for answering. I am writing as DOS because it is a homework assignment and my crusty old teacher wants it that way!

PBrennick

 ::)

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
The GeneSys Project is available from:
The Repository or My crappy website

veronicak5678

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


PBrennick

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
The GeneSys Project is available from:
The Repository or My crappy website

veronicak5678

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?'

PBrennick

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
The GeneSys Project is available from:
The Repository or My crappy website

FORTRANS

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

PBrennick

Thanks FORTRAN, it has been a while for me when it comes to 16 bit.

Paul
The GeneSys Project is available from:
The Repository or My crappy website

FORTRANS

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.

PBrennick

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
The GeneSys Project is available from:
The Repository or My crappy website