## News:

Message to All Guests
NB: Posting URL's See here: Posted URL Change

## Pseudo Random Numbers

Started by tda0626, June 04, 2024, 09:06:52 AM

#### NoCforMe

I guess I was thinking of the die-hard DOS programmer pecking away on their still-running PC or XT, green-screen monitor and everything.
Assembly language programming should be fun. That's why I do it.

#### sinsi

It's perfectly valid to use a 32-bit register to access memory in real mode, you just have to be careful that the high 16-bits are zero,
e.g. MOV ECX,[EAX+EDX*4+1000h] is OK (assuming the address computes to <64K).
Like Steve said, instead of mucking around with DX:AX for 32-bit numbers we can use one 32-bit register or (gasp) 64-bit maths with EDX:EAX

The assembler has to support 32-bit instructions, too.

#### tda0626

This has me perplexed. Wrote a little program to output some random numbers but it is doing some weird stuff right after my
`div dx` instruction. It starts randomly executing code right after the instruction, see pictures below. The unassembled code segment shows my
`add dx, 30` but never executes it. I have attached my source to this post too. What in the world is happening?

#### sinsi

You are trying to divide DX:AX by DX, in this case 000a0012h / 000ah, which overflows.
Use a register other than DX.

#### NoCforMe

Wait a second:
I understand the overflow problem.
But isn't it perfectly valid to divide by DX, provided it doesn't result in an overflow?
In other words, the problem isn't dividing by DX, it's the values being divided, right?

Scratch that. (E)DX is the last register you'd want to use as a divisor. Because it holds the high word/dword of the dividend.

You're right. Don't use it!
Assembly language programming should be fun. That's why I do it.

#### tda0626

Does the same thing when I change it to CX. I was under the assumption that it would return AX=0 if the number was less than 10 and put the remainder in DX. Guess not.

#### NoCforMe

Did you remember to set DX to zero? Remember, DIV does DX:AX / {dividend}.
Assembly language programming should be fun. That's why I do it.

#### tda0626

Quote from: NoCforMe on June 05, 2024, 09:46:44 AMDid you remember to set DX to zero? Remember, DIV does DX:AX / {dividend}.

LOL these little mistakes drive you crazy but I am learning from them. You are right. I XOR DX, DX and it works somewhat but doesn't print out the right characters. Prints out a triangle and some other garbage. The correct values are written to the memory location though when I dump the memory. DOS function AH=9 21h just doesn't print the right stuff.

`numstring DB 0,0,32,'\$'                                mov ah, 9 mov dx, offset numstring int 21h `

#### NoCforMe

... and of course with INT 21/AH=9 you need to remember to terminate the string with a "\$".

(What a weird terminator; how'd they come up with that? What if you want to print a dollar sign in the string?)
Assembly language programming should be fun. That's why I do it.

#### tda0626

I am on a roll tonight with blunders  . I was adding 30 decimal to make it an ASCII number instead of 30h, which was the reason for the weird characters. Now just need figure out why my loop exit check isn't working.

#### NoCforMe

Easy way to remember the binary--> ASCII numeric conversion thing:
`  MOV  AL, number  ADD  AL, '0'`No need to remember any hexadecimal #s.
Assembly language programming should be fun. That's why I do it.

#### sinsi

Quote from: tda0626 on June 05, 2024, 10:22:39 AMNow just need figure out why my loop exit check isn't working.
You start with CX=1000 and increment it after each loop, did you mean to decrement it?
I'm not sure if the sign flag is the one you should be testing, maybe the carry or zero flag?

#### tda0626

Yep I saw that earlier and fixed it. Got it to work finally but the period is only 15 before it starts repeating again so it does not work. Guess I need to maybe do another method or read up more on LFSR.

#### NoCforMe

#28
You might want to use the LOOP instruction.
When you know exactly how many iterations you want, it makes things much easier.
You set (E)CX to the loop count.
At the bottom of the loop you code the LOOP instruction with the jump target of the loop.
LOOP automagically decrements (E)CX, compares it to zero, jumps to the loop target if not.
Saves you a little bit of bookkeeping.
`    MOV   CX, loopCountlp: ; do stuff    ; do more stuff    LOOP  lp`Only "gotcha" is that it's only good for short distance loops (max. 127 bytes of code).

There are even 2 more flavors of this instruction, LOOPE/Z and LOOPNE/Z that will loop while equal (zero flag set) or not equal, from an operation that sets that flag before the LOOP instruction.

The 8086/8088 was an awesome little machine.
Assembly language programming should be fun. That's why I do it.

#### zedd151

Quote from: NoCforMe on June 05, 2024, 11:38:36 AMYou might want to use the LOOP instruction.
...You set (E)CX to the loop count.
Only "gotcha" is that it's only good for short distance loops (max. 127 bytes of code).

And you cannot use CX within the loop (without some form of preserving it of course)...