Solved

ASM question

Posted on 2003-10-27
19
520 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

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

[Webinar] Learn How Hackers Steal Your Credentials

Do You Know How Hackers Steal Your Credentials? Join us and Skyport Systems to learn how hackers steal your credentials and why Active Directory must be secure to stop them. Thursday, July 13, 2017 10:00 A.M. PDT

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
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…
There are cases when e.g. an IT administrator wants to have full access and view into selected mailboxes on Exchange server, directly from his own email account in Outlook or Outlook Web Access. This proves useful when for example administrator want…
This tutorial will teach you the special effect of super speed similar to the fictional character Wally West aka "The Flash" After Shake : http://www.videocopilot.net/presets/after_shake/ All lightning effects with instructions : http://www.mediaf…
Suggested Courses
Course of the Month9 days, 1 hour left to enroll

617 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