; Listing generator
; LocoDelAssembly 2007.06.01

INSTRUCTIONS equ bt in ja jb jc je jg jl jo jp js jz or 		       \
		 aaa aad aam aas adc add and bsf bsr btc btr bts cbw cdq clc   \
		 cld cli cmc cmp cqo cwd daa das dec div fld fst hlt inc ins   \
		 int jae jbe jge jle jmp jna jnb jnc jne jng jnl jno jnp jns   \
		 jnz jpe jpo lar lds lea les lfs lgs lsl lss ltr mov mul neg   \
		 nop not out pop por rcl rcr ret rol ror rsm sal sar sbb shl   \
		 shr stc std sti str sub ud2 xor			       \
		 arpl call cdqe clgi clts cmps cwde emms fabs fadd fbld fchs   \
		 fcom fcos fdiv feni fild fist fld1 fldz fmul fnop fsin fstp   \
		 fsub ftst fxam fxch idiv imul insb insd insw int1 int3 into   \
		 invd iret jcxz jnae jnbe jnge jnle lahf lgdt lidt lldt lmsw   \
		 lods loop movd movq movs orpd orps outs pand popa popd popf   \
		 popq popw push pxor retd retf retn retq retw sahf salc scas   \
		 seta setb setc sete setg setl seto setp sets setz sgdt shld   \
		 shrd sidt sldt smsw stgi stos test verr verw wait xadd xchg   \
		 xlat							       \
		 addpd addps addsd addss andpd andps bound bswap cmova cmovb   \
		 cmovc cmove cmovg cmovl cmovo cmovp cmovs cmovz cmppd cmpps   \
		 cmpsb cmpsd cmpsq cmpss cmpsw cpuid divpd divps divsd divss   \
		 enter f2xm1 faddp fbstp fclex fcomi fcomp fdisi fdivp fdivr   \
		 femms ffree fiadd ficom fidiv fimul finit fistp fisub fldcw   \
		 fldpi fmulp fneni fprem fptan fsave fsqrt fstcw fstsw fsubp   \
		 fsubr fucom fwait fyl2x icebp iretd iretq iretw jecxz jrcxz   \
		 lddqu leave lodsb lodsd lodsq lodsw loopd loope loopq loopw   \
		 loopz maxpd maxps maxsd maxss minpd minps minsd minss movsb   \
		 movsd movsq movss movsw movsx movzx mulpd mulps mulsd mulss   \
		 mwait outsb outsd outsw pabsb pabsd pabsw paddb paddd paddq   \
		 paddw pandn pause pavgb pavgw pf2id pf2iw pfacc pfadd pfmax   \
		 pfmin pfmul pfrcp pfsub pi2fd pi2fw popad popaw popfd popfq   \
		 popfw pslld psllq psllw psrad psraw psrld psrlq psrlw psubb   \
		 psubd psubq psubw pusha pushd pushf pushq pushw rcpps rcpss   \
		 rdmsr rdpmc rdtsc retfd retfq retfw retnd retnq retnw scasb   \
		 scasd scasq scasw setae setbe setge setle setna setnb setnc   \
		 setne setng setnl setno setnp setns setnz setpe setpo stosb   \
		 stosd stosq stosw subpd subps subsd subss vmrun vmxon wrmsr   \
		 xlatb xorpd xorps					       \
		 andnpd andnps cmovae cmovbe cmovge cmovle cmovna cmovnb cmovnc\
		 cmovne cmovng cmovnl cmovno cmovnp cmovns cmovnz cmovpe cmovpo\
		 comisd comiss fcmovb fcmove fcmovu fcomip fcompp fdivrp ffreep\
		 ficomp fidivr fisttp fisubr fldenv fldl2e fldl2t fldlg2 fldln2\
		 fnclex fndisi fninit fnsave fnstcw fnstsw fpatan fprem1 frstor\
		 frstpm fscale fsetpm fstenv fsubrp fucomi fucomp fxsave haddpd\
		 haddps hsubpd hsubps invlpg lfence looped loopeq loopew loopne\
		 loopnz loopzd loopzq loopzw mfence movapd movaps movdqa movdqu\
		 movhpd movhps movlpd movlps movnti movntq movsxd movupd movups\
		 paddsb paddsw pextrw pfnacc pfsubr phaddd phaddw phsubd phsubw\
		 pinsrw pmaxsw pmaxub pminsw pminub pmulhw pmullw psadbw pshufb\
		 pshufd pshufw psignb psignd psignw pslldq psrldq psubsb psubsw\
		 pswapd pushad pushaw pushfd pushfq pushfw rdmsrq rdtscp setalc\
		 setnae setnbe setnge setnle sfence shufpd shufps skinit sqrtpd\
		 sqrtps sqrtsd sqrtss swapgs sysret vmcall vmload vmread vmsave\
		 vmxoff wbinvd wrmsrq					       \
		 clflush cmovnae cmovnbe cmovnge cmovnle cmpeqpd cmpeqps       \
		 cmpeqsd cmpeqss cmplepd cmpleps cmplesd cmpless cmpltpd       \
		 cmpltps cmpltsd cmpltss cmpxchg fcmovbe fcmovnb fcmovne       \
		 fcmovnu fdecstp fincstp fnstenv frndint fsincos fucomip       \
		 fucompp fxrstor fxtract fyl2xp1 invlpga ldmxcsr loopned       \
		 loopneq loopnew loopnzd loopnzq loopnzw monitor movddup       \
		 movdq2q movhlps movlhps movntdq movntpd movntps movq2dq       \
		 paddusb paddusw palignr pavgusb pcmpeqb pcmpeqd pcmpeqw       \
		 pcmpgtb pcmpgtd pcmpgtw pfcmpeq pfcmpge pfcmpgt pfpnacc       \
		 pfrsqrt phaddsw phsubsw pmaddwd pmulhrw pmulhuw pmuludq       \
		 pshufhw pshuflw psubusb psubusw rsqrtps rsqrtss stmxcsr       \
		 syscall sysexit sysretq ucomisd ucomiss vmclear vmmcall       \
		 vmptrld vmptrst vmwrite				       \
		 addsubpd addsubps cmpneqpd cmpneqps cmpneqsd cmpneqss cmpnlepd\
		 cmpnleps cmpnlesd cmpnless cmpnltpd cmpnltps cmpnltsd cmpnltss\
		 cmpordpd cmpordps cmpordsd cmpordss cvtdq2pd cvtdq2ps cvtpd2dq\
		 cvtpd2pi cvtpd2ps cvtpi2pd cvtpi2ps cvtps2dq cvtps2pd cvtps2pi\
		 cvtsd2si cvtsd2ss cvtsi2sd cvtsi2ss cvtss2sd cvtss2si fcmovnbe\
		 maskmovq movmskpd movmskps movshdup movsldup packssdw packsswb\
		 packuswb pfrcpit1 pfrcpit2 pfrsqit1 pmovmskb pmulhrsw prefetch\
		 sysenter sysexitq unpckhpd unpckhps unpcklpd unpcklps vmlaunch\
		 vmresume						       \
		 cmpxchg8b cvttpd2dq cvttpd2pi cvttps2dq cvttps2pi cvttsd2si   \
		 cvttss2si pmaddubsw prefetchw punpckhbw punpckhdq punpckhwd   \
		 punpcklbw punpckldq punpcklwd				       \
		 cmpunordpd cmpunordps cmpunordsd cmpunordss cmpxchg16b        \
		 loadall286 loadall386 maskmovdqu prefetcht0 prefetcht1        \
		 prefetcht2 punpckhqdq punpcklqdq prefetchnta

