News:

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

LARGE_INTEGER Divide

Started by msmith, January 21, 2006, 04:15:14 AM

Previous topic - Next topic

msmith

I would think that eiher the API or msvcrt would have LARGE_INTEGER (64 bit) functions such as multiply and divide, but I can't find them using MSDN, dependency walker or Google.

Does someone know where these are and what they are called?

MichaelW

eschew obfuscation

msmith

Hi Michael,

I did already find the page you helped me with.

It does not have a 64 bit divide.

The reason I need this is to find the difference (subtract)  between 2 FileTimes and then divide this result by 1,000,000,000 to get the difference in seconds. I think I can handle the subtraction but not the division.

Thanks,

Mike

raymond

1,000,000,000 is a 32-bit value. When you divide by that number, you are effectively dividing a 64-bit value held in the EDX:EAX registers. You don't need "LARGE INTEGERS" to perform such an operation. :naughty:

If you can subtract the 2 file times, put the most significant dword in EDX and the least significant dword in EAX and divide it. :clap: Your result is in EAX and the remainder in EDX.

Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

msmith

Thanks raymond.

Its getting late here so I'll try this tomorrow.
Do I use div or idiv? (I think div).

Also, later can I take the result of the divide and multiply it by 1,000,000,000 at a later time using a similar technique?

All of this allows me to store time as a 32 bit value based on the number of seconds since Jan 1, 2002.

This allows me to put date/time stamps on machinery events that consume less space and since there are thousands of events, it adds up quickly.

Regards,

Mike

raymond

I would suggest that you use idiv. If your subtraction results are always positive, the division result would be the same whether you use div or idiv. However, if you use div and a subtraction result happens to be negative, your program would CRASH. (Safety first :bdg)

And you can later multiply the results by 1,000,000,000 but with some loss of accuracy because of the dropped fraction. The result would be in the EDX:EAX register pair. Again, use imul to cater for the possibility of negative results.

Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

msmith

Thanks again raymond,

I'll try both ideas tomorrow.

What are the register setup going in for the mpy? (I  think op1  in eax and op2 in edx)

Mike


raymond

For the standard 64-bit result (i.e. in EDX:EAX), one of the operands must be in EAX. The other operand can be in any of the other regular registers or in memory. For example

.data
  billion dd 1000000000
  time    dd 6
.code
  mov  eax,time
  imul billion

  mov  eax,time
  mov  edx,1000000000
  imul edx


Raymond

When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

msmith

Raymond,

I really appreciate it. I was "spoiled" by the instruction set of the 68000 for almost 20 years where all of the data registers had equal rank and usage (there were 8 of them). I still miss the memory to memory moves, memory indirect, and auto increment/decrement modes.

99% of my asm programming is from the standpoint of making my compiler generate code, so I have never become as familiar of the register usage rules of the 386 architecture as I otherwise might have.

Mike

msmith

Raymond,

Thanks again for your help.

Here is the code to do the date difference in seconds.


; LN:26 x=timediff(dt1,dt2)
mov esi,dt1+0
mov [_TmpVec1],esi
mov esi,dt2+0
mov [_TmpVec2],esi
invoke SystemTimeToFileTime,[_TmpVec1],!dwLowDateTime1
invoke SystemTimeToFileTime,[_TmpVec2],!dwLowDateTime2
mov eax,[!dwLowDateTime1]
mov edx,[!dwHighDateTime1]
sub eax,[!dwLowDateTime2]
sbb edx,[!dwHighDateTime2]
mov ebx,10000000
idiv ebx
mov dword [x],eax



BTW, I had two extra zeros on the divisor last night. I am dividing by 100NS , not 1NS.

Things were hectic here today, so I'lll do the timeadd function tomorrow where I can try the multiply.

msmith

Raymond,

Your example:


  mov  eax,time
  mov  edx,10000000
  imul edx


is what I used to recontruct the date/time and and it works fine.

I tried one of the 2 operand forms and it didn't work. The divide register requirements are very restricted, but at least they are clear.

