Solved

ASM question

Posted on 2003-10-27
19
489 Views
Last Modified: 2013-11-22
Following code works fine:
function GetBump(x,y : integer) : integer;
// return pixel at x,y  (on 256x256 bump-map)
asm
      push edi
      mov edi,bump
      and eax,$ff      // modulate result:  x := x mod 256
      and edx,$ff      // modulate result:  y := y mod 256
      mov ah,dl
      add edi,eax
      xor eax,eax
      mov al,ds:[edi]
      pop edi
end;

Following code does not (now in a class):
function TTerrain.GetBump(x,y : integer) : integer;
// return pixel at x,y  (on 256x256 bump-map)
asm
      push edi
      mov edi,bump
      and eax,$ff      // modulate result:  x := x mod 256
      and edx,$ff      // modulate result:  y := y mod 256
      mov ah,dl
      add edi,eax
      xor eax,eax
      mov al,ds:[edi]
      pop edi
end;

It crashes on the mov al,ds:[edi] line. Bump is a pointer, valid and pointing to the correct address with a much-larger-than-required memory allocation.

I have done this for the moment, but looking at what Delphi generates, it'd be far faster to use the code above (it's called about a million times per second):
function TTerrain.GetBump(x,y : integer) : integer;
// return pixel at x,y  (on 256x256 bump-map)
begin
      x := x mod 256;
      y := y mod 256;
      Result := Bump[x, y];
end;

Any ideas?

Geoff M.
0
Comment
Question by:gmayo
  • 9
  • 6
  • 3
  • +1
19 Comments
 
LVL 26

Expert Comment

by:Russell Libby
ID: 9629616

Offhand (without looking) I would say that the object itself will be passed in on eax, thus you should be using edx/ecx to get the params.

asm
  push  edi
  mov   edi, bump
  and   edx, $ff    // modulate result:  x := x mod 256
  and   ecx, $ff    // modulate result:  y := y mod 256
  mov   dh, cl
  add   edi, edx
  xor   eax, eax
  mov   al, ds:[edi]
  pop   edi
end;

Regards,
Russell
0
 
LVL 6

Expert Comment

by:swift99
ID: 9631407
object is usually in EBX.  if bump is a property of the object, then the corect code should be

asm
     push edi
     mov ebx, self
     mov edi,[ebx+bump]
     and eax,$ff      // modulate result:  x := x mod 256
     and edx,$ff      // modulate result:  y := y mod 256
     mov ah,dl
     add edi,eax
     xor eax,eax
     mov al,ds:[edi]
     pop edi
end;


0
 
LVL 5

Expert Comment

by:snehanshu
ID: 9631507
Listening...
0
 
LVL 8

Author Comment

by:gmayo
ID: 9632162
Russell - still crashes.

Swift99 - nearly works except the y parameter is not having any effect - is one of the registers being overwritten?

snehanshu - you can listen to topics simply by clicking on the "subscribe" button, whcih doesn't trigger off emails to everybody to tell them you are listening, which is pointless...

Cheers for the help everybody

Geoff M.
0
 
LVL 6

Expert Comment

by:swift99
ID: 9633873
You aren't using EDX anywhere after you modulate it.

     push edi
     mov ebx, self
     and eax,$ff      // modulate result:  x := x mod 256
     and edx,$ff      // modulate result:  y := y mod 256
     mov ah,dl
     mov edi,[ebx+bump]
     add edi,eax
     xor eax,eax
     mov al,ds:[edi]
     mov edi,[ebx+bump]
     add edi,edx
     xor edx,edx
     mov dl,ds:[edi]

     pop edi
0
 
LVL 6

Expert Comment

by:swift99
ID: 9633886
Still not right ... sorry ... but you get the idea.
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 9634048

Swift99, to the best of my knowledge (and that of others), when using the register calling convention, self is always passed in EAX. If I am mistaken, then please correct me.

But, if self is in EBX, why do you perform the mov of self to EBX? I am also of the understanding that EBX should not be modified without being push'ed first. (per Borland)

< An asm statement must preserve the EDI, ESI, ESP, EBP, and EBX registers >

Geoff, you didnt mention that bump was a property of the class, which if this is the case:

function TForm1.GetBump(x,y : integer) : integer;
// return pixel at x,y  (on 256x256 bump-map)
asm
  push  edi
  mov   edi, [eax+bump]
  and   edx, $ff    // modulate result:  x := x mod 256
  and   ecx, $ff    // modulate result:  y := y mod 256
  mov   dh, cl
  add   edi, edx
  xor   eax, eax
  mov   al, ds:[edi]
  pop   edi
end;

Regards,
Russell



0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 9634064

Replace the TForm1 (my own testing) with your appropriate class name... ;-)


0
 
LVL 6

Expert Comment

by:swift99
ID: 9634215
From experience, self is not always loaded until you address a property.  EAX may or may not be self on entry, and Delphi uses EBX for self in the code I have disassembled.

EAX is used for returning values from functions, and is undefined on return from procedures.
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 6

Expert Comment

by:swift99
ID: 9634221
the best bet is to look at the code generated by your specific compiler and settings and work from there.
0
 
LVL 8

Author Comment

