flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > 'pk' macro (works this time :)

Author
Thread Post new topic Reply to topic
Borsuc



Joined: 29 Dec 2005
Posts: 2468
Location: Bucharest, Romania
Borsuc
Hey,

I developed the 'pk' macro, which I had trouble with a few weeks ago because I was new to Fasm.. And it's based on Tomasz's 'classical' fasm method he posted.. thanks again

The reason I built this up was because I wanted to do it much more flexible and it proved to be a really good learning of Fasm preprocessor. I know, the implementation is a bit ugly because it uses a LOT of nesting stuff.. but it's pretty fast, because it has little to do at each pass (mainly because most of the job is done by preprocessor). Any suggestions on how it can be improved, or just some feedback is welcome.


Description:
Quote:
The 'pk' macro can be pretty useful. It can either make the code more readable in some cases, and add some optimizations for situations like:
Code:
mov bh, 5
mov bl, 1
mov ax, 2    
Which, written using the 'pk' macro pk mov bh:5, bl:1, ax:2 becomes:
Code:
mov bx, 0x0501  ; bh is 5 and bl is 1
mov ax, 2    
packs the constant values after the ':' into corresponding registers; everything is processed from left to right, so if you define ah:5 and then eax:2, the value in ah (5) will be completely replaced.

NOTE: this macro packs ONLY constants (immediate values).

Another example:
Code:
pk mov ah:5, eax:2    
will generate
Code:
mov eax, 2    
because eax:2 was encountered after ah:5, and it completely replaced it, since eax occupies the entire register, so it is, in fact, mov eax, 0x00000002, which completely sets ah to 0!

Please be careful when using these instructions (in fact, those that modify flags, e.g: add, sub, xor...). They DO NOT generate the same flags. Always try to imagine what will become after these instructions, and do the flag operations accordingly.

Another example:
Code:
pk and cx:1125h, eax:2, ch:3    
This produces the actual:
Code:
and cx, 0x0325
and eax, 2    


ch:3 replaces the 0x11 in cx's upper byte, because it is on the right, which means it is processed after cx... eax should be obvious Smile

and cx, 0x0325 is used here before and eax, 2 because the counter (cl,ch,cx,ecx) register was found before the accumulator (al,ah,ax,eax).

It's important to note this is only a macro, not something magical, and as such you should not overuse it, especially in some circumstances where it generates improper or poor code. And watch out for the flags! Wink




Here's it:

PS: "@err" signals error to preprocessor (is defined as @err fix macro +) and "err" to assembler.. if anyone has a idea for other ways, please share it Very Happy

Code:
macro pk [def]
{
 common
  ; list holds the ordered register bases, which are in fact
  ; symbolic constants representing the size mask
  ;
  ; the SIZE MASK is the mask of the compiled reg
  ; ex: FFFF means 16-bit register, FF00 means high-part 8-bit reg (ah,bh,ch,dh), etc...
  ;
  define list +  ; dummy value to start

  ; base is register type (accumulator, counter, etc...)
  ; the SIZE MASK is the second symbol
  ; third symbol is shift left value (i.e ch has shift=8 )
  ;
  ; these are stored temporary in 't' symbolic constant
  ; 't' also serves for other purposes (like error checking)
  define t

  ;
  ; each base name (eg: ax for accumulator, si for source index) has 2 type of prefixes
  ; if prefix is '_' then the specified symbolic constant contains the SIZE MASK
  ; if prefix is 'c' it means it's the 'immediate' or 'constant' value for the register
  ;
  ; eg: _ax is the SIZE MASK for accumulator
  ;     cax is the immediate value for accumulator
  ;
  ;     if _ax = $FFFFFFFF
  ;       mov eax, cax
  ;     else if _ax = $FFFF
  ;       mov ax, cax
  ;     ...
  ;
  ; or something like that Smile
  ;
  irp r, ax,bx,cx,dx,si,di,bp,sp \{ define _\#r \}  ; null-out all the SIZE MASKS

  match instr p, def \{
   irp parm, p \\{ match reg:v, parm \\\{

    irp r, ax,bx,cx,dx,si,di,bp,sp \\\\{
     match =e\\\\#r, reg \\\\\{ define t r FFFFFFFF 0 \\\\\}
     match =r, reg \\\\\{ define t r FFFF 0 \\\\\} \\\\}

    irp r, a,b,c,d \\\\{
     match =r\\\\#h, reg \\\\\{ define t r\\\\\#x FF 8 \\\\\}
     match =r\\\\#l, reg \\\\\{ define t r\\\\\#x FF 0 \\\\\} \\\\}

    match , t \\\\{
     @err ; invalid register
    \\\\}

    match base mask shift, t \\\\{
     restore t  ; revert back to empty definition

     if (~ v eqtype 0) | (v > $\\\\#mask)
      err ; invalid immediate operand
     end if


     match , _\\\\#base \\\\\{
      match old, list \\\\\\{
       restore list
       define list old,base  ; append it to the list
      \\\\\\}

      restore _\\\\\#base
      define _\\\\\#base 0  ; starting number (size mask)
      define c\\\\\#base 0
     \\\\\}

     match size, _\\\\#base \\\\\{
      restore _\\\\\#base
      define _\\\\\#base (size) or ($\\\\\#mask shl shift)  ; combine it with the mask
     \\\\\}

     match val, c\\\\#base \\\\\{
      restore c\\\\\#base

      ; now calculate the immediate
      ; first clear the bits in val, within our current mask
      ; then 'or' it with the new value to yield the result
      define c\\\\\#base (val) and not ($\\\\\#mask shl shift)  or  ((v) shl shift)
     \\\\\}

    \\\\} define t + \\\}    ; just a signal

    match , t \\\{
     @err ; invalid arguments
    \\\}
    restore t                ; remove the signal
   \\}

   ; iterate through the list and encode the specified instructions
   ; each element in the list is the name of a symbolic constant (base name)
   ; well, in fact it's the name of the symbolic constant without '_' prefix
   ; anyway, we also need it for constant value (with a 'c' prefix)
   ; '_' prefix means the SIZE MASK for the specified base register

   restore t  ; remove the empty definition
   define t + ; just a signal to indicate our  match instr p, def  did work

   match +=,regs, list \\{   ; list began with a dummy '+' value, so ignore it and the comma
    restore list

    irp r, regs \\\{

     if _\\\#r = $FFFFFFFF   ; ex: eax
       instr e\\\#r, c\\\#r
     else if _\\\#r = $FFFF  ; ex: ax
       instr r, c\\\#r
     else if _\\\#r = $FF00  ; ex: ah
       irp i, a,b,c,d \\\\{ match =i\\\\#x, r \\\\\{
        instr i\\\\\#h, c\\\\\#r shr 8
       \\\\\} \\\\}
     else
       irp i, a,b,c,d \\\\{ match =i\\\\#x, r \\\\\{
        instr i\\\\\#l, c\\\\\#r
       \\\\\} \\\\}
     end if

     restore _\\\#r,c\\\#r ; clean up
    \\\}
   \\}
  \}

  ; see if pk has invalid arguments (if first match was false)
  ; use t as an arbitrary variable to signal if match was processed
  match , t \{
   @err ; invalid use of instruction argument
  \}

  ; cleanup
  restore t
}    



