Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
Solved

# ASM question

Posted on 2003-10-27
Medium Priority
526 Views
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
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
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
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
• 9
• 6
• 3
• +1

LVL 26

Expert Comment

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
xor   eax, eax
mov   al, ds:[edi]
pop   edi
end;

Regards,
Russell
0

LVL 6

Expert Comment

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
xor eax,eax
mov al,ds:[edi]
pop edi
end;

0

LVL 5

Expert Comment

ID: 9631507
Listening...
0

LVL 8

Author Comment

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

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]
xor eax,eax
mov al,ds:[edi]
mov edi,[ebx+bump]
xor edx,edx
mov dl,ds:[edi]

pop edi
0

LVL 6

Expert Comment

ID: 9633886
Still not right ... sorry ... but you get the idea.
0

LVL 26

Expert Comment

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
xor   eax, eax
mov   al, ds:[edi]
pop   edi
end;

Regards,
Russell

0

LVL 26

Expert Comment

ID: 9634064

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

0

LVL 6

Expert Comment

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

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

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

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

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

LVL 8

Author Comment

ID: 9637177
LOL!
0

LVL 8

Author Comment

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

>>begin

push ebp
mov ebp,esp
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

ID: 9644583
begin
asm
push ebp
mov ebp,esp
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

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

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

swift99 earned 1000 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

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

Question has a verified solution.

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

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi projâ€¦
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â€¦
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on tâ€¦
In this video, Percona Solution Engineer Rick Golba discuss how (and why) you implement high availability in a database environment. To discuss how Percona Consulting can help with your design and architecture needs for your database and infrastrâ€¦
###### Suggested Courses
Course of the Month8 days, 6 hours left to enroll