In your example, it appears that you load the multiplier into eax and the multiplicand into edx with the 64 bit result in edx:eax, and with your help I got it to work. Even there, where does it say to multiply by edx (imul edx) as opposed to imul eax? This is not logical to me at all. I am not a beginner at this. I have been designing hardware and software (including several compilers, minicomputers, and microprocessor systems) since 1970. I have worked with DEC, Univac, HP, Lockheed, Motorola (6800 thru 68020, and more. I have never seen anything so non-orthagonal and poorly documented as the i386 instruction set. When using a compiler to generate code, you only have to address these issues when generating new code in the compiler, so I only have to "hold my nose" for a little while. The compiler is written in itself, so most new compiler code is familiar to me (since I created the syntax myself).

Without your prompt and accurate help, this seemingly simple task would have take much longer. I really appreciate it!

I have the official Intel PDF set and other sources, but nowhere does anyone really explain the imul instruction as far as which register(s) to load what instruction format to use, and where the result will be.

In my effort to use a 2 operand approach, my code seemed to follow the Intel info, but did not work.

My question is where is an authoratative and clear writeup on this subject?

zooba

imul eax will work, but since it will multiply by eax you'll get eax2.

imul eax, 100000 will work as this is in the form IMUL r32,imm32 which is supported. The single operand form appears to have been preserved since it is the way the mul operand works.

msmith

Hi Zooba,

Quote
imul eax, 100000 will work as this is in the form IMUL r32,imm32 which is supported.

My code was:

mov eax,[x]
imul eax,10000000


This is what I tried. It did not work. Furthermore doing an xor edx,edx before the imul changed the result. I was interpreting the result as edx:eax.

Mike

MichaelW

Chapter 4 of the MASM Reference Guide, available here, covers the x86 instruction set up through the 486, with encodings, timings, and examples.


eschew obfuscation

msmith

Hi Michael,

Thanks for the link, but it's a download to the Intel vol 2 I already have. My previous point is that even with the officiall docs from Intel it is not clearly explained.

From the Intel Vol 2 Instruction Set Reference:

Quote
Description
Performs a signed multiplication of two operands. This instruction has three forms, depending
on the number of operands.
• One-operand form. This form is identical to that used by the MUL instruction. Here, the
source operand (in a general-purpose register or memory location) is multiplied by the
value in the AL, AX, or EAX register (depending on the operand size) and the product is
stored in the AX, DX:AX, or EDX:EAX registers, respectively.
• Two-operand form. With this form the destination operand (the first operand) is
multiplied by the source operand (second operand). The destination operand is a general-purpose
register and the source operand is an immediate value, a general-purpose register,
or a memory location. The product is then stored in the destination operand location.
• Three-operand form. This form requires a destination operand (the first operand) and two
source operands (the second and the third operands). Here, the first source operand (which
can be a general-purpose register or a memory location) is multiplied by the second source
operand (an immediate value). The product is then stored in the destination operand (a
general-purpose register).

Notice that the  "One-operand form" nowhere tells your that the form of the instruction is imul edx. A proper explanation would be to explain that the first operand is loaded into edx while the second is loaded into eax. The 2 operands are then multiplied by imul edx with the result in edx:eax.

Also note that the "Two-operand form" nowhere tell you that the result is stored in edx:eax. This is fundamental, basic info that is required to use the instruction properly.

The remarks I made about my experience in hardware and software design were intended to show that I know what should reasonably be expected.

The whole culture of the PC world today is to have poorly documented and secret information and to make assumptions about what the reader already knows and what culture he is from. When the Motorola 6809 processor came out in the early 80's, the docs constantly referred to something being like the 6800 except... This drove non 6800 conversant people up the wall. It is clear to me that the people working with Intel for all of their professional careers have no reason to expect better. I spent 10 years making my compiler output low level c code, and believe me, I don't like c. The latest development of the compiler outputting asm is much more rewarding, so i am all for programming with asm. As an experienced user of 68xxx processors, the Intel stuff is not at all orthagonal. The Motorola stuff is. The reverse endian of multibyte data type is a royal pain. For mainstream computing, Motorola is out of the picture, Intel is it. That doesn't mean that the best always wins. It means that I have to learn what it takes to work with what there is and this forum helps greatly. Thanks Hutch!

Mike