PREFIXES equ	 rep lock repe repz repne repnz

DATA_DEFINITORS  equ db dw du dd dp df dq dt file
DATA_RESERVERS	 equ rb rw rd rp rf rq rt

CRLF		  equ 13, 10  ; Remove 13 for Linux
MAX_BYTES	  equ 13

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MODE MACROSES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
macro use16
{
use16
  _USE = 16
}

macro use32
{
use32
  _USE = 32
}

macro use64
{
use64
  _USE = 64
}

macro detect_mode
{
local aux

  _USE = 32

  virtual at 0
    xchg  eax, eax
    load aux byte from 0

    if aux = $66
      _USE = 16
    else if aux = $87
      _USE = 64
    end if
  end virtual
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;; DISPLAYING MACROSES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

macro display_address address*
{
local aux, digit

  aux  = address

  repeat _USE / 4
    digit = aux shr (_USE - 4 * %) and $F

    display digit + '0' + ('9' - 'B') and (9 - digit) shr 4 and $F
  end repeat

  display ': '
}

macro display_bytes pointer
{
local aux, size, digit

  size = $ - pointer

  if size > MAX_BYTES
    size = MAX_BYTES
  end if

  repeat size
    load aux byte from pointer+%-1

      digit = aux shr 4
      display digit + '0' + ('9' - 'B') and (9 - digit) shr 4 and $F

      digit = aux and $F
      display digit + '0' + ('9' - 'B') and (9 - digit) shr 4 and $F


    display ' '
  end repeat

  repeat MAX_BYTES - size
    display '   '
  end repeat
}

; The macro below in some situations doesn't adds a space to separate things unfortunatelly, so for readability ensurance
; another one will be used instead...
;macro display_args [args]
;{
;common
;  aux = 1
;
;forward
;  if ~args eq
;    if aux
;      display ' '
;    else
;      display ', '
;    end if
;
;    aux = 0
;
;    match =ON, _RESOLVE_EQUATES
;    \{
;      match args, args
;      \\{
;        irps arg, args
;        \\\{
;          display \\\`arg
;        \\\}
;      \\}
;    \}
;    match =OFF, _RESOLVE_EQUATES
;    \{
;      irps arg, args
;      \\{
;        display \\`arg
;      \\}
;
;    \}
;  end if
;}

; This one separates everything with one space. A very ugly listing but at least you will not see things
; like "push ebxesiedi" nor "ret word0"

macro display_args [args]
{
common
  aux = 1

forward
  if ~args eq
    if ~aux
      display ','
    end if

    aux = 0

    match =ON, _RESOLVE_EQUATES
    \{
      match args, args
      \\{
	if ~args eqtype ""
	  irps arg, args
	  \\\{
	      display ' ', \\\`arg
	  \\\}
	else
	  display " '", args, "'"
	end if
      \\}
    \}
    match =OFF, _RESOLVE_EQUATES
    \{
      if ~args eqtype ""
	irps arg, args
	\\{
	    display ' ', \\`arg
	\\}
      else
	display " '", args, "'"
      end if
    \}
  end if
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;; INSTRUCTIONS & PREFIXES MACROSES ;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

macro prefix mnemonic
{
local aux

  macro mnemonic [args]
  \{
  \common
    match =1, _ON_VIRTUAL\\{_LISTING equ 0\\}
    match =equ, args\\{_LISTING equ 0\\}
    match =equ any, args\\{_LISTING equ 0\\}

    match =1, _LISTING
    \\{
      display_address $
      aux = $
    \\}

    mnemonic

    match =1, _LISTING
    \\{
      display_bytes aux

      display \`mnemonic
      display CRLF
    \\}

    match =1, _ON_VIRTUAL\\{restore _LISTING\\}
    match =equ, args\\{restore _LISTING\\}
    match =equ any, args\\{restore _LISTING\\}

    def_prefix mnemonic
    args
    purge mnemonic
  \}
}

macro def_prefix mnemonic
{
  macro def_prefix mnemonic
  \{
    prefix mnemonic
  \}
  def_prefix mnemonic
}

macro instruction mnemonic
{
local aux

  macro mnemonic [args]
  \{
  \common
    match =1, _ON_VIRTUAL\\{_LISTING equ 0\\}
    match =equ, args\\{_LISTING equ 0\\}
    match =equ any, args\\{_LISTING equ 0\\}

    match =1, _LISTING
    \\{
      display_address $
      aux = $
    \\}

    mnemonic args

    match =1, _LISTING
    \\{
      display_bytes aux

      display \`mnemonic

      virtual at 0
	db \`mnemonic
	repeat 11 - $
	  display ' '
	end repeat
      end virtual

      display_args args
      display CRLF
    \\}

    match =1, _ON_VIRTUAL\\{restore _LISTING\\}
    match =equ, args\\{restore _LISTING\\}
    match =equ any, args\\{restore _LISTING\\}
  \}
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DATA MACROSES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

macro data_define mnemonic
{
local aux
  macro mnemonic [args]
  \{
  \common
    match =1, _ON_VIRTUAL\\{_LISTING equ 0\\}
    match =equ, args\\{_LISTING equ 0\\}
    match =equ any, args\\{_LISTING equ 0\\}

    match =1, _LISTING
    \\{
      display_address $
       aux = $
    \\}

    mnemonic args

    match =1, _LISTING
    \\{
      display_bytes aux

      display \`mnemonic

      display_args args
      display CRLF

      aux = aux + MAX_BYTES

      repeat ($ - aux + MAX_BYTES - 1) / MAX_BYTES
	display_address aux
	display_bytes aux
	display CRLF

	aux = aux + MAX_BYTES
      end repeat
    \\}

    match =1, _ON_VIRTUAL\\{restore _LISTING\\}
    match =equ, args\\{restore _LISTING\\}
    match =equ any, args\\{restore _LISTING\\}
  \}

  struc mnemonic [args]
  \{
  \common
    match =1, _ON_VIRTUAL\\{_LISTING equ 0\\}
    match =equ, args\\{_LISTING equ 0\\}
    match =equ any, args\\{_LISTING equ 0\\}

    match =1, _LISTING
    \\{
      display_address $
      aux = $
    \\}

    . mnemonic args

    match =1, _LISTING
    \\{
      display_bytes aux

      display  \`., ' ', \`mnemonic

      display_args args
      display CRLF

      aux = aux + MAX_BYTES

      repeat ($ - aux + MAX_BYTES - 1) / MAX_BYTES
	display_address aux
	display_bytes aux
	display CRLF

	aux = aux + MAX_BYTES
      end repeat
    \\}

    match =1, _ON_VIRTUAL\\{restore _LISTING\\}
    match =equ, args\\{restore _LISTING\\}
    match =equ any, args\\{restore _LISTING\\}
  \}
}

macro data_reserve mnemonic
{
local aux
  macro mnemonic [args]
  \{
  \common
    match =1, _ON_VIRTUAL\\{_LISTING equ 0\\}
    match =equ, args\\{_LISTING equ 0\\}
    match =equ any, args\\{_LISTING equ 0\\}

    match =1, _LISTING
    \\{
      display_address $
       aux = $
    \\}

    mnemonic args

    match =1, _LISTING
    \\{
      times MAX_BYTES display '   '

      display \`mnemonic

      display_args args
      display CRLF
    \\}

    match =1, _ON_VIRTUAL\\{restore _LISTING\\}
    match =equ, args\\{restore _LISTING\\}
    match =equ any, args\\{restore _LISTING\\}
  \}

  struc mnemonic [args]
  \{
  \common
    match =1, _ON_VIRTUAL\\{_LISTING equ 0\\}
    match =equ, args\\{_LISTING equ 0\\}
    match =equ any, args\\{_LISTING equ 0\\}

    match =1, _LISTING
    \\{
      display_address $
      aux = $
    \\}

    . mnemonic args

    match =1, _LISTING
    \\{
      times MAX_BYTES display '   '

      display  \`., ' ', \`mnemonic

      display_args args
      display CRLF
    \\}

    match =1, _ON_VIRTUAL\\{restore _LISTING\\}
    match =equ, args\\{restore _LISTING\\}
    match =equ any, args\\{restore _LISTING\\}
  \}
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;; LISTING CONTROL MACROSES ;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

macro virtual [args]
{
common
  _ON_VIRTUAL equ 1

  virtual args
}

macro end [args]
{
common
  match =virtual, args\{restore _ON_VIRTUAL\}

  end args
}

macro enable_listing
{
  detect_mode

  match =0, _MACROSES_INSTALLED
  \{
    match instructions, INSTRUCTIONS
    \\{
      irps ins, instructions
      \\\{
	instruction ins
      \\\}
    \\}

    match prefixes, PREFIXES
    \\{
      irps prefix, prefixes
      \\\{
	def_prefix prefix
      \\\}
    \\}

    match data_definitors, DATA_DEFINITORS
    \\{
      irps def, data_definitors
      \\\{
	data_define def
      \\\}
    \\}

    match data_reservers, DATA_RESERVERS
    \\{
      irps def, data_reservers
      \\\{
	data_reserve def
      \\\}
    \\}
  \}

  _MACROSES_INSTALLED equ 1
  _LISTING	      equ 1
}

macro disable_listing
{
  _LISTING equ 0
}

macro enable [feature*]
{
forward
  UNKNOWN equ 1

  match =resolve_equates, feature
  \{
    restore _RESOLVE_EQUATES
    _RESOLVE_EQUATES equ ON
    UNKNOWN equ 0
  \}

  match =listing, feature
  \{
    enable_listing
    UNKNOWN equ 0
  \}

  match =1, UNKNOWN
  \{
    display 'ERROR: Unknown "',`feature, '" feature', 13, 10
    err
  \}

  restore UNKNOWN
  restore UNKNOWN
}

macro disable [feature*]
{
  UNKNOWN equ 1

  match =resolve_equates, feature
  \{
    restore _RESOLVE_EQUATES
    _RESOLVE_EQUATES equ OFF
    UNKNOWN equ 0
  \}

  match =listing, feature
  \{
    disable_listing
    UNKNOWN equ 0
  \}

  match =1, UNKNOWN
  \{
    display 'ERROR: Unknown "',`feature, '" feature', 13, 10
    err
  \}

  restore UNKNOWN
  restore UNKNOWN
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; INITIALIZATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

_MACROSES_INSTALLED equ 0
_ON_VIRTUAL	    equ 0

disable resolve_equates
