flat assembler
Message board for the users of flat assembler.

 Index > Macroinstructions > HL Expressions in ASM!?
Author
 Thread
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)>>+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
}    ```
26 Apr 2012, 00:48
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
26 Apr 2012, 07:59
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?
26 Apr 2012, 08:36
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) --> ???
26 Apr 2012, 16:38
 Display posts from previous: All Posts1 Day7 Days2 Weeks1 Month3 Months6 Months1 Year Oldest FirstNewest First

 Jump to: Select a forum Official----------------AssemblyPeripheria General----------------MainTutorials and ExamplesDOSWindowsLinuxUnixMenuetOS Specific----------------MacroinstructionsOS ConstructionIDE DevelopmentProjects and IdeasNon-x86 architecturesHigh Level LanguagesProgramming Language DesignCompiler Internals Other----------------FeedbackHeapTest Area

Forum Rules:
 You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot vote in polls in this forumYou cannot attach files in this forumYou can download files in this forum

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

Website powered by rwasa.