Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 530
  • Last Modified:

ASM question

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
gmayo
Asked:
gmayo
  • 9
  • 6
  • 3
  • +1
1 Solution
 
Russell LibbySoftware Engineer, Advisory Commented:

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
 
swift99Commented:
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
 
snehanshuCommented:
Listening...
0
Industry Leaders: 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!

 
gmayoAuthor Commented:
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
 
swift99Commented:
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
 
swift99Commented:
Still not right ... sorry ... but you get the idea.
0
 
Russell LibbySoftware Engineer, Advisory Commented:

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
 
Russell LibbySoftware Engineer, Advisory Commented:

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


0
 
swift99Commented:
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
 
swift99Commented:
the best bet is to look at the code generated by your specific compiler and settings and work from there.
0
 
gmayoAuthor Commented:
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
 
swift99Commented:
>> which, compared to Intel, was a dream BTW

(sounds of Handel's hallelujah chorus) AMEN brother!
0
 
gmayoAuthor Commented:
LOL!
0
 
gmayoAuthor Commented:
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
 
swift99Commented:
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
 
swift99Commented:
oh yeah ... the loading of the registers is probably already handled by Delphi.  Double check the compiled output.
0
 
gmayoAuthor Commented:
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
 
swift99Commented:
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
 
gmayoAuthor Commented:
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

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 9
  • 6
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now