flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > HL Expressions in ASM!?

Author
Thread Post new topic Reply to topic
uart777



Joined: 17 Jan 2012
Posts: 369
uart777 26 Apr 2012, 00:48
Hi, everyone!

Years ago, I was toying with the "let a=b" example macro written by Tomasz. I thought it was an interesting concept and a good example of the match directive, but it wasn't seriously useful because there is no difference between "mov eax,1" and "let eax=1"... not if there's only 1 operation.

So, I modified "let" with a forward to process multiple arguments then added more instructions - <<>> (shl/shr), &| (and/or) r=&[] (lea) - and basic optimizations like r=0 (xor r, r), x+1 (inc x). Now, it's extremely useful. You can write low-level "expressions" (so to speak) in polish notation, left to right with no precedence. Example:

Code:
; a=b*c+d>>4. reduces 5 lines to 1

let eax=[b], eax*[c], eax+[d], eax>>4, [a]=eax    


Here are example procedures that use "let" entirely:

Code:
; mix a, b, n - alpha combination. n=0-255
; note: this only processes one pixel, but is
; fast enough for small images such as text,
; controls and anti-aliasing edges

command mix, a, b, n
locals sr, sg, sb, dr, dg, db
let eax=[a], edx=[b]
.if [n]=NO  ; if no alpha, return a
  jmp .r
.end
.if [n]>254 ; if maximum, return b
  let eax=edx
  jmp .r
.end
let \ ; extract r/g/b components
ecx=eax, ecx>>16, ecx&0FFh, [sr]=ecx,\
ecx=eax, ecx>>8, ecx&0FFh, [sg]=ecx,\
ecx=eax, ecx&0FFh, [sb]=ecx,\
ecx=edx, ecx>>16, ecx&0FFh, [dr]=ecx,\
ecx=edx, ecx>>8, ecx&0FFh, [dg]=ecx,\
ecx=edx, ecx&0FFh, [db]=ecx
let \ ; calculate deltas: (((s-d)*a)>>Cool+d
eax=[sr], eax-[dr], eax*[n], eax>>8, eax+[dr],\
ecx=[sg], ecx-[dg], ecx*[n], ecx>>8, ecx+[dg],\
edx=[sb], edx-[db], edx*[n], edx>>8, edx+[db]
let \ ; construct RGB
eax<<16, ecx<<8, eax|ecx, eax|edx
.r:
endc

command draw.tilemap, tm
locals p, i,\
x, y, mx, my, mw, mh, tw, th,\
locations, images
let eax=[tm],\
[mx]=[?map.x+eax], [my]=[?map.y+eax],\
[mw]=[?map.w+eax], [mh]=[?map.h+eax],\
[tw]=[?map.tile.w+eax], [th]=[?map.tile.h+eax],\
ecx=&[?map.locations.p+eax], [locations]=ecx,\
ecx=&[?map.images+eax], [images]=ecx
let [i]=0
.loop [y]=0 to [mh]
  .loop [x]=0 to [mw]
    array.index [locations], [i]
    .if dword [eax] not -1
      get [p]=array.index [images], [eax]
      let eax=[x], eax*[tw], eax+[mx],\
      ecx=[y], ecx*[th], ecx+[my]
      .if eax>=[screen.w]
        jmp .end.x
      .end
      .if ecx>=[screen.h]
        jmp .end.y
      .end
      draw.image.at [p], eax, ecx
    .end
    .end.x:
    inc [i]
  .endl
.endl
.end.y:
endc

command text.copy, a, b
let eax=[a], edx=[b]
.while byte [edx] ; while *b
  let cl=[edx],\  ; *a++=*b++
  [eax]=cl,\
  eax+1, edx+1
.endw
let byte [eax]=0
endc    


Finally, here's the advanced "let" macro (not quite finished yet):

Code:
macro let [p] {
forward
define ?s 0
match =0 a==&b, ?s p \{ ; a=&[b], lea r, [b]
  lea a, b
  define ?s 1
\}
match =0 a==>b, ?s p \{ ; a=>[b], movsx r, byte [b]
  movsx a, byte b
  define ?s 1
\}
match =0 a==b, ?s p \{ ; a=b, mov or push/pop
  if a eqtype [] & b eqtype [] ; m=m
    push dword b
    pop dword a
  else
; if r=0, use xor r,r
    if a in <eax,ecx,edx,ebx,esi,edi> & b eq 0
      xor a, a
    else
      mov a, b
    end if
  end if
define ?s 1
\}

; (match a-b must be located before a+b
; because it causes ambiguity with [disp+imm]?)

match =0 a-b, ?s p \{
if b eq 1
  dec a
else
  sub a, b
end if
define ?s 1 \}

match =0 a+b, ?s p \{
if b eq 1
  inc a
else
  add a, b
end if
define ?s 1
\}

match =0 a*b, ?s p \{ imul a, b
define ?s 1 \}

; for idiv, only eax/n is allowed
; n must be r/m, not i. alters edx
; example: eax=n/123 may be written:
; let eax=n, ecx=123, eax/ecx

match =0 =eax/n, ?s p \{
cdq
idiv n
define ?s 1 \}
match =0 a<<b, ?s p \{ shl a, b
define ?s 1 \}
match =0 a>>b, ?s p \{ shr a, b
define ?s 1 \}
match =0 a&b, ?s p \{ and a, b
define ?s 1 \}
match =0 a|b, ?s p \{ or a, b
define ?s 1 \}
if ?s eq 0
ERROR: 'Invalid HL syntax: ' p
end if
}    
Post 26 Apr 2012, 00:48
View user's profile Send private message Reply with quote
Madis731



Joined: 25 Sep 2003
Posts: 2139
Location: Estonia
Madis731 26 Apr 2012, 07:59
Its all great, but let doesn't have the power to choose which registers to trash or use mul instead of imul
Post 26 Apr 2012, 07:59
View user's profile Send private message Visit poster's website Yahoo Messenger MSN Messenger Reply with quote
uart777



Joined: 17 Jan 2012
Posts: 369
uart777 26 Apr 2012, 08:36
Madis: This code is merely an example of an advanced "let". Programmers can edit it any way they like.

Signed is the default for numbers that can be negative (example, coordinates). One could create a numeric 1/0 constant for un/signed operations:

Code:
sign=1     ; set signed operations
let [n]>>4 ; uses sar
sign=0     ; set unsigned operations
let [n]>>4 ; uses shr    


* "let doesn't have the power to choose which registers to trash" - No registers are altered except the specified destination. Example: let ecx=0 (xor ecx, ecx) alters ecx and nothing else.

* "mul instead of imul" - Just use "mul r/m" in the situations where it's needed.

Must we choose one or the other? HL or LL? Why not incorporate both? Smile
Post 26 Apr 2012, 08:36
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1619
Location: Toronto, Canada
AsmGuru62 26 Apr 2012, 16:38
Does it do brackets too:
(eax-7)*(ecx+15) --> ???
Post 26 Apr 2012, 16:38
View user's profile Send private message Send e-mail Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.