by:gmayo
ID: 9637149
This was code copied from elsewhere (the whole procedure, I simply converted it (and others) to a class with methods), so I can't comment on the usage of registers. I haven't done assembly since 68000 (which, compared to Intel, was a dream BTW). The implication was that Bump was part of that class, just not explicitly stated! I'll grab the Delphi-generated equivalent and post that tomorrow, but this gets me down to 18fps instead of 60fps (that's why I need it in ASM!).

Cheers

Geoff M.
0
 
LVL 6

Expert Comment

by:swift99
ID: 9637165
>> which, compared to Intel, was a dream BTW

(sounds of Handel's hallelujah chorus) AMEN brother!
0
 
LVL 8

Author Comment

by:gmayo
ID: 9637177
LOL!
0
 
LVL 8

Author Comment

by:gmayo
ID: 9644418
Ok, Delphi lines prefixed >>, the rest is asm:

>>begin

push ebp
mov ebp,esp
add esp,-$10
mov [ebp-$c],ecx
mov [ebp-$8],edx
mov [ebp-$4],eax

>>x := x mod 255;

mov eax,[ebp-$08]
mov ecx,$FF
cdq
idiv ecx
mov [ebp-$8],edx

>>y := y mod 255;

mov eax,[ebp-$0c]
mov ecx,$FF
cdq
idiv ecx
mov [ebp-$c],edx

>>Result := Bump[x,y];

mov eax,[ebp-$8]
shl eax,$6
mov edx,[ebp-$4]
mov edx,[edx+$0000012c]
lea eax,[edx+eax*8]
mov edx,[ebp-$c]
movzx eax,[eax+edx*2]
mov [ebp-$10],eax
mov eax,[ebp-$10]

>>end;

mov esp,ebp
pop ebp
ret
mov eax,eax (eh - won't even get executed anyway!)

---------

Any ideas on how to improve the efficiency of this? It should be possible to make it about 3x faster (non-class version). Points doubled as it seems to be harder than first thought.

Geoff M.
0
 
LVL 6

Expert Comment

by:swift99
ID: 9644583
begin
asm
push ebp
mov ebp,esp
add esp,-$10
mov [ebp-$c],ecx  // y
mov [ebp-$8],edx  // x
mov [ebp-$4],eax  // bump

//x := x mod 255;

and edx, $FF
// mov [x],edx // not required since you do not lose the register value

//y := y mod 255;

and ecx, $FF
// mov [y],ecx // not required since you do not lose the register value

//Result := Bump[x,y];
// mov ebx, self         // uncomment if bump is a property rather than a parameter
mov eax,edx
shl eax,$6
mov edx,[bump]         // change to mov eax, [ebx+bump] for bump being a property
mov edx,[edx+$0000012c]
lea eax,[edx+eax*8]
mov edx,ecx            // may be able to drop this line and ...
movzx eax,[eax+edx*2]  // replace this line with movzx eax,[eax+ecx*2]

// return value
mov [ebp-$10],eax
// mov eax,[ebp-$10]   // EBP -$10 and eax are now the same
end

end;
0
 
LVL 6

Expert Comment

by:swift99
ID: 9644604
oh yeah ... the loading of the registers is probably already handled by Delphi.  Double check the compiled output.
0
 
LVL 8

Author Comment

by:gmayo
ID: 9644846
Ok, this is what I got after changing the lines suggested, but it crashes on the mov edx,[edx+$12c] line:

asm
push ebp
mov ebp,esp
add esp,-$10
mov [ebp-$c],ecx  // y
mov [ebp-$8],edx  // x
mov [ebp-$4],eax  // bump
and edx, $FF
and ecx, $FF
mov ebx, self         // uncomment if bump is a property rather than a parameter
mov eax,edx
shl eax,$6
mov eax,[ebx+bump]         // change to mov eax, [ebx+bump] for bump being a property
mov edx,[edx+$0000012c]
lea eax,[edx+eax*8]
movzx eax,[eax+ecx*2]  // replace this line with movzx eax,[eax+ecx*2]
mov [ebp-$10],eax
end;

Perhaps the way to go would be to have a local (to the unit) variable which contains the bump pointer? Then just set it when the class is called.

eg
implementation
var bump : pointer;
procedure TMyClass.DoMyThing;
begin
  bump := classbump;
  GetBump(x,y)*1000000
etc

Cheers

Geoff M.
0
 
LVL 6

Accepted Solution

by:
swift99 earned 250 total points
ID: 9644935
replace

mov ebx, self         // uncomment if bump is a property rather than a parameter
mov eax,edx
shl eax,$6
mov eax,[ebx+bump]         // change to mov eax, [ebx+bump] for bump being a property
mov edx,[edx+$0000012c]
lea eax,[edx+eax*8]


with

mov eax,edx
shl eax,$6
mov ebx, self         // uncomment if bump is a property rather than a parameter
mov edx,[ebx+bump]         // change to mov eax, [ebx+bump] for bump being a property
mov edx,[edx+$0000012c]
lea eax,[edx+eax*8]
0
 
LVL 8

Author Comment

by:gmayo
ID: 9652608
Hmmm. Seems I was not comparing like-for-like WRT to ASM versus Delphi code.  Still, I have got a 20% increase with speed (not the 300% originally thought), so thanks for your help.

Geoff M.
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now