Any suggestions or improvements are welcome. Smile
Regards


Last edited by Borsuc on 08 Feb 2006, 11:38; edited 1 time in total
Post 01 Feb 2006, 18:46
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7106
Location: Slovakia
vid
it would be nice to say what your macro should do first. "pk" isn't very descriptive Wink
Post 04 Feb 2006, 16:15
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
RedGhost



Joined: 18 May 2005
Posts: 444
Location: BC, Canada
RedGhost
The_Grey_Beast wrote:
mov bx, 0x0501 ; bh is 5 and bl is 1


that never even crossed my mind when you need to set the low and high byte to just set the 16bit register (one less mov instruction) i think im gonna optimize some of my realmode/dos apps, thanks Very Happy

_________________
redghost.ca
Post 05 Feb 2006, 09:42
View user's profile Send private message AIM Address MSN Messenger Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2468
Location: Bucharest, Romania
Borsuc
You're welcome.
I tried to explain it in the Description quote, if you think you can add something there to make it more 'descriptive' feel free to suggest it Wink
Post 08 Feb 2006, 10:51
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7106
Location: Slovakia
vid
oh, sorry. but description should come first because then you don't know what are you reading about until you reach description
Post 08 Feb 2006, 11:10
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2468
Location: Bucharest, Romania
Borsuc
thanks
fixed
Post 08 Feb 2006, 11:38
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7106
Location: Slovakia
vid
by the way: are you sure "err" signals error to assembler? How did you define it? Because if it's undefined symbol then it causes error during parsing, meaning that
Code:
if 0
err
end if    
causes error too
Post 08 Feb 2006, 11:55
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2468
Location: Bucharest, Romania
Borsuc
it's not defined, since it's not a valid instruction anyway.
not to worry, i tested, but I'm also a little confused between parser and assembler.
Post 08 Feb 2006, 12:13
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7106
Location: Slovakia
vid
after preprocessing, you have TEXTUAL source. During parsing, everything is translated into FASM internal binary form. All expressions, instruction arguments, strings etc. have some binary representation. But representation for directives/instructions (treated same by FASM) are pointers to handler of that directive/instruction. And of course, for undefined ones there is no handler, so error occurs during preprocessing, as there is no binary representation for undefined symbol and textual source cannot be translated to binary form.
Post 08 Feb 2006, 12:17
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2468
Location: Bucharest, Romania
Borsuc
I thought parser stops when it sees if 0 because it only recognizes eqtype in eq..
it worked when I tested, maybe there's some trick I coded and I am not even aware of Very Happy
Post 08 Feb 2006, 12:19
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7106
Location: Slovakia
vid
oh, yes, i forgot, parser can actually also remove if-ed blocks which are already predictable without assembling (if 0, if abcd eq abcd, if a in <a,b,c> etc.) i shouldn't forget that, especially because it was my idea Smile...

but in this example it will (hopefully) cause error:
Code:
a=1
if a=0
  err
end if    
Post 08 Feb 2006, 13:06
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2468
Location: Bucharest, Romania
Borsuc
it doesn't give error when i compile.
maybe because that's the assembly stage, not parse stage, and maybe it's different? (parser doesn't have numeric constants, that's why it's assembly stage)
Post 08 Feb 2006, 13:09
View user's profile Send private message Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 7484
Location: Kraków, Poland
Tomasz Grysztar
There are almost no errors that may happen during parsing stage - the illegal instruction error like here happens at the assembly stage, not parsing.
Post 08 Feb 2006, 13:19
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7106
Location: Slovakia
vid
you store something that stores such "parser" error and signals them only if they occur in final assembling pass? Or how does it work... i know you wrote you want to do something like that but then you didn't do because not all errors can be romeved from parser
Post 08 Feb 2006, 13:22
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number 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-2019, Tomasz Grysztar.

Powered by rwasa.