MASM Macros

Chapter 13

  • MASM is actually two languages rolled into a single program. The runtime language is the standard x86-64/MASM assembly language you’ve been reading about in all the previous chapters. This is called the runtime language because the programs you write execute when you run the executable file. MASM contains an interpreter for a second language, the MASM compile-time language (CTL). MASM executes the CTL program during assembly (compilation). Once MASM completes assembly, the CTL program terminates.

  • The CTL application is not a part of the runtime executable that MASM emits, although the CTL application can write part of the runtime program for you. By learning how to use the MASM CTL and applying it properly, you can develop assembly language applications as rapidly as high-level language applications.

Compile-Time Expressions and Operators

Constants and variables

  • You declare compile-time constants by using the textequ or equ directives. You declare compile-time variables by using the "=" directive.

inc_by equ 1
ctlVar = 0
ctlVar = ctlVar + inc_by

The MASM Escape (!) Operator

  • The first operator is the ! operator. When placed in front of another symbol, this operator tells MASM to treat that character as text rather than as a special symbol.

The MASM Evaluation (%) Operator

  • The second useful CTL operator is %. The percent operator causes MASM to evaluate the expression following it and replace that expression with its value.

num10 = 10
text10 textequ <10>
tn11 textequ %num10 + 1

The catstr Directive

  • The catstr function has the following syntax:

identifier catstr string1, string2, ...

; example

helloWorld catstr <Hello>, <, >, <World!!>
  • The identifier is an (up to this point) undefined symbol. The string1 and string2 operands are textual data surrounded by < and > symbols. This statement stores the concatenation of the two strings into identifier.

The echo and .err Directives

; CTL "Hello World" program

            echo    Listing 13-1: Hello, World!
            end
  • The echo statement displays the textual representation of its argument list during the assembly of a MASM program. The above program will show -

Listing 13-1: Hello, world! 
  • %out is a synonym for echo (just in case you see %out in any MASM source files)

  • The .err directive, like echo, will display a string to the console during assembly, though this must be a text string (delimited by < and >). The .err statement displays the text as part of a MASM error diagnostic.

  • Furthermore, the .err statement increments the error count, and this will cause MASM to stop the assembly (without assembling or linking) after processing the current source file.

.err <Error message here>

The instr Directive

  • The instr directive searches for the presence of one string within another.

identifier instr start, source, search


; example

WorldPosn instr 1, <Hello World>, <World>
  • where identifier is a symbol into which MASM will put the offset of the search string within the source string. The search begins at position start within source. Unconventionally, the first character in source has the position 1 (not 0).

The sizestr Directive

  • The sizestr directive computes the length of a string

identifier sizestr string

; example

hwLen sizestr <Hello World>
  • where identifier is the symbol into which MASM will store the string’s length, and string is the string literal whose length this directive computes.

The substr Directive

  • The substr directive extracts a substring from a larger string

identifier substr source, start, len


; example

hString substr <Hello World>, 1, 5
  • where identifier is the symbol that MASM will create (type TEXT, initialized with the substring characters), source is the source string from which MASM will extract the substring, start is the starting position in the string to begin the extraction, and len is the length of the substring to extract.

  • The len operand is optional; if it is absent, MASM will assume you want to use the remainder of the string.

Conditional And Repetitive Assembly

Conditional Assembly

  • The simplest form of the MASM compile-time if statement uses the following syntax:

if constant_boolean_expression
        Text
endif 
  • The expression must be a constant expression that evaluates to an integer value.

  • The identifiers in a compile-time expression must all be constant identifiers or a MASM compile-time function call (with appropriate parameters). Because MASM evaluates these expressions at assembly time, they cannot contain runtime variables.

  • The MASM if statement supports optional elseif and else clauses that behave in an intuitive fashion. The complete syntax for the if statement looks like the following:

if constant_boolean_expression1
         Text
elseif constant_boolean_expression2
         Text
else
         Text
endif 

Repetitive Assembly

  • MASM’s while..endm, for..endm, and forc..endm statements provide compiletime loop constructs. The while statement tells MASM to process the same sequence of statements repetitively during assembly. This is handy for constructing data tables as well as providing a traditional looping structure for compile-time programs.

while constant_boolean_expression
        Text
endm 
  • To understand how it works, look at the program below

; CTL while loop demonstration program

        option  casemap:none

nl          =       10
           

            .data
ary         dword   2, 3, 5, 8, 13

            include print.inc
            
            .code

            
; Here is the "asmMain" function.

            public  asmMain
asmMain     proc
            push    rbx
            push    rbp
            mov     rbp, rsp
            sub     rsp, 56         ;Shadow storage

i           =       0            
            while   i LT 5  

            mov     edx, i          ;This is a constant!
            mov     r8d, ary[ i*4 ] ;Index is a constant
            call    print
            byte    "array[ %d ] = %d", nl, 0
              
i           =       i + 1
            endm 

             
allDone:    leave
            pop     rbx
            ret     ;Returns to caller
asmMain     endp
            end
  • MASM provides two forms of the for..endm loop. These two loops take the following general form:

for identifier, <arg1, arg2, ..., argn>
 .
 .
 .
endm

forc identifier, <string>
 .
 .
 .
endm 
  • The first form of the for loop (plain for) repeats the code once for each of the arguments specified between the < and > brackets. On each repetition of the loop, it sets identifier to the text of the current argument: on the first iteration of the loop, identifier is set to arg1, and on the second iteration it is set to arg2, and so on, until the last iteration, when it is set to argn.

  • The forc compile-time loop repeats the body of its loop for each character appearing in the string specified by the second argument.

Macros

Standard Macros

  • MASM supports a straightforward macro facility that lets you define macros in a manner that is similar to declaring a procedure. A typical, simple macro declaration takes the following form:

macro_name macro arguments
        Macro body
        endm
  • To execute the code associated with a macro, you specify the macro’s name at the point you want to execute these instructions.

mov rax, qword ptr i128
mov rdx, qword ptr i128[8]
; calling the macro
macro_name
  • The difference between the macro invocation versus the procedure call is that macros expand their text inline, whereas a procedure call emits a call to the corresponding procedure elsewhere in the text.

  • You should choose macro versus procedure call based on efficiency. Macros are slightly faster than procedure calls because you don’t execute the call and corresponding ret instructions, but they can make your program larger because a macro invocation expands to the text of the macro’s body on each invocation.

  • Macros have many other disadvantages over procedures. Macros cannot have local (automatic) variables, macro parameters work differently than procedure parameters, macros don’t support (runtime) recursion, and macros are a little more difficult to debug than procedures (just to name a few disadvantages). Therefore, you shouldn’t really use macros as a substitute for procedures except when performance is absolutely critical.

Macro Parameters

  • Macro parameter declaration syntax is straightforward. You supply a list of parameter names as the operands in a macro declaration:

neg128 macro reg64HO, reg64LO
        neg reg64HO
        neg reg64LO
        sbb reg64HO, 0
        end
  • When you invoke a macro, you supply the actual parameters as arguments to the macro invocation:

neg128 rdx, rax
  • A macro invocation of the form neg128 rdx, rax is equivalent to the following:

reg64HO textequ <rdx>
reg64LO textequ <rax>
        neg reg64HO
        neg reg64LO
        sbb reg64HO, 0
  • We use the < and > brackets to treat anything inside them as a single string.

chkError macro instr, jump, target

         instr
         jump target
         
         endm
         
         chkError <cmp eax, 0>, jnl, RangeError ; Example 1
         .
         .
         . 
  • When passing numeric parameters that may contain compile-time expressions, surround them in the macro with parentheses.

Echo2nTimes macro n, theStr
echoCnt = 0
        while echoCnt LT (n) * 2
  • If you don’t have control over the macro definition (perhaps it’s part of a library module you use, and you can’t change the macro definition because doing so could break existing code), there is another solution to this problem: use the MASM % operator before the argument in the macro invocation so that the CTL interpreter evaluates the expression before expanding the parameters. For example:

Echo2nTimes %3 + 1, "Hello"

Optional and Required Macro Parameters

  • As a general rule, MASM treats macro arguments as optional arguments. If you define a macro that specifies two arguments and invoke that argument with only one argument, MASM will not (normally) complain about the invocation. Instead, it will simply substitute the empty string for the expansion of the second argument.

  • However, suppose you left off the second parameter in the neg128 macro given earlier. That would compile to a neg instruction with a missing operand and MASM would report an error

neg128 macro arg1, arg2 ; Line 6
       
       neg arg1         ; Line 7
       neg arg2         ; Line 8
       sbb arg1, 0      ; Line 9
       endm             ; Line 10
                        ; Line 11
       neg128 rdx       ; Line 
  • MASM solves this issue by introducing several additional conditional if statements intended for use with text operands and macro arguments.

  • Example use of ifb:

neg128 macro reg64HO, reg64LO
        ifb <reg64LO>
        .err <neg128 requires 2 operands>
        endif
        neg reg64HO
        neg reg64LO
        sbb reg64HO, 0
        endm
  • The neg128 macro complete code:

; neg128 macro

        option  casemap:none

nl          =       10

            .const
           

neg128      macro reg64HO, reg64LO

            ifb   <reg64LO>
            .err "neg128 requires 2 operands"
            endif

            neg  reg64HO
            neg  reg64LO
            sbb  reg64HO, 0
            endm


            include print.inc
            
            .code
            
; Here is the "asmMain" function.

        
            public  asmMain
asmMain     proc
            push    rbx
            push    rbp
            mov     rbp, rsp
            sub     rsp, 56         ;Shadow storage


            mov     rdx, 12345678h
            mov     rax, 90123456h
            neg128  rdx, rax
            
             
allDone:    leave
            pop     rbx
            ret     ;Returns to caller
asmMain     endp
            end
  • A different way to handle missing macro arguments is to explicitly tell MASM that an argument is required with the :req suffix on the macro definition line.

neg128 macro reg64HO:req, reg64LO:req
        neg reg64HO
        neg reg64LO
        sbb reg64HO, 0
        endm

Default Macro Parameter Values

  • One way to handle missing macro arguments is to define default values for those arguments.

neg128 macro reg64HO:=<rdx>, reg64LO:=<rax>
        neg reg64HO
        neg reg64LO
        sbb reg64HO, 0
        endm
  • The ":=" operator tells MASM to substitute the text constant to the right of the operator for the associated macro argument if an actual value is not present on the macro invocation.

Macros with a Variable Number of Parameters

  • It is possible to tell MASM to allow a variable number of arguments in a macro invocation:

varParms macro varying:vararg
        Macro body
        
        endm
        .
        .
        .
        varParms 1
        varParms 1, 2
        varParms 1, 2, 3
        varParms 
  • A macro can have, at most, one vararg parameter. If a macro has more than one parameter and also has a vararg parameter, the vararg parameter must be the last argument.

The Macro Expansion (&) Operator

  • Inside a macro, you can use the & operator to replace a macro name (or other text symbol) with its actual value. This operator is active anywhere, even with string literals.

expand macro parm
        byte '&parm', 0
        endm

        .data
        expand a
  • If, for some reason, you need the string '&parm' to be emitted within a macro (that has parm as one of its parameters), you will have to work around the expansion operator.

expand macro parm
        byte '&', 'parm', 0
        endm

Local Symbols in a macro

  • Local macro symbols are unique to a specific invocation of a macro. You must explicitly tell MASM which symbols must be local by using the local directive:

macro_name macro optional_parameters
        local list_of_local_names
        Macro body
        endm
        
; example

jzc macro target
        local NotTarget
        
        jnz NotTarget
        jc target
NotTarget:
        
        endm 

The exitm Directive

  • The MASM exitm directive tells MASM to immediately terminate the processing of the macro. MASM will ignore any additional lines of text within the macro.

  • The exitm directive is useful in a conditional assembly sequence. Perhaps after checking for the presence (or absence) of certain macro arguments, you might want to stop processing the macro to avoid additional errors from MASM

neg128 macro reg64HO, reg64LO
        ifb <reg64LO>
        .err <neg128 requires 2 operands>
        exitm
        endif

        neg reg64HO
        neg reg64LO
        sbb reg64HO, 0
        endm

MASM Macro Function Syntax

  • Today, MASM supports additional syntax that allows you to create macro functions. A MASM macro function definition looks exactly like a normal macro definition with one addition: you use an exitm directive with a textual argument to return a function result from the macro.

; CTL while loop demonstration program

        option  casemap:none

nl          =       10           


; upperCase macro function.
;
; Converts text argument to a string, converting
; all lower-case characters to uppercase.

upperCase   macro   theString
            local   resultString, thisChar, sep
resultStr   equ     <> ;Initialize function result with ""
sep         textequ <> ;Initialize separator char with ""

            forc    curChar, theString
            
; Check to see if the character is lower case.
; Convert it to upper case if it is, otherwise
; output it to resultStr as-is. Concatenate the
; current character to the end of the result string
; (with a ", " separator, if this isn�t the first
; character appended to resultStr).

            if      ('&curChar' GE 'a') and ('&curChar' LE 'z')
resultStr   catstr  resultStr, sep, %'&curChar'-32
            else
resultStr   catstr  resultStr, sep, %'&curChar'
            endif
            
; First time through, sep is the empty string, for all
; other iterations, sep is the comma separator between
; values.

sep         textequ <, >    
            endm    ;End for
            
            exitm   <resultStr>
            endm    ;End macro
            

; Demonstratoin of the upperCase macro function
            
            .data
chars       byte    "Demonstration of upperCase "
            byte    "macro function:"
            byte    upperCase( <abcdEFG123> ), nl, 0
            
            .code
            externdef printf:proc      
            
; Here is the "asmMain" function.
        
            public  asmMain
asmMain     proc
            push    rbx
            push    rbp
            mov     rbp, rsp
            sub     rsp, 56         ;Shadow storage

            lea     rcx, chars
            call    printf
             
allDone:    leave
            pop     rbx
            ret     ;Returns to caller
asmMain     endp
            end
  • Whenever you invoke a MASM macro function, you must always follow the macro name with a pair of parentheses enclosing the macro’s arguments. Even if the macro has no arguments, an empty pair of parentheses must be present. This is how MASM differentiates standard macros and macro functions.

Writing Compile-Time “Programs”

  • The MASM compile-time language allows you to write short programs that write other programs—in particular, to automate the creation of large or complex assembly language sequences.

Constructing Data Tables at Compile Time

  • One common use for the compile-time language is to build ASCII character lookup tables for alphabetic case manipulation with the xlat instruction at runtime.

  • Note the use of a macro as a compiletime procedure to reduce the complexity of the table-generating code.

; Creating lookup tables with macros

        option  casemap:none

nl          =       10

            .const
fmtStr1     byte    "testString converted to UC:", nl
            byte    "%s", nl, 0
            
fmtStr2     byte    "testString converted to LC:", nl
            byte    "%s", nl, 0
            

testString  byte    "This is a test string ", nl
            byte    "Containing UPPER CASE ", nl
            byte    "and lower case chars", nl, 0
           

emitChRange macro   start, last
            local   index, resultStr
index       =       start
            while   index lt last
            byte    index
index       =       index + 1
            endm
            endm

; Lookup table that will convert lowercase
; characters to uppercase. The byte at each
; index contains the value of that index,
; except for the bytes at indexes 'a'..'z'.
; Those bytes contain the values 'A'..'Z'.
; Therefore, if a program uses an ASCII
; character's numeric value as an index
; into this table and retrieves that byte,
; it will convert the character to upper
; case.

lcToUC      equ             this byte
            emitChRange     0, 'a'
            emitChRange     'A', %'Z'+1
            emitChRange     %'z'+1, 0ffh

; As above, but this table converts upper
; case to lower case characters.
            
UCTolc      equ             this byte
            emitChRange     0, 'A'
            emitChRange     'a', %'z'+1
            emitChRange     %'Z'+1, 0ffh

            
            .data

; Store the destination strings here:

toUC        byte    256 dup (0)
TOlc        byte    256 dup (0)     

            
            .code
            externdef printf:proc  
            
; Here is the "asmMain" function.

        
            public  asmMain
asmMain     proc
            push    rbx
            push    rdi
            push    rsi
            push    rbp
            mov     rbp, rsp
            sub     rsp, 56         ;Shadow storage
            
; Convert the characters in testString to Uppercase

            lea     rbx, lcToUC
            lea     rsi, testString
            lea     rdi, toUC
            jmp     getUC
            
toUCLp:     xlat
            mov     [rdi], al
            inc     rsi
            inc     rdi
getUC:      mov     al, [rsi]
            cmp     al, 0
            jne     toUCLp
            
; Display the converted string

            lea     rcx, fmtStr1
            lea     rdx, toUC
            call    printf
            
                    
; Convert the characters in testString to lowercase

            lea     rbx, UCTolc
            lea     rsi, testString
            lea     rdi, TOlc
            jmp     getLC
            
toLCLp:     xlat
            mov     [rdi], al
            inc     rsi
            inc     rdi
getLC:      mov     al, [rsi]
            cmp     al, 0
            jne     toLCLp
            
; Display the converted string

            lea     rcx, fmtStr2
            lea     rdx, TOlc
            call    printf
            
       
allDone:    leave
            pop     rsi
            pop     rdi
            pop     rbx
            ret     ;Returns to caller
asmMain     endp
            end

Unrolling Loops

  • With a small amount of extra typing plus one copy of the loop body, you can unroll a loop as many times as you please. If you simply want to repeat the same code sequence a certain number of times, unrolling the code is especially trivial. All you have to do is wrap a MASM while..endm loop around the sequence and count off the specified number of iterations.

  • For example, if you wanted to print Hello World 10 times, you could encode this as follows:

count = 0
while count LT 10
      call print
      byte "Hello World", nl, 0

count = count + 1
endm

Using Macros to Write Macros

  • One advanced use of macros is to have a macro invocation create one or more new macros. If you nest a macro declaration inside another macro, invoking that (enclosing) macro will expand the enclosed macro definition and define that macro at that point.

  • Below is an example of a macro writing a macro to initialize a compile-time array

        option  casemap:none

genArray    macro   arrayName, elements
            local   index, eleName, getName
            
; Loop over each element of the array:

index       =       0
            while   index lt &elements
            
; Generate a textequ statement to define a single
; element of the array, e.g.,
;
;  aryXX = 0
;
; where "XX" is the index (0..(elements-1))

eleName     catstr  <&arrayName>,%index,< = 0>

; Expand the text just created with the catstr directive

            eleName
            
; Move on to next array index:

index       =       index + 1
            endm    ;while
            
; Create a macro function to retrieve a value from
; the array:

getName     catstr  <&arrayName>,<_get>

getName     macro   theIndex
            local   element
element     catstr  <&arrayName>,%theIndex
            exitm   <element>
            endm
            
; Create a macro to assign a value to
; an array element


setName     catstr  <&arrayName>,<_set>

setName     macro   theIndex, theValue
            local   assign
assign      catstr  <&arrayName>, %theIndex, < = >, %theValue
            assign
            endm

            endm    ;genArray

; mout-
;
;  Replacement for echo. Allows "%" operator
; in operand field to expand text symbols.

mout        macro   valToPrint
            local   cmd
cmd         catstr  <echo >, <valToPrint>
            cmd
            endm
            
	
; Create an array ("ary") with ten elements:

            genArray ary, 10

            
; Initialize each element of the array to
; its index value:

index	= 0
	while	index lt 10
	ary_set	index, index
index	=	index + 1
	endm
	
; Print out the array values:

index	= 	0
	while	index lt 10
	
value	=	ary_get(index)
	mout	ary[%index] = %value
index	=	index + 1
	endm
	
            end

Simulating HLL Procedure Calls

  • Macros provide a good mechanism to call procedures and functions in a high-level-like manner.

HLL-Like Calls with No Parameters

  • Of course, the most trivial example is a call to an assembly language procedure that has no arguments at all:

someProc macro
          call _someProc
          endm

_someProc proc
           .
           .
           .
_someProc endp
            .
            .
            .
           someProc ; Call the procedure
  • This simple example demonstrates a couple of conventions used for calling procedures via macro invocation:

    • If the procedure and all calls to the procedure occur within the same source file, place the macro definition immediately before the procedure to make it easy to find.

    • If you would normally name the procedure someProc, change the procedure’s name to _someProc and then use someProc as the macro name.

HLL-Like Calls with One or More Parameter

  • Assuming you’re using the Microsoft ABI and passing the parameter in RCX, the simplest solution is something like the following:

someProc macro parm1
         mov rcx, parm1
         call _someProc
         endm
         .
         .
         .
         someProc Parm1Value
  • This macro works well if you’re passing a 64-bit integer by value. If the parameter is an 8-, 16-, or 32-bit value, you would swap CL, CX, or ECX for RCX in the mov instruction.

  • If you’re passing the first argument by reference, you would swap an lea instruction for the mov instruction in this example. As reference parameters are always 64-bit values, the lea instruction would usually take this form:

lea rcx, parm1
  • Finally, if you’re passing a real4 or real8 value as the parameter, you’d swap one of the following instructions for the mov instruction in the previous macro:

movss xmm0, parm1 ; Use this for real4 parameters
movsd xmm0, parm1 ; Use this for real8 parameters
  • Expanding the macro-calling mechanism from one parameter to two or more (assuming a fixed number of parameters) is fairly easy. All you need to do is add more formal parameters and handle those arguments in your macro definition.

  • Below code uses macro invocations with multiple for calls to r10ToStr, e10ToStr, and some fixed calls to printf.

HLL-Like Calls With Multiple Parameters
; Floating-point to string conversion

        option  casemap:none

nl          =       10

            .const
fmtStr1     byte    "r10ToStr: value='%s'", nl, 0
fmtStr2     byte    "fpError: code=%I64d", nl, 0
fmtStr3     byte    "e10ToStr: value='%s'", nl, 0

r10_1       real10  1.2345678901234567
r10_2       real10  0.0000000000000001
r10_3       real10  12345678901234567.0
r10_4       real10  1234567890.1234567
r10_5       real10  994999999999999999.0

e10_1       real10  1.2345678901234567e123
e10_2       real10  1.2345678901234567e-123
e10_3       real10  1.2345678901234567e1
e10_4       real10  1.2345678901234567e-1
e10_5       real10  1.2345678901234567e10
e10_6       real10  1.2345678901234567e-10
e10_7       real10  1.2345678901234567e100
e10_8       real10  1.2345678901234567e-100
e10_9       real10  1.2345678901234567e1000
e10_0       real10  1.2345678901234567e-1000

            .data
r10str_1    byte    32 dup (0)

           
            align   4

; TenTo17 - Holds the value 1.0e+17. Used to get a floating 
;           point number to the range x.xxxxxxxxxxxxe+17

TenTo17     real10  1.0e+17
            
; PotTblN- Hold powers of ten raised to negative powers of two.
            
PotTblN     real10  1.0,
                    1.0e-1,
                    1.0e-2,
                    1.0e-4,
                    1.0e-8,
                    1.0e-16,
                    1.0e-32,
                    1.0e-64,
                    1.0e-128,
                    1.0e-256,
                    1.0e-512,
                    1.0e-1024,
                    1.0e-2048,
                    1.0e-4096                               
                                    
                                            
; PotTblP- Hold powers of ten raised to positive powers of two.
            
            align   4
PotTblP     real10  1.0,
                    1.0e+1,
                    1.0e+2,
                    1.0e+4,
                    1.0e+8,
                    1.0e+16,
                    1.0e+32,
                    1.0e+64,
                    1.0e+128,
                    1.0e+256,
                    1.0e+512,
                    1.0e+1024,
                    1.0e+2048,
                    1.0e+4096
                                    
; ExpTbl- Integer equivalents to the powers in the tables 
;         above.
            
            align   4
ExpTab      dword   0,
                    1,
                    2,
                    4,
                    8,
                    16,
                    32,
                    64,
                    128,
                    256,
                    512,
                    1024,
                    2048,
                    4096
            
	include	print.inc
            
            .code
;*************************************************************
;
; expToBuf-
;
;  Unsigned integer to buffer.
; Used to output up to 4-digit exponents.
;
; Inputs:
;
;    EAX:   Unsigned integer to convert
;    ECX:   Print width 1-4
;    RDI:   Points at buffer.
;

expToBuf    proc

expWidth    equ     <[rbp+16]>
exp         equ     <[rbp+8]>
bcd         equ     <[rbp-16]>

            push    rdx
            push    rcx     ;At [RBP+16]
            push    rax     ;At [RBP+8]
            push    rbp
            mov     rbp, rsp
            sub     rsp, 16

; Verify exponent digit count is in the range 1-4:

            cmp     rcx, 1
            jb      badExp
            cmp     rcx, 4
            ja      badExp
            mov     rdx, rcx
            
; Verify the actual exponent will fit in the number of digits:

            cmp     rcx, 2
            jb      oneDigit
            je      twoDigits
            cmp     rcx, 3
            ja      fillZeros       ;4 digits, no error
            cmp     eax, 1000
            jae     badExp
            jmp     fillZeros
            
oneDigit:   cmp     eax, 10
            jae     badExp
            jmp     fillZeros
            
twoDigits:  cmp     eax, 100
            jae     badExp
            
            
; Fill in zeros for exponent:

fillZeros:  mov     byte ptr [rdi+rcx*1-1], '0'
            dec     ecx
            jnz     fillZeros
            
; Point RDI at the end of the buffer:

            lea     rdi, [rdi+rdx*1-1]
            mov     byte ptr [rdi+1], 0
            push    rdi                 ;Save pointer to end

; Quick test for zero to handle that special case:

            test    eax, eax
            jz      allDone
            
; The number to convert is non-zero.
; Use BCD load and store to convert
; the integer to BCD:

            fild    dword ptr exp   ;Get integer value
            fbstp   tbyte ptr bcd   ;Convert to BCD
            
; Begin by skipping over leading zeros in
; the BCD value (max 10 digits, so the most
; significant digit will be in the HO nibble
; of byte 4).

            mov     eax, bcd        ;Get exponent digits
            mov     ecx, expWidth   ;Number of total digits
            
OutputExp:  mov     dl, al
            and     dl, 0fh
            or      dl, '0'
            mov     [rdi], dl
            dec     rdi
            shr     ax, 4
            jnz     OutputExp


; Zero-terminte the string and return:
            
allDone:    pop     rdi
            leave
            pop     rax
            pop     rcx
            pop     rdx
            clc
            ret
            
badExp:     leave
            pop     rax
            pop     rcx
            pop     rdx
            mov     rax, -3
            stc
            ret
            
expToBuf    endp


;*************************************************************
;                                                                  
; FPDigits-                                                        
;                                                                  
; Used to convert a floating point number on the FPU 
; stack (ST(0)) to a string of digits.                                           
;                                                                  
; Entry Conditions:                                                
;                                                                  
; ST(0)-    80-bit number to convert.                              
; RDI-      Points at array of at least 18 bytes where FPDigits    
;           stores the output string.                      
;                                                                  
; Exit Conditions:                                                 
;                                                                  
; RDI-      Converted digits are found here.                       
; RAX-      Contains exponent of the number.                       
; CL-       Contains the sign of the mantissa (" " or "-").
;                                                                  
;*************************************************************

P10TblN     equ     <real10 ptr [r8]>
P10TblP     equ     <real10 ptr [r9]>
xTab        equ     <dword ptr [r10]>

FPDigits    proc
            push    r8
            push    r9
            push    r10

; Special case if the number is zero.
   
            ftst
            fstsw   ax
            sahf
            jnz     fpdNotZero

; The number is zero, output it as a special case.

            fstp    tbyte ptr [rdi]  ;Pop value off FPU stack.
            mov     rax, "00000000"
            mov     [rdi], rax 
            mov     [rdi+8], rax 
            mov     [rdi+16], ax
            add     rdi, 18 
            xor     edx, edx         ; Return an exponent of 0.
            mov     cl, ' '          ; Sign is positive.
            jmp     fpdDone
                    
fpdNotZero:
            
; If the number is not zero, then fix the sign of the value.
            
            mov     cl, ' '      ; Assume it's positive.
            jbe     WasPositive  ; Flags set from sahf above.
            
            fabs             ; Deal only with positive numbers.
            mov     cl, '-'  ; Set the sign return result.
                    
WasPositive:

; Get the number between one and ten so we can figure out 
; what the exponent is.  Begin by checking to see if we have 
; a positive or negative exponent.
            
            
            xor     edx, edx        ; Initialize exponent to 0.
            fld1
            fcomip  st(0), st(1)
            jbe     PosExp

; We've got a value between zero and one, exclusive, 
; at this point.  That means this number has a negative 
; exponent.  Multiply the number by an appropriate power
; of ten until we get it in the range 1..10.
                    
            mov     esi, sizeof PotTblN     ; After last element.
            mov     ecx, sizeof ExpTab      ; Ditto.
            lea     r8, PotTblN
            lea     r9, PotTblP
            lea     r10, ExpTab

CmpNegExp:
            sub     esi, 10          ; Move to previous element.
            sub     ecx, 4           ; Zeros HO bytes
            jz      test1

            fld     P10TblN[ rsi*1 ] ; Get current power of 10.
            fcomip  st(0), st(1)     ; Compare against NOS.
            jbe     CmpNegExp        ;While Table >= value.

            mov     eax, xTab[ rcx*1 ]
            test    eax, eax
            jz      didAllDigits

            sub     edx, eax
            fld     P10TblP[ rsi*1 ]
            fmulp
            jmp     CmpNegExp

; If the remainder is *exactly* 1.0, then we can branch
; on to InRange1_10, otherwise, we still have to multiply
; by 10.0 because we've overshot the mark a bit.

test1:
            fld1
            fcomip  st(0), st(1)
            je      InRange1_10

didAllDigits:
                            
; If we get to this point, then we've indexed through
; all the elements in the PotTblN and it's time to stop.

            fld     P10TblP[ 10 ]   ; 10.0
            fmulp
            dec     edx
            jmp     InRange1_10
                         
;  At this point, we've got a number that is one or greater.
;  Once again, our task is to get the value between 1 and 10.
            
PosExp:
            
            mov     esi, sizeof PotTblP ; After last element.
            mov     ecx, sizeof ExpTab  ; Ditto.
            lea     r9, PotTblP
            lea     r10, ExpTab

CmpPosExp:
            sub     esi, 10         ; Move back 1 element in
            sub     ecx, 4          ;  PotTblP and ExpTbl.
            fld     P10TblP[ rsi*1 ]
            fcomip  st(0), st(1)
            ja      CmpPosExp;
            mov     eax, xTab[ rcx*1 ]
            test    eax, eax
            jz      InRange1_10
            
            add     edx, eax
            fld     P10TblP[ rsi*1 ]
            fdivp
            jmp     CmpPosExp
                    
                            
InRange1_10:

; Okay, at this point the number is in the range 1 <= x < 10,
; Let's multiply it by 1e+18 to put the most significant digit
; into the 18th print position.  Then convert the result to
; a BCD value and store away in memory.

            
            sub     rsp, 24         ; Make room for BCD result.
            fld     TenTo17
            fmulp
            
; We need to check the floating-point result to make sure it
; is not outside the range we can legally convert to a BCD 
; value.
;
; Illegal values will be in the range:
;
;  >999,999,999,999,999,999 ..<1,000,000,000,000,000,000
;      $403a_de0b_6b3a_763f_ff01..$403a_de0b_6b3a_763f_ffff
;
; Should one of these values appear, round the result up to
;
;           $403a_de0b_6b3a_7640_0000
            
            fstp    real10 ptr [rsp]
            cmp     word ptr [rsp+8], 403ah
            jne     noRounding
            
            cmp     dword ptr [rsp+4], 0de0b6b3ah
            jne     noRounding
                    
            mov     eax, [rsp]
            cmp     eax, 763fff01h
            jb      noRounding;
            cmp     eax, 76400000h
            jae     TooBig
                            
            fld     TenTo17
            inc     edx     ;Inc exp as this is really 10^18. 
            jmp     didRound
                                    
; If we get down here, there was some problems getting the
; value in the range 1 <= x <= 10 above and we've got a value
; that is 10e+18 or slightly larger. We need to compensate for
; that here.

TooBig:
            lea     r9, PotTblP
            fld     real10 ptr [rsp]
            fld     P10TblP[ 10 ]   ; /10
            fdivp
            inc     edx             ; Adjust exp due to fdiv.
            jmp     didRound
                            
                                    
noRounding:
            fld     real10 ptr [rsp]
didRound:   
            fbstp   tbyte ptr [rsp]

                        
; The data on the stack contains 18 BCD digits.  Convert these
; to ASCII characters and store them at the destination location
; pointed at by edi.
            
            mov     ecx, 8
repeatLp:
            mov     al, byte ptr [rsp+rcx]
            shr     al, 4                   ;Always in the
            or      al, '0'                 ; range 0..9
            mov     [rdi], al
            inc     rdi
            
            mov     al, byte ptr [rsp+rcx]
            and     al, 0fh
            or      al, '0'
            mov     [rdi], al
            inc     rdi
            
            dec     ecx     
            jns     repeatLp

            add     rsp, 24         ; Remove BCD data from stack.

fpdDone:

            mov     eax, edx        ; Return exponent in EAX.
            pop     r10
            pop     r9
            pop     r8
            ret
                    
                    
FPDigits    endp

     
;***********************************************************
;                                                           
; _r10ToStr-                                                 
;                                                           
; Converts a REAL10 floating-point number to the       
; corresponding string of digits.  Note that this           
; function always emits the string using decimal            
; notation.  For scientific notation, use the e10ToBuf      
; routine.                                                  
;                                                           
; On Entry:                                                 
;                                                           
; r10-              Real10 value to convert.
;                   Passed in ST(0).                       
;                                                           
; fWidth-           Field width for the number (note that this   
;                   is an *exact* field width, not a minimum         
;                   field width).
;                   Passed in EAX (RAX).                                    
;                                                           
; decimalpts-       # of digits to display after the decimal pt.
;                   Passed in EDX (RDX). 
;                                                           
; fill-             Padding character if the number is smaller   
;                   than the specified field width.
;                   Passed in CL (RCX).                  
;                                                                            
; buffer-           _r10ToStr stores the resulting characters in  
;                   this string.
;                   Address passed in RDI.
;
; maxLength-        Maximum string length.
;                   Passed in R8d (R8).                                     
;                                                                            
; On Exit:                                                  
;                                                           
; Buffer contains the newly formatted string.  If the       
; formatted value does not fit in the width specified,      
; _r10ToStr will store "#" characters into this string.      
;                                                           
; Carry-    Clear if success, set if an exception occurs.                                                         
;           If width is larger than the maximum length of          
;           the string specified by buffer, this routine        
;           will return with the carry set and RAX=-1.                                             
;                                                           
;***********************************************************


_r10ToStr    proc


; Local variables:

fWidth      equ     <dword ptr [rbp-8]>     ;RAX: uns32
decDigits   equ     <dword ptr [rbp-16]>    ;RDX: uns32
fill        equ     <[rbp-24]>              ;CL: char
bufPtr      equ     <[rbp-32]>              ;RDI: pointer
exponent    equ     <dword ptr [rbp-40]>    ;uns32
sign        equ     <byte ptr [rbp-48]>     ;char
digits      equ     <byte ptr [rbp-128]>    ;char[80]

            push    rdi
            push    rbx
            push    rcx
            push    rdx
            push    rsi
            push    rax
            push    rbp
            mov     rbp, rsp
            sub     rsp, 128        ;128 bytes of local vars

; First, make sure the number will fit into the 
; specified string.
            
            cmp     eax, r8d 
            jae     strOverflow
            
            test    eax, eax
            jz      voor

            mov     bufPtr, rdi
            mov     qword ptr decDigits, rdx
            mov     fill, rcx
            mov     qword ptr fWidth, rax
            
;  If the width is zero, raise an exception:

            test    eax, eax
            jz      voor
            
; If the width is too big, raise an exception:

            cmp     eax, fWidth
            ja      badWidth        

; Okay, do the conversion. 
; Begin by processing the mantissa digits:
                    
            lea     rdi, digits     ; Store result here.
            call    FPDigits        ; Convert r80 to string.
            mov     exponent, eax   ; Save away exp result.
            mov     sign, cl        ; Save mantissa sign char.

; Round the string of digits to the number of significant 
; digits we want to display for this number:

            cmp     eax, 17
            jl      dontForceWidthZero

            xor     rax, rax        ; If the exp is negative, or
                                    ; too large, set width to 0.
dontForceWidthZero:
            mov     rbx, rax        ; Really just 8 bits.
            add     ebx, decDigits  ; Compute rounding position.
            cmp     ebx, 17
            jge     dontRound       ; Don't bother if a big #.


; To round the value to the number of significant digits,
; go to the digit just beyond the last one we are considering
; (eax currently contains the number of decimal positions)
; and add 5 to that digit.  Propagate any overflow into the
; remaining digit positions.
                    
                    
            inc     ebx           ; Index+1 of last sig digit.
            mov     al, digits[rbx*1] ; Get that digit.
            add     al, 5             ; Round (e.g., +0.5 ).
            cmp     al, '9'
            jbe     dontRound

            mov     digits[ rbx*1 ], '0'+10 ; Force to zero
whileDigitGT9:                              ; (see sub 10 below).
            sub     digits[ rbx*1 ], 10     ; Sub out overflow, 
            dec     ebx                     ; carry, into prev
            js      hitFirstDigit;          ; digit (until 1st
                                            ;  digit in the #).
            inc     digits[rbx*1]
            cmp     digits[rbx], '9'        ; Overflow if > '9'.
            ja      whileDigitGT9
            jmp     dontRound
            
                                    
hitFirstDigit:
                                            
; If we get to this point, then we've hit the first
; digit in the number.  So we've got to shift all
; the characters down one position in the string of
; bytes and put a "1" in the first character position.
            
            mov     ebx, 17
repeatUntilEBXeq0:
            
            mov     al, digits[rbx*1]
            mov     digits[rbx*1+1], al
            dec     ebx     
            jnz     repeatUntilEBXeq0
                    
            mov     digits, '1'
            inc     exponent    ; Because we added a digit.
                    
dontRound: 
                    
            
; Handle positive and negative exponents separately.

            mov     rdi, bufPtr ; Store the output here.
            cmp     exponent, 0
            jge     positiveExponent

; Negative exponents:
; Handle values between 0 & 1.0 here (negative exponents
; imply negative powers of ten).
;
; Compute the number's width.  Since this value is between
; 0 & 1, the width calculation is easy: it's just the
; number of decimal positions they've specified plus three
; (since we need to allow room for a leading "-0.").
                    
            
            mov     ecx, decDigits
            add     ecx, 3
            cmp     ecx, 4
            jae     minimumWidthIs4

            mov     ecx, 4  ; Minimum possible width is four.

minimumWidthIs4:
            cmp     ecx, fWidth
            ja      widthTooBig 
            
; This number will fit in the specified field width,
; so output any necessary leading pad characters.
            
            mov     al, fill
            mov     edx, fWidth
            sub     edx, ecx
            jmp     testWhileECXltWidth
            
            
whileECXltWidth:
            mov     [rdi], al
            inc     rdi
            inc     ecx
testWhileECXltWidth:
            cmp     ecx, fWidth
            jb      whileECXltWidth
                            
; Output " 0." or "-0.", depending on the sign of the number.
            
            mov     al, sign
            cmp     al, '-'
            je      isMinus
                    
            mov     al, ' '
            
isMinus:    mov     [rdi], al
            inc     rdi
            inc     edx
                    
            mov     word ptr [rdi], '.0'
            add     rdi, 2
            add     edx, 2
            
; Now output the digits after the decimal point:

            xor     ecx, ecx        ; Count the digits in ecx.
            lea     rbx, digits     ; Pointer to data to output.
                                    
; If the exponent is currently negative, or if
; we've output more than 18 significant digits,
; just output a zero character.
            
repeatUntilEDXgeWidth: 
            mov     al, '0'
            inc     exponent
            js      noMoreOutput
            
            cmp     ecx, 18
            jge     noMoreOutput
            
            mov     al, [rbx]
            inc     ebx
                    
noMoreOutput:
            mov     [rdi], al
            inc     rdi
            inc     ecx
            inc     edx
            cmp     edx, fWidth
            jb      repeatUntilEDXgeWidth
            jmp     r10BufDone


; If the number's actual width was bigger than the width
; specified by the caller, emit a sequence of '#' characters
; to denote the error.
                            
widthTooBig:
            

; The number won't fit in the specified field width,
; so fill the string with the "#" character to indicate
; an error.
                    
                    
            mov     ecx, fWidth
            mov     al, '#'
fillPound:  mov     [rdi], al
            inc     rdi
            dec     ecx
            jnz     fillPound
            jmp     r10BufDone

            
; Handle numbers with a positive exponent here.

positiveExponent:
            
; Compute # of digits to the left of the ".".
; This is given by:
;
;                   Exponent     ; # of digits to left of "."
;           +       2            ; Allow for sign and there
;                                ; is always 1 digit left of "."
;           +       decimalpts   ; Add in digits right of "."
;           +       1            ; If there is a decimal point.
            

            mov     edx, exponent   ; Digits to left of "."
            add     edx, 2          ; 1 digit + sign posn.
            cmp     decDigits, 0
            je      decPtsIs0

            add     edx, decDigits  ; Digits to right of "."
            inc     edx             ; Make room for the "."
            
decPtsIs0:
            
; Make sure the result will fit in the
; specified field width.
            
            cmp     edx, fWidth
            ja      widthTooBig
            
                    
; If the actual number of print positions
; is less than the specified field width,
; output leading pad characters here.
            
            cmp     edx, fWidth
            jae     noFillChars
            
            mov     ecx, fWidth
            sub     ecx, edx
            jz      noFillChars
            mov     al, fill
fillChars:  mov     [rdi], al
            inc     rdi
            dec     ecx
            jnz     fillChars
                    
noFillChars:
            
            
; Output the sign character.
            
            mov     al, sign
            cmp     al, '-'
            je      outputMinus;
            
            mov     al, ' '
                    
outputMinus:
            mov     [rdi], al
            inc     rdi
                    
; Okay, output the digits for the number here.
            
            
            xor     ecx, ecx        ; Counts  # of output chars.
            lea     rbx, digits     ; Ptr to digits to output.
            
            
; Calculate the number of digits to output
; before and after the decimal point.
            
            
            mov     edx, decDigits  ; Chars after "."
            add     edx, exponent   ; # chars before "."
            inc     edx             ; Always one digit before "."
            
                    
; If we've output fewer than 18 digits, go ahead
; and output the next digit.  Beyond 18 digits,
; output zeros.
            
repeatUntilEDXeq0:
            mov     al, '0'
            cmp     ecx, 18
            jnb     putChar
            
            mov     al, [rbx]
            inc     rbx

putChar:    mov     [rdi], al
            inc     rdi     
            
; If the exponent decrements down to zero,
; then output a decimal point.
            
            cmp     exponent, 0
            jne     noDecimalPt
            cmp     decDigits, 0
            je      noDecimalPt
            
            mov     al, '.'
            mov     [rdi], al
            inc     rdi
                    
noDecimalPt:
            dec     exponent      ; Count down to "." output.
            inc     ecx           ; # of digits thus far.
            dec     edx           ; Total # of digits to output.
            jnz     repeatUntilEDXeq0
                    

; Zero-terminate string and leave:
            
r10BufDone: mov     byte ptr [rdi], 0
            leave
            clc     ;No error
            jmp     popRet

badWidth:   mov     rax, -2 ;Illegal character
            jmp     ErrorExit
            
strOverflow:
            mov     rax, -3 ;String overflow
            jmp     ErrorExit

voor:       or      rax, -1 ;Range error
ErrorExit:  leave
            stc     ;Error
            mov     [rsp], rax      ;Change RAX on return
            
popRet:     pop     rax
            pop     rsi
            pop     rdx
            pop     rcx
            pop     rbx
            pop     rdi
            ret

_r10ToStr    endp



;***********************************************************
;                                                           
; _e10ToStr-                                                   
;                                                           
; Converts a REAL10 floating-point number to the       
; corresponding string of digits.  Note that this           
; function always emits the string using scientific                  
; notation, use the _r10ToStr routine for decimal notation.   
;                                                           
; On Entry:                                                 
;                                                           
;    e10-           Real10 value to convert.
;                   Passed in ST(0)                     
;                                                           
;    width-         Field width for the number (note that this   
;                   is an *exact* field width, not a minimum     
;                   field width).
;                   Passed in RAX (LO 32 bits).                                
;                                                           
;    fill-          Padding character if the number is smaller   
;                   than the specified field width.
;                   Passed in RCX.                  
;                                                                            
;    buffer-        _e10ToStr stores the resulting characters in  
;                   this buffer (passed in EDI).
;                   Passed in RDI (LO 32 bits).                 
;                                                           
;    expDigs-       Number of exponent digits (2 for real4,     
;                   3 for real8, and 4 for real10).
;                   Passed in RDX (LO 8 bits)             
;                                                                            
;
;    maxLength-     Maximum buffer size.
;                   Passed in R8.                                     
; On Exit:                                                  
;                                                           
;    Buffer contains the newly formatted string.  If the    
;    formatted value does not fit in the width specified,   
;    _e10ToStr will store "#" characters into this string.   
;                                                           
;-----------------------------------------------------------
;                                                           
; Unlike the integer to string conversions, this routine    
; always right justifies the number in the specified        
; string.  Width must be a positive number, negative        
; values are illegal (actually, they are treated as         
; *really* big positive numbers which will always raise     
; a string overflow exception.                              
;                                                           
;***********************************************************

_e10ToStr    proc

fWidth      equ     <[rbp-8]>       ;RAX
buffer      equ     <[rbp-16]>      ;RDI
expDigs     equ     <[rbp-24]>      ;RDX
rbxSave     equ     <[rbp-32]>
rcxSave     equ     <[rbp-40]>
rsiSave     equ     <[rbp-48]>
Exponent    equ     <dword ptr [rbp-52]>
MantSize    equ     <dword ptr [rbp-56]>
Sign        equ     <byte ptr [rbp-60]>
Digits      equ     <byte ptr [rbp-128]>

            push    rbp
            mov     rbp, rsp
            sub     rsp, 128
            
            cmp     eax, r8d
            jae     strOvfl
            mov     byte ptr [rdi+rax*1], 0 ; 0-terminate str
            
            
            mov     buffer, rdi
            mov     rsiSave, rsi
            mov     rcxSave, rcx
            mov     rbxSave, rbx
            mov     fWidth, rax
            mov     expDigs, rdx
            
; First, make sure the width isn't zero.
            
            test    eax, eax
            jz      voor

; Just to be on the safe side, don't allow widths greater 
; than 1024:

            cmp     eax, 1024
            ja      badWidth

; Okay, do the conversion.

            lea     rdi, Digits     ; Store result string here.
            call    FPDigits        ; Convert e80 to digit str.
            mov     Exponent, eax   ; Save away exponent result.
            mov     Sign, cl        ; Save mantissa sign char.

; Verify that there is sufficient room for the mantissa's sign,
; the decimal point, two mantissa digits, the "E", 
; and the exponent's sign.  Also add in the number of digits
; required by the exponent (2 for real4, 3 for real8, 4 for 
; real10).
;
; -1.2e+00    :real4
; -1.2e+000   :real8
; -1.2e+0000  :real10
            
            
            mov     ecx, 6          ; Char posns for above chars.
            add     ecx, expDigs    ; # of digits for the exp.
            cmp     ecx, fWidth
            jbe     goodWidth
            
; Output a sequence of "#...#" chars (to the specified width)
; if the width value is not large enough to hold the 
; conversion:

            mov     ecx, fWidth
            mov     al, '#'
            mov     rdi, buffer
fillPound:  mov     [rdi], al
            inc     rdi
            dec     ecx
            jnz     fillPound
            jmp     exit_eToBuf


; Okay, the width is sufficient to hold the number, do the
; conversion and output the string here:

goodWidth:
            
            mov     ebx, fWidth     ; Compute the # of mantissa
            sub     ebx, ecx        ; digits to display.
            add     ebx, 2          ; ECX allows for 2 mant digs.
            mov     MantSize,ebx
                    
            
; Round the number to the specified number of print positions.
; (Note: since there are a maximum of 18 significant digits,
;  don't bother with the rounding if the field width is greater
;  than 18 digits.)
            
            
            cmp     ebx, 18
            jae     noNeedToRound
                    
; To round the value to the number of significant digits,
; go to the digit just beyond the last one we are considering
; (ebx currently contains the number of decimal positions)
; and add 5 to that digit.  Propagate any overflow into the
; remaining digit positions.
            
            mov     al, Digits[rbx*1] ; Get least sig digit + 1.
            add     al, 5             ; Round (e.g., +0.5 ).
            cmp     al, '9'
            jbe     noNeedToRound
            mov     Digits[rbx*1], '9'+1
            jmp     whileDigitGT9Test
whileDigitGT9:                      

; Subtract out overflow and add the carry into the previous
; digit (unless we hit the first digit in the number).

            sub     Digits[ rbx*1 ], 10     
            dec     ebx                     
            cmp     ebx, 0                  
            jl      firstDigitInNumber      
                                                                    
            inc     Digits[rbx*1]
            jmp     whileDigitGT9Test

firstDigitInNumber:

; If we get to this point, then we've hit the first
; digit in the number.  So we've got to shift all
; the characters down one position in the string of
; bytes and put a "1" in the first character position.
            
            mov     ebx, 17
repeatUntilEBXeq0:
            
            mov     al, Digits[rbx*1]
            mov     Digits[rbx*1+1], al
            dec     ebx
            jnz     repeatUntilEBXeq0
                    
            mov     Digits, '1'
            inc     Exponent         ; Because we added a digit.
            jmp     noNeedToRound
            
                    
whileDigitGT9Test:
            cmp     Digits[rbx], '9' ; Overflow if char > '9'.
            ja      whileDigitGT9 
            
noNeedToRound:      
            
; Okay, emit the string at this point.  This is pretty easy
; since all we really need to do is copy data from the
; digits array and add an exponent (plus a few other simple chars).
            
            xor     ecx, ecx    ; Count output mantissa digits.
            mov     rdi, buffer
            xor     edx, edx    ; Count output chars.
            mov     al, Sign
            cmp     al, '-'
            je      noMinus
            
            mov     al, ' '
                    
noMinus:    mov     [rdi], al
            
; Output the first character and a following decimal point
; if there are more than two mantissa digits to output.
            
            mov     al, Digits
            mov     [rdi+1], al
            add     rdi, 2
            add     edx, 2
            inc     ecx
            cmp     ecx, MantSize
            je      noDecPt
            
            mov     al, '.'
            mov     [rdi], al
            inc     rdi
            inc     edx     
                                    
noDecPt:
            
; Output any remaining mantissa digits here.
; Note that if the caller requests the output of
; more than 18 digits, this routine will output zeros
; for the additional digits.
            
            jmp     whileECXltMantSizeTest
            
whileECXltMantSize:
            
            mov     al, '0'
            cmp     ecx, 18
            jae     justPut0

            mov     al, Digits[ rcx*1 ]
                    
justPut0:
            mov     [rdi], al
            inc     rdi
            inc     ecx
            inc     edx
            
whileECXltMantSizeTest:
            cmp     ecx, MantSize
            jb      whileECXltMantSize

; Output the exponent:
            
            mov     byte ptr [rdi], 'e'
            inc     rdi
            inc     edx
            mov     al, '+'
            cmp     Exponent, 0
            jge     noNegExp
            
            mov     al, '-'
            neg     Exponent
                                            
noNegExp:
            mov     [rdi], al
            inc     rdi
            inc     edx
            
            mov     eax, Exponent
            mov     ecx, expDigs
            call    expToBuf
            jc      error
                    
exit_eToBuf:
            mov     rsi, rsiSave
            mov     rcx, rcxSave
            mov     rbx, rbxSave
            mov     rax, fWidth
            mov     rdx, expDigs
            leave
            clc
            ret

strOvfl:    mov     rax, -3
            jmp     error

badWidth:   mov     rax, -2
            jmp     error
            
voor:       mov     rax, -1
error:      mov     rsi, rsiSave
            mov     rcx, rcxSave
            mov     rbx, rbxSave
            mov     rdx, expDigs
            leave
            stc
            ret

_e10ToStr   endp

    
    
  
 
 

; r10ToStr-
;
;   Macro to create a HLL-like call for the 
; _r10ToStr procedure.
;
; Parameters:
;
;   r10:    Must be the name of a real4, real8, or 
;           real10 variable
;   dest:   Must be the name of a byte buffer to hold 
;           string result.
;
;   wdth:   Output width for the string. Either an
;           integer constant or a dword variable.
;
;   dPts:   Number of positions after the decimal
;           point. Either an integer constant or
;           a dword variable.
;
;   fill:   Fill char. Either a character constant
;           or a byte variable.
;
;   mxLen:  Maximum length of output string. Either
;           an integer constant or a dword variable.                   
            
r10ToStr    macro   r10, dest, wdth, dPts, fill, mxLen
            fld     r10
            
; dest is a label associated with a string variable.

            lea     rdi, dest
            
; width is either a constant or a dword var:

            mov     eax, wdth
            
; dPts is either a constant or a dword var
; holding the number of decimal point positions:

            mov     edx, dPts
            
; Process fill character. If it's a constant, 
; directly load it into ECX (which zero-extends
; into RCX). If it's a variable, then move with
; zero extension into ECX (which also zero 
; extends into RCX).
;
; Note: Bit 2 from OPATTR is 1 if fill is 
; a constant.
            
            if      ((opattr fill) and 4) eq 4
            mov     ecx, fill
            else
            movzx   ecx, fill
            endif

; maxLength is either a constant or a dword var.
            
            mov     r8d, mxLen
            call    _r10ToStr
            endm
            

; e10ToStr-
;
;   Macro to create a HLL-like call for the 
; _e10ToStr procedure.
;
; Parameters:
;
;   e10:    Must be the name of a real4, real8, or 
;           real10 variable
;   dest:   Must be the name of a byte buffer to hold 
;           string result.
;
;   wdth:   Output width for the string. Either an
;           integer constant or a dword variable.
;
;   xDigs:  Number of exponent digits.
;
;   fill:   Fill char. Either a character constant
;           or a byte variable.
;
;   mxLen:  Maximum length of output string. Either
;           an integer constant or a dword variable.                   

            

            
e10ToStr    macro   e10, dest, wdth, xDigs, fill, mxLen
            fld     e10
            
; dest is a label associated with a string variable.

            lea     rdi, dest
            
; width is either a constant or a dword var:

            mov     eax, wdth
            
; xDigs is either a constant or a dword var
; holding the number of decimal point positions:

            mov     edx, xDigs
            
; Process fill character. If it's a constant, 
; directly load it into ECX (which zero-extends
; into RCX). If it's a variable, then move with
; zero extension into ECX (which also zero 
; extends into RCX).
;
; Note: Bit 2 from OPATTR is 1 if fill is 
; a constant.
            
            if      ((opattr fill) and 4) eq 4
            mov     ecx, fill
            else
            movzx   ecx, fill
            endif

; maxLength is either a constant or a dword var.
            
            mov     r8d, mxLen
            call    _e10ToStr
            endm
            
            
; puts-
;
;   A macro to print a string using printf.
;
; Parameters:
;
;   fmt:    Format string (must be a byte
;           variable or string constant).
;
;   theStr: String to print (must be a
;           byte variable, a register,
;           or string constant).

puts        macro   fmt, theStr
            local   strConst, bool
            
            lea     rcx, fmt
            
            if      ((opattr theStr) and 2)
            
; If memory operand:

            lea     rdx, theStr
            
            elseif  ((opattr theStr) and 10h)
            
; If register operand:

            mov     rdx, theStr
            
            else 
            
; Assume it must be a string constant.

            .data
strConst    byte    theStr, 0
            .code
            lea     rdx, strConst
            
            endif
            
            call    printf
            endm

        
            public  asmMain
asmMain     proc
            push    rbx
            push    rsi
            push    rdi
            push    rbp
            mov     rbp, rsp
            sub     rsp, 64         ;Shadow storage
            
; F output

            r10ToStr r10_1, r10str_1, 30, 16, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 15, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 14, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 13, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 12, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 11, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 10, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 9, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 8, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 7, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 6, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 5, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 4, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 3, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 2, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 1, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
            r10ToStr r10_1, r10str_1, 30, 0, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            


            r10ToStr r10_2, r10str_1, 30, 16, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            

            r10ToStr r10_3, r10str_1, 30, 1, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            

            r10ToStr r10_4, r10str_1, 30, 6, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            

            r10ToStr r10_5, r10str_1, 30, 1, '*', 32
            jc      fpError
            puts    fmtStr1, r10str_1
            
; E output

            e10ToStr e10_1, r10str_1, 26, 3, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1

            e10ToStr e10_2, r10str_1, 26, 3, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1

            e10ToStr e10_3, r10str_1, 26, 3, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1

            e10ToStr e10_4, r10str_1, 26, 3, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1

            e10ToStr e10_5, r10str_1, 26, 3, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1

            e10ToStr e10_6, r10str_1, 26, 3, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1

            e10ToStr e10_7, r10str_1, 26, 3, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1

            e10ToStr e10_8, r10str_1, 26, 3, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1

            e10ToStr e10_9, r10str_1, 26, 4, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1

            e10ToStr e10_0, r10str_1, 26, 4, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1
            
            

            e10ToStr e10_3, r10str_1, 26, 1, '*', 32
            puts    fmtStr3, r10str_1
            
            e10ToStr e10_3, r10str_1, 26, 2, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1

            e10ToStr e10_3, r10str_1, 26, 3, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1

            e10ToStr e10_3, r10str_1, 26, 4, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1
            
            e10ToStr e10_3, r10str_1, 25, 1, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1
            
            e10ToStr e10_3, r10str_1, 20, 1, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1
            
            e10ToStr e10_3, r10str_1, 15, 1, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1
            
            e10ToStr e10_3, r10str_1, 10, 1, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1
            
            e10ToStr e10_3, r10str_1, 9, 1, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1
            
            e10ToStr e10_3, r10str_1, 8, 1, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1
            
            e10ToStr e10_3, r10str_1, 7, 1, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1
            
            e10ToStr e10_3, r10str_1, 6, 1, '*', 32
            jc      fpError
            puts    fmtStr3, r10str_1
            
            jmp     allDone
            
fpError:    puts    fmtStr2, rax
 

             
allDone:    leave
            pop     rdi
            pop     rsi
            pop     rbx
            ret     ;Returns to caller
asmMain     endp
            end

HLL-Like Calls with a Varying Parameter List

  • It can be done as shown below-

; HLL-like procedure calls with
; a varying parameter list.

        option  casemap:none

nl          =       10

            .const
ttlStr      byte    "Listing 14-9", 0
            
            .code
            externdef printf:proc

            
; Note: don't include print.inc here
; because this code uses a macro for
; print.

; print macro-
;
; HLL-like calling sequence for the _print
; function (which is, itself, a shell for
; the printf function).
;
; If print appears on a line by itself (no
; arguments), then emit a string consisting
; of a single newline character (and zero
; terminating byte). If there are one or
; more arguments, emit each argument; append
; a single zero byte after all the arguments.
;
; Examples:
;
;           print
;           print   "Hello, World!"
;           print   "Hello, World!", nl

print       macro   arg1, optArgs:vararg
            call    _print
            
            ifb     <arg1>

; If print is used byte itself, print a
; newline character:
            
            byte    nl, 0
            
            else
            
; If we have one or more arguments, then
; emit each of them:
            
            byte    arg1

            for     oa, <optArgs>
            
            byte    oa
            
            endm

; Zero-terminate the string.

            byte    0
            
            endif
            endm
 
_print      proc
            push    rax
            push    rbx
            push    rcx
            push    rdx
            push    r8
            push    r9
            push    r10
            push    r11
            
            push    rbp
            mov     rbp, rsp
            sub     rsp, 40
            and     rsp, -16
            
            mov     rcx, [rbp+72]   ;Return address
            call    printf
            
            mov     rcx, [rbp+72]
            dec     rcx
skipTo0:    inc     rcx
            cmp     byte ptr [rcx], 0
            jne     skipTo0
            inc     rcx
            mov     [rbp+72], rcx
            
            leave
            pop     r11
            pop     r10
            pop     r9
            pop     r8
            pop     rdx
            pop     rcx
            pop     rbx
            pop     rax
            ret
_print      endp
              
; Here is the "asmMain" function.

        
            public  asmMain
asmMain     proc
            push    rbx
            push    rdi
            push    rsi
            push    rbp
            mov     rbp, rsp
            sub     rsp, 56         ;Shadow storage

            print   "Hello world"
            print
            print   "Hello, World!", nl
                        

allDone:    leave
            pop     rsi
            pop     rdi
            pop     rbx
            ret     ;Returns to caller
asmMain     endp
            end

Advanced Macro Parameter Parsing

Using opattr to Determine Argument Types

  • Opattr compile-time operator returns an integer value with certain bits set based on the type of expression that follows. In particular, bit 2 will be set if the expression following is relocatable or otherwise references memory. Therefore, this bit will be set if a variable such as fmtStr appears as the argument, and it will be clear if you pass a string literal as the argument.

  • It follows the following syntax-

opattr expression
  • The opattr operator returns an integer value that is a bit mask specifying the opattr attributes of the associated expression. If the expression following opattr contains forward-referenced symbols or is an illegal expression, opattr returns 0.

opattr Return Values
; OPATTR demonstration

        option  casemap:none

nl          =       10

            .const
           
fmtStr      byte    nl, "Hello, World! #2", nl, 0

            .code
            externdef printf:proc

; cprintf macro-
;
;           cprintf fmtStr
;           cprintf "Format String"

cprintf     macro   fmtStrArg
            local   fmtStr, attr, isConst
            
attr        =       OPATTR fmtStrArg
isConst     =       (attr and 4) eq 4
            if      (attr eq 0) or isConst
            .data                                              
fmtStr      byte    fmtStrArg, 0
            .code
            lea     rcx, fmtStr
            
            else
            
            lea     rcx, fmtStrArg
            
            endif
            call    printf
            endm
 
atw         =       opattr "Hello Word"
bin         =       opattr "abcdefghijklmnopqrstuvwxyz"                 
                    
            
; Here is the "asmMain" function.
        
            public  asmMain
asmMain     proc
            push    rbx
            push    rdi
            push    rsi
            push    rbp
            mov     rbp, rsp
            sub     rsp, 56         ;Shadow storage

            cprintf "Hello World!"
            cprintf fmtStr
             
allDone:    leave
            pop     rsi
            pop     rdi
            pop     rbx
            ret     ;Returns to caller
asmMain     endp
            end
  • If, in a macro, you were to test only bit 2 to determine if the operand is a constant, you could get into trouble when bit 2 is set and you assume that it is a constant. Probably the wisest thing to do is to mask off bits 0 to 7 (or maybe just bits 0 to 6) and compare the result against an 8-bit value rather than a simple mask.

8-Bit Values for opattr Results
  • We can check for specific parameter types using opattr operator as shown in the code below.

; Several useful macro functions:
;
; mout-	Like echo, but allows "%" operators.
;
; testStr-	Tests an operand to see if it
;	is a string literal constant
;
; @sizestr-	Handles missing MASM function
;
; isDigit-	Tests first character of its
;	argument to see if it's a decimal
;	digit.
;
; isSign-	Tests first character of its
;	argument to see if it's a '+'
;	or a '-' character.
;
; extract1st- Removes the first character
;	from its argument (side effect)
;	and returns that character as
;	the function result.
;
; getReal-	Parses the argument and returns
;	true if it is a reasonable-
;	looking real constant.


        option  casemap:none


; mout-
;
;  Replacement for echo. Allows "%" operator
; in operand field to expand text symbols.

mout        macro   valToPrint
            local   cmd
cmd         catstr  <echo >, <valToPrint>
            cmd
            endm

; testStr is a macro function that tests its
; operand to see if it is a string literal.
            
testStr     macro   strParm
            local   firstChar
            
            ifnb    <strParm>
firstChar   substr  <strParm>, 1, 1

            ifidn   firstChar,<!">
            
; First character was '"', so assume it's
; a string.

            exitm   <1>
            endif   ;ifidn
            endif   ;ifnb
            
; If we get to this point in the macro
; we definitely do not have a string.

            exitm   <0>
            endm
            
; @sizestr-
;
;  Replacement for the MASM function
; which doesn't seem to work

@sizestr    macro   theStr
            local   theLen
theLen      sizestr <theStr>
            exitm   <&theLen>
            endm	;@sizestr


; isDigit-
;
;   Macro function that returns true if the
; first character of its parameter is a
; decimal digit.

isDigit     macro   parm
            local   FirstChar
            if      @sizestr(%parm) eq 0
            exitm   <0>
            endif
            
FirstChar   substr  parm, 1, 1
	ifidn	FirstChar,<0>
	exitm	<1>
	endif
	ifidn	FirstChar,<1>
	exitm	<1>
	endif
	ifidn	FirstChar,<2>
	exitm	<1>
	endif
	ifidn	FirstChar,<3>
	exitm	<1>
	endif
	ifidn	FirstChar,<4>
	exitm	<1>
	endif
	ifidn	FirstChar,<5>
	exitm	<1>
	endif
	ifidn	FirstChar,<6>
	exitm	<1>
	endif
	ifidn	FirstChar,<7>
	exitm	<1>
	endif
	ifidn	FirstChar,<8>
	exitm	<1>
	endif
	ifidn	FirstChar,<9>
	exitm	<1>
	endif
	exitm	<0>
            endm


; isSign-
;
;   Macro function that returns true if the
; first character of its parameter is a
; + or -

isSign      macro   parm
            local   FirstChar
            ifb     <parm>
            exitm   <0>
            endif
            
FirstChar   substr  parm, 1, 1
            ifidn   FirstChar, <+>
            exitm   <1>
            endif
            ifidn   FirstChar, <->
            exitm   <1>
            endif
            exitm   <0>
            endm



; isE-
;
;   Macro function that returns true if the
; first character of its parameter is a
; e or E

isE         macro   parm
            local   FirstChar
            if      @sizestr(%parm) eq 0
            exitm   <0>
            endif
            
FirstChar   substr  parm, 1, 1
            ifidni   FirstChar, <e>
            exitm   <1>
            endif
            exitm   <0>
            endm
            
; extract1st
;
;  Macro that gets passed a text variable.
; Extracts the first character (if any)
; and removes that character from the
; argument.

extract1st  macro   parm
            local   FirstChar
            ifb     <%parm>
            exitm   <>
            endif
FirstChar   substr  parm, 1, 1
            if      @sizestr(%parm) GE 2
parm        substr  parm, 2
            else
parm        textequ <>
            endif

            exitm   <FirstChar>
            endm
            
            
            
; getExp-
;
;  Given an input string that (presumably)
; holds an exponent value, this function
; returns the following:
;
; <0>:      Invalid text (error)
; <1>:      Either a valid exponent
;           is present, or no exponent
;           at all is present.
;
; Note that a blank input string is legal.
; Exponents are optional.
;
; Sign :=(+|-) 
; Digit ::= [0-9]
; Exp ::= (e|E) Sign? Digit Digit? Digit? Digit?

getExp      macro   parm
            local   curChar
            
; Return success if no exponent present

            if      @sizestr(%parm) eq 0
            exitm   <1>
            endif

; Extract the next character, return failure
; if it is not an 'e' or 'E' character:
            
curChar     textequ extract1st(parm)
            if      isE(curChar) eq 0
            exitm   <0>
            endif

; Extract the next character:
            
curChar     textequ extract1st(parm)

; If an optional sign character appears,
; remove it from the string:

            if      isSign( curChar )
curChar     textequ extract1st(parm)        ;Skip sign char
            endif   ;isSign
            
; Must have at least one digit

            if      isDigit( curChar ) eq 0
            exitm   <0>
            endif
            
; Optionally, we can have up to three additional digits

            if      @sizestr(%parm) gt 0
curChar     textequ extract1st(parm)        ;Skip 1st digit
            if      isDigit( curChar ) eq 0
            exitm   <0>
            endif
            endif

            if      @sizestr(%parm) gt 0
curChar     textequ extract1st(parm)        ;Skip 2nd digit
            if      isDigit( curChar ) eq 0
            exitm   <0>
            endif
            endif

            if      @sizestr(%parm) gt 0
curChar     textequ extract1st(parm)        ;Skip 3rd digit
            if      isDigit( curChar ) eq 0
            exitm   <0>
            endif
            endif

; If we get to this point, we have a valid exponent.

            exitm   <1>     
            endm    ;getExp
            
; getMant
;
;
;  Given an input string that (presumably)
; holds a mantissa value, this function
; returns the following:
;
; <0>:      Invalid text (error)
; <1>:      A valid mantissa
;
; Note that processing stops on the first
; illegal character (or the second decimal
; point, if it finds 2 of them). 
; As long as the string contains at least 1 digit, 
; this function returns true. 
;
; Digit ::= [0-9]
; Mantissa ::= (Digit)+ | '.' Digit)+ | (Digit)+ '.' Digit*

getMant     macro   parm
            local   curChar, sawDecPt, rpt
sawDecPt    =       0
curChar     textequ extract1st(parm)        ;get 1st char
            ifidn   curChar, <.>            ;Check for dec pt
sawDecPt    =       1
curChar     textequ extract1st(parm)        ;get 2nd char
            endif
            
; Must have at least one digit:

            if      isDigit( curChar ) eq 0
            exitm   <0>                     ;Bad mantissa
            endif

            
; Process zero or more digits. If we haven't already
; seen a decimal point, allow exactly one of those.
;
; Do loop at least once if there is at least one
; character left in parm:

rpt         =       @sizestr(%parm)
            while   rpt
            
; Get the 1st char from parm and see if
; it is a decimal point or a digit:

curChar     substr  parm, 1, 1
            ifidn   curChar, <.>
rpt         =       sawDecPt eq 0
sawDecPt    =       1
            else
rpt         =       isDigit(curChar)
            endif

; If char was legal, then extract it from parm:

            if      rpt
curChar     textequ extract1st(parm)        ;get next char
            endif
            
; Repeat as long as we have more chars and the
; current character is legal:

rpt         =       rpt and (@sizestr(%parm) gt 0)
            endm    ;while
            
; If we've seen at least one digit, we've got a valid
; mantissa. We've stopped processing on the first 
; character that is not a digit or the 2nd '.' char.

            exitm   <1>
            endm    ;getMant
            

; getReal-
;
;   Parses a real constant.
;
; Returns:
;    true:  If the parameter contains a syntactically
;           correct real number (and no extra characters).
;    false: If there are any illegal characters or
;           other syntax errors in the numeric string.
;
; Sign :=(+|-) 
; Digit ::= [0-9]
; Mantissa ::= (Digit)+ | '.' Digit)+ | (Digit)+ '.' Digit*
; Exp ::= (e|E) Sign? Digit Digit? Digit? Digit?
; Real ::= Sign? Mantissa Exp?

getReal     macro   origParm
            local   parm, curChar, result
            
; Make a copy of the parameter so we don't
; delete the characters in the original string

parm        textequ &origParm

; Must have at least one character:

            ifb     parm
            exitm   <0>
            endif
            
; Extract the optional sign:

            if      isSign(parm)
curChar     textequ extract1st(parm)        ;skip sign char
            endif
            
; Get the required mantissa:

            if      getMant(parm) eq 0
            exitm   <0>                     ;Bad mantissa
            endif

; Extract the optional exponent:

result      textequ getExp(parm)    
            exitm   <&result>       
            
            endm    ;getReal
	
	
; Test strings and invocations for the
; getReal macro;

            
mant1       textequ <1>
mant2       textequ <.2>
mant3       textequ <3.4>
rv4         textequ <1e1>
rv5         textequ <1.e1>
rv6         textequ <1.0e1>
rv7         textequ <1.0e+1>
rv8         textequ <1.0e-1>
rv9         textequ <1.0e12>
rva         textequ <1.0e1234>
rvb         textequ <1.0E123>
rvc         textequ <1.0E+1234>
rvd         textequ <1.0E-1234>
rve         textequ <-1.0E-1234>
rvf         textequ <+1.0E-1234>
badr1       textequ <>
badr2       textequ <a>
badr3       textequ <1.1.0>
badr4       textequ <e1>
badr5       textequ <1ea1>
badr6       textequ <1e1a>

% echo get_Real(mant1) = getReal(mant1) 
% echo get_Real(mant2) = getReal(mant2)
% echo get_Real(mant3) = getReal(mant3)
% echo get_Real(rv4)   = getReal(rv4)
% echo get_Real(rv5)   = getReal(rv5)
% echo get_Real(rv6)   = getReal(rv6)
% echo get_Real(rv7)   = getReal(rv7)
% echo get_Real(rv8)   = getReal(rv8)
% echo get_Real(rv9)   = getReal(rv9)
% echo get_Real(rva)   = getReal(rva)
% echo get_Real(rvb)   = getReal(rvb)
% echo get_Real(rvc)   = getReal(rvc)
% echo get_Real(rvd)   = getReal(rvd)
% echo get_Real(rve)   = getReal(rve)
% echo get_Real(rvf)   = getReal(rvf)
% echo get_Real(badr1) = getReal(badr1)
% echo get_Real(badr2) = getReal(badr2)
% echo get_Real(badr3) = getReal(badr3)
% echo get_Real(badr4) = getReal(badr4)
% echo get_Real(badr5) = getReal(badr5)
% echo get_Real(badr5) = getReal(badr5)
            
; Here is the "asmMain" function.
            end

Checking For Registers

  • Although the opattr operator provides a bit to tell you that its operand is an x86-64 register, that’s the only information opattr provides. In particular, opattr’s return value won’t tell you which register it has seen; whether it’s a general-purpose, XMM, YMM, ZMM, MM, ST, or other register; or the size of that register.

  • The below code contains a set of equates that map register names to numeric values. These equates use symbols of the form regXXX, where XXX is the register name (all uppercase).

Opattr check for registers
; Compile-time program testing
; register operands

        option  casemap:none

; Register values:

regNone     =       0
regAL       =       1
regBL       =       2
regCL       =       3
regDL       =       4
regAH       =       5
regBH       =       6
regCH       =       7
regDH       =       8
regSIL      =       9
regDIL      =       10
regBPL      =       11
regSPL      =       12
regR8B      =       13
regR9B      =       14
regR10B     =       15
regR11B     =       16
regR12B     =       17
regR13B     =       18
regR14B     =       19
regR15B     =       20

regAX       =       21
regBX       =       22
regCX       =       23
regDX       =       24
regSI       =       25
regDI       =       26
regBP       =       27
regSP       =       28
regR8W      =       29
regR9W      =       30
regR10W     =       31
regR11W     =       32
regR12W     =       33
regR13W     =       34
regR14W     =       35
regR15W     =       36

regEAX      =       37
regEBX      =       38
regECX      =       39
regEDX      =       40
regESI      =       41
regEDI      =       42
regEBP      =       43
regESP      =       44
regR8D      =       45
regR9D      =       46
regR10D     =       47
regR11D     =       48
regR12D     =       49
regR13D     =       50
regR14D     =       51
regR15D     =       52

regRAX      =       53
regRBX      =       54
regRCX      =       55
regRDX      =       56
regRSI      =       57
regRDI      =       58
regRBP      =       59
regRSP      =       60
regR8       =       61
regR9       =       62
regR10      =       63
regR11      =       64
regR12      =       65
regR13      =       66
regR14      =       67
regR15      =       68

regST       =       69
regST0      =       70
regST1      =       71
regST2      =       72
regST3      =       73
regST4      =       74
regST5      =       75
regST6      =       76
regST7      =       77

regMM0      =       78
regMM1      =       79
regMM2      =       80
regMM3      =       81
regMM4      =       82
regMM5      =       83
regMM6      =       84
regMM7      =       85

regXMM0     =       86
regXMM1     =       87
regXMM2     =       88
regXMM3     =       89
regXMM4     =       90
regXMM5     =       91
regXMM6     =       92
regXMM7     =       93
regXMM8     =       94
regXMM9     =       95
regXMM10    =       96
regXMM11    =       97
regXMM12    =       98
regXMM13    =       99
regXMM14    =       100
regXMM15    =       101

regYMM0     =       102
regYMM1     =       103
regYMM2     =       104
regYMM3     =       105
regYMM4     =       106
regYMM5     =       107
regYMM6     =       108
regYMM7     =       109
regYMM8     =       110
regYMM9     =       111
regYMM10    =       112
regYMM11    =       113
regYMM12    =       114
regYMM13    =       115
regYMM14    =       116
regYMM15    =       117

; Left to the reader:
; Implement ZMM registers.
; Implement system and special-purpose registers.




; The following text equates allow
; this code to turn a register
; number (the equates above)
; into a register name.

toReg       macro   regNum
            local   register
register    catstr  <reg>,%regNum
            exitm   &register
            endm    ;toReg
                            
reg0        textequ <>
reg1        textequ <al>
reg2        textequ <bl>            
reg3        textequ <cl>
reg4        textequ <dl>
reg5        textequ <ah>
reg6        textequ <bh>
reg7        textequ <ch>
reg8        textequ <dh>
reg9        textequ <sil>
reg10       textequ <dil>
reg11       textequ <bpl>
reg12       textequ <spl>
reg13       textequ <r8b>
reg14       textequ <r9b>
reg15       textequ <r10b>
reg16       textequ <r11b>
reg17       textequ <r12b>
reg18       textequ <r13b>
reg19       textequ <r14b>
reg20       textequ <r15b>

reg21       textequ <ax>  
reg22       textequ <bx>  
reg23       textequ <cx>  
reg24       textequ <dx>  
reg25       textequ <si>  
reg26       textequ <di>  
reg27       textequ <bp>  
reg28       textequ <sp>  
reg29       textequ <r8w> 
reg30       textequ <r9w> 
reg31       textequ <r10w>
reg32       textequ <r11w>
reg33       textequ <r12w>
reg34       textequ <r13w>
reg35       textequ <r14w>
reg36       textequ <r15w>

reg37       textequ <EAX> 
reg38       textequ <EBX> 
reg39       textequ <ECX> 
reg40       textequ <EDX> 
reg41       textequ <ESI> 
reg42       textequ <EDI> 
reg43       textequ <EBP> 
reg44       textequ <ESP> 
reg45       textequ <R8D> 
reg46       textequ <R9D> 
reg47       textequ <R10D>
reg48       textequ <R11D>
reg49       textequ <R12D>
reg50       textequ <R13D>
reg51       textequ <R14D>
reg52       textequ <R15D>

reg53       textequ <RAX>
reg54       textequ <RBX>
reg55       textequ <RCX>
reg56       textequ <RDX>
reg57       textequ <RSI>
reg58       textequ <RDI>
reg59       textequ <RBP>
reg60       textequ <RSP>
reg61       textequ <R8>
reg62       textequ <R9>
reg63       textequ <R10>
reg64       textequ <R11>
reg65       textequ <R12>
reg66       textequ <R13>
reg67       textequ <R14>
reg68       textequ <R15>

reg69       textequ <ST>          
reg70       textequ <ST(0)>         
reg71       textequ <ST(1)>         
reg72       textequ <ST(2)>         
reg73       textequ <ST(3)>         
reg74       textequ <ST(4)>         
reg75       textequ <ST(5)>         
reg76       textequ <ST(6)>         
reg77       textequ <ST(7)>         

reg78       textequ <MM0>         
reg79       textequ <MM1>         
reg80       textequ <MM2>         
reg81       textequ <MM3>         
reg82       textequ <MM4>         
reg83       textequ <MM5>         
reg84       textequ <MM6>         
reg85       textequ <MM7>         

reg86       textequ <XMM0>        
reg87       textequ <XMM1>        
reg88       textequ <XMM2>        
reg89       textequ <XMM3>        
reg90       textequ <XMM4>        
reg91       textequ <XMM5>        
reg92       textequ <XMM6>        
reg93       textequ <XMM7>        
reg94       textequ <XMM8>        
reg95       textequ <XMM9>        
reg96       textequ <XMM10>       
reg97       textequ <XMM11>       
reg98       textequ <XMM12>       
reg99       textequ <XMM13>       
reg100      textequ <XMM14>       
reg101      textequ <XMM15>       

reg102      textequ <YMM0>        
reg103      textequ <YMM1>        
reg104      textequ <YMM2>        
reg105      textequ <YMM3>        
reg106      textequ <YMM4>        
reg107      textequ <YMM5>        
reg108      textequ <YMM6>        
reg109      textequ <YMM7>        
reg110      textequ <YMM8>        
reg111      textequ <YMM9>        
reg112      textequ <YMM10>       
reg113      textequ <YMM11>       
reg114      textequ <YMM12>       
reg115      textequ <YMM13>       
reg116      textequ <YMM14>       
reg117      textequ <YMM15>       


; The following equates allow
; this code to map an 8-bit
; register to its corresponding
; 16-bit register:

reg8To16    macro   reg8
            local   register
register    catstr  <m8_16_>,%reg8
            exitm   &register
            endm    ;toReg

m8_16_1     textequ <ax>    ;Maps al to ax
m8_16_2     textequ <bx>    ;Maps bl to bx
m8_16_3     textequ <cx>    ;Maps cl to cx
m8_16_4     textequ <dx>    ;Maps dl to dx
m8_16_5     textequ <ax>    ;Maps ah to ax
m8_16_6     textequ <bx>    ;Maps bh to bx
m8_16_7     textequ <cx>    ;Maps ch to cx
m8_16_8     textequ <dx>    ;Maps dh to dx
m8_16_9     textequ <si>    ;Maps sil to si
m8_16_10    textequ <di>    ;Maps dil to di
m8_16_11    textequ <bp>    ;Maps bpl to bp
m8_16_12    textequ <sp>    ;Maps spl to sp
m8_16_13    textequ <r8w>   ;Maps r8b to r8w
m8_16_14    textequ <r9w>   ;Maps r9b to r9w
m8_16_15    textequ <r10w>  ;Maps r10b to r10w
m8_16_16    textequ <r11w>  ;Maps r11b to r11w
m8_16_17    textequ <r12w>  ;Maps r12b to r12w
m8_16_18    textequ <r13w>  ;Maps r13b to r13w
m8_16_19    textequ <r14w>  ;Maps r14b to r14w
m8_16_20    textequ <r15w>  ;Maps r15b to r15w

; The following equates allow
; this code to map an 8-bit
; register to its corresponding
; 32-bit register:

reg8To32    macro   reg8
            local   register
register    catstr  <m8_32_>,%reg8
            exitm   &register
            endm    ;toReg

m8_32_1     textequ <eax>   ;Maps al to eax
m8_32_2     textequ <ebx>   ;Maps bl to ebx
m8_32_3     textequ <ecx>   ;Maps cl to ecx
m8_32_4     textequ <edx>   ;Maps dl to edx
m8_32_5     textequ <eax>   ;Maps ah to eax
m8_32_6     textequ <ebx>   ;Maps bh to ebx
m8_32_7     textequ <ecx>   ;Maps ch to ecx
m8_32_8     textequ <edx>   ;Maps dh to edx
m8_32_9     textequ <esi>   ;Maps sil to esi
m8_32_10    textequ <edi>   ;Maps dil to edi
m8_32_11    textequ <ebp>   ;Maps bpl to ebp
m8_32_12    textequ <esp>   ;Maps spl to esp
m8_32_13    textequ <r8d>   ;Maps r8b to r8d
m8_32_14    textequ <r9d>   ;Maps r9b to r9d
m8_32_15    textequ <r10d>  ;Maps r10b to r10d
m8_32_16    textequ <r11d>  ;Maps r11b to r11d
m8_32_17    textequ <r12d>  ;Maps r12b to r12d
m8_32_18    textequ <r13d>  ;Maps r13b to r13d
m8_32_19    textequ <r14d>  ;Maps r14b to r14d
m8_32_20    textequ <r15d>  ;Maps r15b to r15d

; The following equates allow
; this code to map an 8-bit
; register to its corresponding
; 32-bit register:

reg8To64    macro   reg8
            local   register
register    catstr  <m8_64_>,%reg8
            exitm   &register
            endm    ;toReg

m8_64_1     textequ <rax>   ;Maps al to rax
m8_64_2     textequ <rbx>   ;Maps bl to rbx
m8_64_3     textequ <rcx>   ;Maps cl to rcx
m8_64_4     textequ <rdx>   ;Maps dl to rdx
m8_64_5     textequ <rax>   ;Maps ah to rax
m8_64_6     textequ <rbx>   ;Maps bh to rbx
m8_64_7     textequ <rcx>   ;Maps ch to rcx
m8_64_8     textequ <rdx>   ;Maps dh to rdx
m8_64_9     textequ <rsi>   ;Maps sil to rsi
m8_64_10    textequ <rdi>   ;Maps dil to rdi
m8_64_11    textequ <rbp>   ;Maps bpl to rbp
m8_64_12    textequ <rsp>   ;Maps spl to rsp
m8_64_13    textequ <r8>    ;Maps r8b to r8
m8_64_14    textequ <r9>    ;Maps r9b to r9
m8_64_15    textequ <r10>   ;Maps r10b to r10
m8_64_16    textequ <r11>   ;Maps r11b to r11
m8_64_17    textequ <r12>   ;Maps r12b to r12
m8_64_18    textequ <r13>   ;Maps r13b to r13
m8_64_19    textequ <r14>   ;Maps r14b to r14
m8_64_20    textequ <r15>   ;Maps r15b to r15



; The following equates allow
; this code to map a 16-bit
; register to its corresponding
; 32-bit register:

reg16To32   macro   reg16
            local   register
register    catstr  <m16_32_>,%reg16
            exitm   &register
            endm    ;toReg

m16_32_21   textequ <eax>   ;Maps ax to eax
m16_32_22   textequ <ebx>   ;Maps bx to ebx
m16_32_23   textequ <ecx>   ;Maps cx to ecx
m16_32_24   textequ <edx>   ;Maps dx to edx
m16_32_25   textequ <esi>   ;Maps si to esi
m16_32_26   textequ <edi>   ;Maps di to edi
m16_32_27   textequ <ebp>   ;Maps bp to ebp
m16_32_28   textequ <esp>   ;Maps sp to esp
m16_32_29   textequ <r8d>   ;Maps r8w to r8d
m16_32_30   textequ <r9d>   ;Maps r9w to r9d
m16_32_31   textequ <r10d>  ;Maps r10w to r10d
m16_32_32   textequ <r11d>  ;Maps r11w to r11d
m16_32_33   textequ <r12d>  ;Maps r12w to r12d
m16_32_34   textequ <r13d>  ;Maps r13w to r13d
m16_32_35   textequ <r14d>  ;Maps r14w to r14d
m16_32_36   textequ <r15d>  ;Maps r15w to r15d



; The following equates allow
; this code to map a 16-bit
; register to its corresponding
; 64-bit register:

reg16To64   macro   reg16
            local   register
register    catstr  <m16_64_>,%reg16
            exitm   &register
            endm    ;toReg

m16_64_21   textequ <rax>   ;Maps ax to rax
m16_64_22   textequ <rbx>   ;Maps bx to rbx
m16_64_23   textequ <rcx>   ;Maps cx to rcx
m16_64_24   textequ <rdx>   ;Maps dx to rdx
m16_64_25   textequ <rsi>   ;Maps si to rsi
m16_64_26   textequ <rdi>   ;Maps di to rdi
m16_64_27   textequ <rbp>   ;Maps bp to rbp
m16_64_28   textequ <rsp>   ;Maps sp to rsp
m16_64_29   textequ <r8>    ;Maps r8w to r8
m16_64_30   textequ <r9>    ;Maps r9w to r9
m16_64_31   textequ <r10>   ;Maps r10w to r10
m16_64_32   textequ <r11>   ;Maps r11w to r11
m16_64_33   textequ <r12>   ;Maps r12w to r12
m16_64_34   textequ <r13>   ;Maps r13w to r13
m16_64_35   textequ <r14>   ;Maps r14w to r14
m16_64_36   textequ <r15>   ;Maps r15w to r15



; The following equates allow
; this code to map a 32-bit
; register to its corresponding
; 64-bit register:

reg32To64   macro   reg32
            local   register
register    catstr  <m32_64_>,%reg32
            exitm   &register
            endm    ;toReg

m32_64_37   textequ <rax>   ;Maps eax to rax
m32_64_38   textequ <rbx>   ;Maps ebx to rbx
m32_64_39   textequ <rcx>   ;Maps ecx to rcx
m32_64_40   textequ <rdx>   ;Maps edx to rdx
m32_64_41   textequ <rsi>   ;Maps esi to rsi
m32_64_42   textequ <rdi>   ;Maps edi to rdi
m32_64_43   textequ <rbp>   ;Maps ebp to rbp
m32_64_44   textequ <rsp>   ;Maps esp to rsp
m32_64_45   textequ <r8>    ;Maps r8d to r8
m32_64_46   textequ <r9>    ;Maps r9d to r9
m32_64_47   textequ <r10>   ;Maps r10d to r10
m32_64_48   textequ <r11>   ;Maps r11d to r11
m32_64_49   textequ <r12>   ;Maps r12d to r12
m32_64_50   textequ <r13>   ;Maps r13d to r13
m32_64_51   textequ <r14>   ;Maps r14d to r14
m32_64_52   textequ <r15>   ;Maps r15d to r15
                    



; mout-
;
;  Replacement for echo. Allows "%" operator
; in operand field to expand text symbols.

mout        macro   valToPrint
            local   cmd
cmd         catstr  <echo >, <valToPrint>
            cmd
            endm


            
; toUpper
;
;   Converts alphabetic characters to upper case
;   in a text string

toUpper     macro   lcStr
            local   result
            
; Build the result string in "result":

result      textequ <>

; For each character in the source string, conver it to upper case.

            forc    eachChar, <lcStr>

; See if we have a lower case character:

            if      ('&eachChar' ge 'a') and ('&eachChar' le 'z')
            
; If lower case, convert it to the symbol "lc_*" where "*"
; is the lower case character. The equates below will map
; this character to upper case:

eachChar    catstr  <lc_>,<eachChar>
result      catstr  result, &eachChar

            else
            
; If it wasn't a lower case character, just append it
; to the end of the string:

result      catstr  result, <eachChar>

            endif
            endm    ;forc
            exitm   result  ;Return result string
            endm    ;toUpper
            
lc_a        textequ <A>
lc_b        textequ <B>
lc_c        textequ <C>
lc_d        textequ <D>
lc_e        textequ <E>
lc_f        textequ <F>
lc_g        textequ <G>
lc_h        textequ <H>
lc_i        textequ <I>
lc_j        textequ <J>
lc_k        textequ <K>
lc_l        textequ <L>
lc_m        textequ <M>
lc_n        textequ <N>
lc_o        textequ <O>
lc_p        textequ <P>
lc_q        textequ <Q>
lc_r        textequ <R>
lc_s        textequ <S>
lc_t        textequ <T>
lc_u        textequ <U>
lc_v        textequ <V>
lc_w        textequ <W>
lc_x        textequ <X>
lc_y        textequ <Y>
lc_z        textequ <Z>

; isReg-
;
;   Returns true if operand is a register
;   (any register type)

isReg       macro   parm
            local   result
result      textequ %(((opattr &parm) and 10h) eq 10h)
            exitm   <&result>
            endm    ;isReg
 
;--------------------------------------------------------
; lookupReg:
;
; Given a (suspected) register and a lookup table, convert
; that register to the corresponding numeric form.

lookupReg   macro   theReg, regList, regIndex
            local   regUpper, regConst, inst, regLen, indexLen

; Convert (possible) register to upper case:

regUpper    textequ toUpper( theReg )
regLen      sizestr <&theReg>

; Does it exist in regList? If not, it's not a register.

inst        instr   1, regList, &regUpper
            if      inst ne 0

regConst    substr  &regIndex, inst, 1
            if      &regConst eq regLen
            
; It's a  register (in text form). Create an identifier of
; the form "regXX" where "XX" represents the register name:

regConst    catStr  <reg>,regUpper

            ifdef   &regConst

; Return "regXX" as function result. This is the numeric value
; for the register.

            exitm   regConst
            endif
            endif
            endif

; If the parameter string wasn't in regList, then return
; "regNone" as the function result:

            exitm   <regNone>
            endm    ;lookupReg

;------------------------------------------------------------------------------           
; is8BitReg
;
;  Returns reg numeric value if an 8-bit register,
; returns 0 (regNone) if not an 8-bit register.
;
; all8BitRegs is a string with all the 8-bit registers listed (must be upper case).
; all8Lengths is an array of 1-digit register lengths. The index into the string
; matches the starting index of each register in all8BitRegs.

all8BitRegs textequ <ALBLCLDLAHBHCHDHSILDILBPLSPLR8BR9BR10BR11BR12BR13BR14BR15B>
all8Lengths textequ <2020202020202020300300300300300300400040004000400040004000>

is8BitReg   macro   parm
            exitm   lookupReg( parm, all8BitRegs, all8Lengths )
            endm    ;is8BitReg
            

;-------------------------------------------------------------------------------            
; is16BitReg
;
;  Returns reg numeric value if a 16-bit register,
; returns 0 (regNone) if not an 16-bit register.

all16Regs   textequ <AXBXCXDXSIDIBPSPR8WR9WR10WR11WR12WR13WR14WR15W>
all16Lens   textequ <2020202020202020300300400040004000400040004000>

is16BitReg  macro   parm
            exitm   lookupReg( parm, all16Regs, all16Lens )
            endm    ;is16BitReg



;-------------------------------------------------            
; is32BitReg
;
;  Returns reg numeric value if a 32-bit register,
; returns 0 (regNone) if not an 32-bit register.

all32Regs   textequ <EAXEBXECXEDXESIEDIEBPESPR8DR9DR10DR11DR12DR13DR14DR15D>
all32Lens   textequ <300300300300300300300300300300400040004000400040004000>

is32BitReg  macro   parm
            exitm   lookupReg( parm, all32Regs, all32Lens )
            endm    ;is32BitReg


            
; is64BitReg
;
;  Returns reg numeric value if a 64-bit register,
; returns 0 (regNone) if not an 64-bit register.

all64Regs   textequ <RAXRBXRCXRDXRSIRDIRBPRSPR8R9R10R11R12R13R14R15>
all64Lens   textequ <3003003003003003003003002020300300300300300300>

is64BitReg  macro   parm
            exitm   lookupReg( parm, all64Regs, all64Lens )
            endm    ;is64BitReg


; isGPReg-
;
;   Returns the register number constant if
; the register is a general-purpose (8-, 16-,
; 32-, or 64-bit) register.

isGPReg     macro   parm
            local   text

text        textequ is8BitReg(parm)
            if      &text ne regNone
            exitm   text
            endif
                        
text        textequ is16BitReg(parm)
            if      &text ne regNone
            exitm   text
            endif
                        
text        textequ is32BitReg(parm)
            if      &text ne regNone
            exitm   text
            endif
                        
text        textequ is64BitReg(parm)
            if      &text ne regNone
            exitm   text
            endif
                        
            exitm   <0>
            endm    ;isGPReg
            

; isFPReg-
;
;  True if the parameter is one of the
; FPU registers (ST, ST(0), ST(1), etc)
;
; Note that isFPReg returns regST0 for
; the text "ST". If you need to differentiate
; ST and ST(0), you will need to keep the
; original parameter text around.
;
; Because FPU registers have a funny syntax,
; we have to brute-force compare against them.


isFPReg     macro   parm
            ifidni  <&parm>, <st>
            exitm   <regST>
            endif
            ifidni  <&parm>, <ST(0)>
            exitm   <regST0>
            endif
            ifidni  <&parm>, <ST(1)>
            exitm   <regST1>
            endif
            ifidni  <&parm>, <ST(2)>
            exitm   <regST2>
            endif
            ifidni  <&parm>, <ST(3)>
            exitm   <regST3>
            endif
            ifidni  <&parm>, <ST(4)>
            exitm   <regST4>
            endif
            ifidni  <&parm>, <ST(5)>
            exitm   <regST5>
            endif
            ifidni  <&parm>, <ST(6)>
            exitm   <regST6>
            endif
            ifidni  <&parm>, <ST(7)>
            exitm   <regST7>
            endif

            endm    ;isFPReg

; isMMReg
;
;  Returns register value for one of
; the MMX registers (mm0..mm15)

allMMRegs   textequ <MM0MM1MM2MM3MM4MM5MM6MM7>
allMMLens   textequ <300300300300300300300300>

isMMReg     macro   parm
            exitm   lookupReg( parm, allMMRegs, allMMLens )
            endm    ;isMMReg        
            
; isXMMReg
;
;  Returns register value for one of
; the XMM registers (xmm0..xmm15)

isXMMReg    macro   parm
            ifidni  <&parm>, <xmm0>
            exitm   <regXMM0>
            endif
            ifidni  <&parm>, <xmm1>
            exitm   <regXMM1>
            endif
            ifidni  <&parm>, <xmm2>
            exitm   <regXMM2>
            endif
            ifidni  <&parm>, <xmm3>
            exitm   <regXMM3>
            endif
            ifidni  <&parm>, <xmm4>
            exitm   <regXMM4>
            endif
            ifidni  <&parm>, <xmm5>
            exitm   <regXMM5>
            endif
            ifidni  <&parm>, <xmm6>
            exitm   <regXMM6>
            endif
            ifidni  <&parm>, <xmm7>
            exitm   <regXMM7>
            endif
            ifidni  <&parm>, <xmm8>
            exitm   <regXMM8>
            endif
            ifidni  <&parm>, <xmm9>
            exitm   <regXMM9>
            endif
            ifidni  <&parm>, <xmm10>
            exitm   <regXMM10>
            endif
            ifidni  <&parm>, <xmm11>
            exitm   <regXMM11>
            endif
            ifidni  <&parm>, <xmm12>
            exitm   <regXMM12>
            endif
            ifidni  <&parm>, <xmm13>
            exitm   <regXMM13>
            endif
            ifidni  <&parm>, <xmm14>
            exitm   <regXMM14>
            endif
            ifidni  <&parm>, <xmm15>
            exitm   <regXMM15>
            endif
            endm    ;isXMMReg       
            
; isYMMReg
;
;  Returns register value for one of
; the YMM registers (ymm0..ymm15)

isYMMReg    macro   parm
            ifidni  <&parm>, <ymm0>
            exitm   <regYMM0>
            endif
            ifidni  <&parm>, <ymm0>
            exitm   <regYMM0>
            endif
            ifidni  <&parm>, <ymm1>
            exitm   <regYMM1>
            endif
            ifidni  <&parm>, <ymm2>
            exitm   <regYMM2>
            endif
            ifidni  <&parm>, <ymm3>
            exitm   <regYMM3>
            endif
            ifidni  <&parm>, <ymm4>
            exitm   <regYMM4>
            endif
            ifidni  <&parm>, <ymm5>
            exitm   <regYMM5>
            endif
            ifidni  <&parm>, <ymm6>
            exitm   <regYMM6>
            endif
            ifidni  <&parm>, <ymm7>
            exitm   <regYMM7>
            endif
            ifidni  <&parm>, <ymm8>
            exitm   <regYMM8>
            endif
            ifidni  <&parm>, <ymm9>
            exitm   <regYMM9>
            endif
            ifidni  <&parm>, <ymm10>
            exitm   <regYMM10>
            endif
            ifidni  <&parm>, <ymm11>
            exitm   <regYMM11>
            endif
            ifidni  <&parm>, <ymm12>
            exitm   <regYMM12>
            endif
            ifidni  <&parm>, <ymm13>
            exitm   <regYMM13>
            endif
            ifidni  <&parm>, <ymm14>
            exitm   <regYMM14>
            endif
            ifidni  <&parm>, <ymm15>
            exitm   <regYMM15>
            endif
            endm    ;isYMMReg       
            
            
; whichReg-
;
;   Translate text register to numeric
; constant.

whichReg    macro   parm
            local   result, text
text        textequ isGPReg(parm)
result      =       &text
            if      result ne regNone
            exitm   %result
            endif
            
text        textequ isFPReg(parm)
result      =       &text
            if      result ne regNone
            exitm   %result
            endif
            
text        textequ isMMReg(parm)
result      =       &text
            if      result ne regNone
            exitm   %result
            endif
            
text        textequ isXMMReg(parm)
result      =       &text
            if      result ne regNone
            exitm   %result
            endif
            
text        textequ isYMMReg(parm)
result      =       &text
            if      result ne regNone
            exitm   %result
            endif
            
            exitm   %regNone
            endm    ;whichReg
            
            
            
; regSize-
;
;   Given a register number, this macro function
; returns the size, in bytes, of that register:

regSize     macro   regNum
            local   rn
rn          =       &regNum
            if      (rn lt regAL)
            exitm   <0>
            endif
            if      (rn le regR15B)
            exitm   <1>
            endif
            if      (rn le regR15W)
            exitm   <2>
            endif
            if      (rn le regR15D)
            exitm   <4>
            endif
            if      (rn le regR15)
            exitm   <8>
            endif
            if      (rn le regST7)
            exitm   <10>
            endif
            if      (rn le regMM7)
            exitm   <8>
            endif
            if      (rn le regXMM15)
            exitm   <16>
            endif
            if      (rn le regYMM15)
            exitm   <32>
            endif
            exitm   <0>
            endm    ;regSize


;************************************************************************
;
; Test calls to all the register macros:

            .code
            mout    Converting register numbers to register text
            mout    8-bit register numbers to text conversion:
            
toAL        textequ toReg( regAL )
            mout    toAL=%toAL
            mov     toAL, 0
            
toBL        textequ toReg( regBL )
            mout    toBL=%toBL
            mov     toBL, 0
            
toCL        textequ toReg( regCL )
            mout    toCL=%toCL
            mov     toCL, 0
            
toDL        textequ toReg( regDL )
            mout    toDL=%toDL
            mov     toDL, 0
            
toAH        textequ toReg( regAH )
            mout    toAH=%toAH
            mov     toAH, 0
            
toBH        textequ toReg( regBH )
            mout    toBH=%toBH
            mov     toBH, 0
            
toCH        textequ toReg( regCH )
            mout    toCH=%toCH
            mov     toCH, 0
            
toDH        textequ toReg( regDH )
            mout    toDH=%toDH
            mov     toDH, 0
            
toSIL       textequ toReg( regSIL )
            mout    toSIL=%toSIL
            mov     toSIL, 0
            
toDIL       textequ toReg( regDIL )
            mout    toDIL=%toDIL
            mov     toDIL, 0
            
toBPL       textequ toReg( regBPL )
            mout    toBPL=%toBPL
            mov     toBPL, 0
            
toSPL       textequ toReg( regSPL )
            mout    toSPL=%toSPL
            mov     toSPL, 0
            
toR8B       textequ toReg( regR8B )
            mout    toR8B=%toR8B
            mov     toR8B, 0
            
toR9B       textequ toReg( regR9B )
            mout    toR9B=%toR9B
            mov     toR9B, 0
            
toR10B      textequ toReg( regR10B )
            mout    toR10B=%toR10B
            mov     toR10B, 0
            
toR11B      textequ toReg( regR11B )
            mout    toR11B=%toR11B
            mov     toR11B, 0
            
toR12B      textequ toReg( regR12B )
            mout    toR12B=%toR12B
            mov     toR12B, 0
            
toR13B      textequ toReg( regR13B )
            mout    toR13B=%toR13B
            mov     toR13B, 0
            
toR14B      textequ toReg( regR14B )
            mout    toR14B=%toR14B
            mov     toR14B, 0
            
toR15B      textequ toReg( regR15B )
            mout    toR15B=%toR15B
            mov     toR15B, 0
            
            
            
            mout    16-bit register numbers to text conversion:
            
toAX        textequ toReg( regAX )
            mout    toAX=%toAX
            mov     toAX, 0
            
toBX        textequ toReg( regBX )
            mout    toBX=%toBX
            mov     toBX, 0
            
toCX        textequ toReg( regCX )
            mout    toCX=%toCX
            mov     toCX, 0
            
toDX        textequ toReg( regDX )
            mout    toDX=%toDX
            mov     toDX, 0
            
toSI        textequ toReg( regSI )
            mout    toSI=%toSI
            mov     toSI, 0
            
toDI        textequ toReg( regDI )
            mout    toDI=%toDI
            mov     toDI, 0
            
toBP        textequ toReg( regBP )
            mout    toBP=%toBP
            mov     toBP, 0
            
toSP        textequ toReg( regSP )
            mout    toSP=%toSP
            mov     toSP, 0
            
toR8W       textequ toReg( regR8W )
            mout    toR8W=%toR8W
            mov     toR8W, 0
            
toR9W       textequ toReg( regR9W )
            mout    toR9W=%toR9W
            mov     toR9W, 0
            
toR10W      textequ toReg( regR10W )
            mout    toR10W=%toR10W
            mov     toR10W, 0
            
toR11W      textequ toReg( regR11W )
            mout    toR11W=%toR11W
            mov     toR11W, 0
            
toR12W      textequ toReg( regR12W )
            mout    toR12W=%toR12W
            mov     toR12W, 0
            
toR13W      textequ toReg( regR13W )
            mout    toR13W=%toR13W
            mov     toR13W, 0
            
toR14W      textequ toReg( regR14W )
            mout    toR14W=%toR14W
            mov     toR14W, 0
            
toR15W      textequ toReg( regR15W )
            mout    toR15W=%toR15W
            mov     toR15W, 0
            
            
            
            mout    32-bit register numbers to text conversion:
            
toEAX       textequ toReg( regEAX )
            mout    toEAX=%toEAX
            mov     toEAX, 0
            
toEBX       textequ toReg( regEBX )
            mout    toEBX=%toEBX
            mov     toEBX, 0
            
toECX       textequ toReg( regECX )
            mout    toECX=%toECX
            mov     toECX, 0
            
toEDX       textequ toReg( regEDX )
            mout    toEDX=%toEDX
            mov     toEDX, 0
            
toESI       textequ toReg( regESI )
            mout    toESI=%toESI
            mov     toESI, 0
            
toEDI       textequ toReg( regEDI )
            mout    toEDI=%toEDI
            mov     toDI, 0
            
toEBP       textequ toReg( regEBP )
            mout    toEBP=%toEBP
            mov     toEBP, 0
            
toESP       textequ toReg( regESP )
            mout    toESP=%toESP
            mov     toESP, 0
            
toR8D       textequ toReg( regR8D )
            mout    toR8D=%toR8D
            mov     toR8D, 0
            
toR9D       textequ toReg( regR9D )
            mout    toR9D=%toR9D
            mov     toR9D, 0
            
toR10D      textequ toReg( regR10D )
            mout    toR10D=%toR10D
            mov     toR10D, 0
            
toR11D      textequ toReg( regR11D )
            mout    toR11D=%toR11D
            mov     toR11D, 0
            
toR12D      textequ toReg( regR12D )
            mout    toR12D=%toR12D
            mov     toR12D, 0
            
toR13D      textequ toReg( regR13D )
            mout    toR13D=%toR13D
            mov     toR13D, 0
            
toR14D      textequ toReg( regR14D )
            mout    toR14D=%toR14D
            mov     toR14D, 0
            
toR15D      textequ toReg( regR15D )
            mout    toR15D=%toR15D
            mov     toR15D, 0
            
            
            
            mout    64-bit register numbers to text conversion:
            
toRAX       textequ toReg( regRAX )
            mout    toRAX=%toRAX
            mov     toRAX, 0
            
toRBX       textequ toReg( regRBX )
            mout    toRBX=%toRBX
            mov     toRBX, 0
            
toRCX       textequ toReg( regRCX )
            mout    toRCX=%toRCX
            mov     toRCX, 0
            
toRDX       textequ toReg( regRDX )
            mout    toRDX=%toRDX
            mov     toRDX, 0
            
toRSI       textequ toReg( regRSI )
            mout    toRSI=%toRSI
            mov     toRSI, 0
            
toRDI       textequ toReg( regRDI )
            mout    toRDI=%toRDI
            mov     toDI, 0
            
toRBP       textequ toReg( regRBP )
            mout    toRBP=%toRBP
            mov     toRBP, 0
            
toRSP       textequ toReg( regRSP )
            mout    toRSP=%toRSP
            mov     toRSP, 0
            
toR8        textequ toReg( regR8 )
            mout    toR8=%toR8
            mov     toR8, 0
            
toR9        textequ toReg( regR9 )
            mout    toR9=%toR9
            mov     toR9, 0
            
toR10       textequ toReg( regR10 )
            mout    toR10=%toR10
            mov     toR10, 0
            
toR11       textequ toReg( regR11 )
            mout    toR11=%toR11
            mov     toR11, 0
            
toR12       textequ toReg( regR12 )
            mout    toR12=%toR12
            mov     toR12, 0
            
toR13       textequ toReg( regR13 )
            mout    toR13=%toR13
            mov     toR13, 0
            
toR14       textequ toReg( regR14 )
            mout    toR14=%toR14
            mov     toR14, 0
            
toR15       textequ toReg( regR15 )
            mout    toR15=%toR15
            mov     toR15, 0


            
            
            
            mout    FPU register number to text conversion
            
toST        textequ toReg( regST )
            mout    toST=%toST
            fadd    toST, st(1)     
            
toST0       textequ toReg( regST0 )
            mout    toST0=%toST0
            fadd    toST0, st(1)    
            
toST1       textequ toReg( regST1 )
            mout    toST1=%toST1
            fadd    st, toST1       
            
toST2       textequ toReg( regST2 )
            mout    toST2=%toST2
            fadd    st, toST2       
            
toST3       textequ toReg( regST3 )
            mout    toST3=%toST3
            fadd    st, toST3       
            
toST4       textequ toReg( regST4 )
            mout    toST4=%toST4
            fadd    st, toST4       
            
toST5       textequ toReg( regST5 )
            mout    toST5=%toST5
            fadd    st, toST5       
            
toST6       textequ toReg( regST6 )
            mout    toST6=%toST6
            fadd    st, toST6       
            
toST7       textequ toReg( regST7 )
            mout    toST7=%toST7
            fadd    st, toST7       


            
            
            
            mout    MMX register number to text conversion
            
toMM0       textequ toReg( regMM0 )
            mout    toMM0=%toMM0
            pand    mm0, toMM0      
            
toMM1       textequ toReg( regMM1 )
            mout    toMM1=%toMM1
            pand    mm0, toMM1      
            
toMM2       textequ toReg( regMM2 )
            mout    toMM2=%toMM2
            pand    mm0, toMM2      
            
toMM3       textequ toReg( regMM3 )
            mout    toMM3=%toMM3
            pand    mm0, toMM3      
            
toMM4       textequ toReg( regMM4 )
            mout    toMM4=%toMM4
            pand    mm0, toMM4      
            
toMM5       textequ toReg( regMM5 )
            mout    toMM5=%toMM5
            pand    mm0, toMM5      
            
toMM6       textequ toReg( regMM6 )
            mout    toMM6=%toMM6
            pand    mm0, toMM6      
            
toMM7       textequ toReg( regMM7 )
            mout    toMM7=%toMM7
            pand    mm0, toMM7      


            
            
            
            mout    XMM register number to text conversion
            
toXMM0      textequ toReg( regXMM0 )
            mout    toXMM0=%toXMM0
            pand    xmm0, toXMM0    
            
toXMM1      textequ toReg( regXMM1 )
            mout    toXMM1=%toXMM1
            pand    xmm0, toXMM1    
            
toXMM2      textequ toReg( regXMM2 )
            mout    toXMM2=%toXMM2
            pand    xmm0, toXMM2    
            
toXMM3      textequ toReg( regXMM3 )
            mout    toXMM3=%toXMM3
            pand    xmm0, toXMM3    
            
toXMM4      textequ toReg( regXMM4 )
            mout    toXMM4=%toXMM4
            pand    xmm0, toXMM4    
            
toXMM5      textequ toReg( regXMM5 )
            mout    toXMM5=%toXMM5
            pand    xmm0, toXMM5    
            
toXMM6      textequ toReg( regXMM6 )
            mout    toXMM6=%toXMM6
            pand    xmm0, toXMM6    
            
toXMM7      textequ toReg( regXMM7 )
            mout    toXMM7=%toXMM7
            pand    xmm0, toXMM7    
            
toXMM8      textequ toReg( regXMM8 )
            mout    toXMM8=%toXMM8
            pand    xmm0, toXMM8    
            
toXMM9      textequ toReg( regXMM9 )
            mout    toXMM9=%toXMM9
            pand    xmm0, toXMM9    
            
toXMM10     textequ toReg( regXMM10 )
            mout    toXMM10=%toXMM10
            pand    xmm0, toXMM10   
            
toXMM11     textequ toReg( regXMM11 )
            mout    toXMM11=%toXMM11
            pand    xmm0, toXMM11   
            
toXMM12     textequ toReg( regXMM12 )
            mout    toXMM12=%toXMM12
            pand    xmm0, toXMM12   
            
toXMM13     textequ toReg( regXMM13 )
            mout    toXMM13=%toXMM13
            pand    xmm0, toXMM13   
            
toXMM14     textequ toReg( regXMM14 )
            mout    toXMM14=%toXMM14
            pand    xmm0, toXMM14   
            
toXMM15     textequ toReg( regXMM15 )
            mout    toXMM15=%toXMM15
            pand    xmm0, toXMM15   


            
            
            
            mout    YMM register number to text conversion
            
toYMM0      textequ toReg( regYMM0 )
            mout    toYMM0=%toYMM0
            vpand   ymm0, ymm0, toYMM0      
            
toYMM1      textequ toReg( regYMM1 )
            mout    toYMM1=%toYMM1
            vpand   ymm0, ymm0, toYMM1      
            
toYMM2      textequ toReg( regYMM2 )
            mout    toYMM2=%toYMM2
            vpand   ymm0, ymm0, toYMM2      
            
toYMM3      textequ toReg( regYMM3 )
            mout    toYMM3=%toYMM3
            vpand   ymm0, ymm0, toYMM3      
            
toYMM4      textequ toReg( regYMM4 )
            mout    toYMM4=%toYMM4
            vpand   ymm0, ymm0, toYMM4      
            
toYMM5      textequ toReg( regYMM5 )
            mout    toYMM5=%toYMM5
            vpand   ymm0, ymm0, toYMM5      
            
toYMM6      textequ toReg( regYMM6 )
            mout    toYMM6=%toYMM6
            vpand   ymm0, ymm0, toYMM6      
            
toYMM7      textequ toReg( regYMM7 )
            mout    toYMM7=%toYMM7
            vpand   ymm0, ymm0, toYMM7      
            
toYMM8      textequ toReg( regYMM8 )
            mout    toYMM8=%toYMM8
            vpand   ymm0, ymm0, toYMM8      
            
toYMM9      textequ toReg( regYMM9 )
            mout    toYMM9=%toYMM9
            vpand   ymm0, ymm0, toYMM9      
            
toYMM10     textequ toReg( regYMM10 )
            mout    toYMM10=%toYMM10
            vpand   ymm0, ymm0, toYMM10     
            
toYMM11     textequ toReg( regYMM11 )
            mout    toYMM11=%toYMM11
            vpand   ymm0, ymm0, toYMM11     
            
toYMM12     textequ toReg( regYMM12 )
            mout    toYMM12=%toYMM12
            vpand   ymm0, ymm0, toYMM12     
            
toYMM13     textequ toReg( regYMM13 )
            mout    toYMM13=%toYMM13
            vpand   ymm0, ymm0, toYMM13     
            
toYMM14     textequ toReg( regYMM14 )
            mout    toYMM14=%toYMM14
            vpand   ymm0, ymm0, toYMM14     
            
toYMM15     textequ toReg( regYMM15 )
            mout    toYMM15=%toYMM15
            vpand   ymm0, ymm0, toYMM15     
            
            
            
            
            mout    8-bit to 16-bit register conversion
            
al2ax       textequ reg8To16( regAL )
            mout    al2ax=%al2ax
            mov     al2ax, 0
            
bl2bx       textequ reg8To16( regBL )
            mout    bl2bx=%bl2bx
            mov     bl2bx, 0
            
cl2cx       textequ reg8To16( regCL )
            mout    cl2cx=%cl2cx
            mov     cl2cx, 0
            
dl2dx       textequ reg8To16( regDL )
            mout    dl2dx=%dl2dx
            mov     dl2dx, 0
            
ah2ax       textequ reg8To16( regAH )
            mout    ah2ax=%ah2ax
            mov     ah2ax, 0
            
bh2bx       textequ reg8To16( regBH )
            mout    bh2bx=%bh2bx
            mov     bh2bx, 0
            
ch2cx       textequ reg8To16( regCH )
            mout    ch2cx=%ch2cx
            mov     ch2cx, 0
            
dh2dx       textequ reg8To16( regDH )
            mout    dh2dx=%dh2dx
            mov     dh2dx, 0
            
sil2si      textequ reg8To16( regSIL )
            mout    sil2si=%sil2si
            mov     sil2si, 0
            
dil2di      textequ reg8To16( regDIL )
            mout    dil2di=%dil2di
            mov     dil2di, 0
            
bpl2bp      textequ reg8To16( regBPL )
            mout    bpl2bp=%bpl2bp
            mov     bpl2bp, 0
            
spl2sp      textequ reg8To16( regSPL )
            mout    spl2sp=%spl2sp
            mov     spl2sp, 0
            
r8b2r8w     textequ reg8To16( regR8B )
            mout    r8b2r8w=%r8b2r8w
            mov     r8b2r8w, 0
            
r9b2r9w     textequ reg8To16( regR9B )
            mout    r9b2r9w=%r9b2r9w
            mov     r9b2r9w, 0
            
r10b2r10w   textequ reg8To16( regR10B )
            mout    r10b2r10w=%r10b2r10w
            mov     r10b2r10w, 0
            
r11b2r11w   textequ reg8To16( regR11B )
            mout    r11b2r11w=%r11b2r11w
            mov     r11b2r11w, 0
            
r12b2r12w   textequ reg8To16( regR12B )
            mout    r12b2r12w=%r12b2r12w
            mov     r12b2r12w, 0
            
r13b2r13w   textequ reg8To16( regR13B )
            mout    r13b2r13w=%r13b2r13w
            mov     r13b2r13w, 0
            
r14b2r14w   textequ reg8To16( regR14B )
            mout    r14b2r14w=%r14b2r14w
            mov     r14b2r14w, 0
            
r15b2r15w   textequ reg8To16( regR15B )
            mout    r15b2r15w=%r15b2r15w
            mov     r15b2r15w, 0
            


            
            
            
            mout    8-bit to 32-bit register conversion
            
al2eax      textequ reg8To32( regAL )
            mout    al2eax=%al2eax
            mov     al2eax, 0
            
bl2ebx      textequ reg8To32( regBL )
            mout    bl2ebx=%bl2ebx
            mov     bl2ebx, 0
            
cl2ecx      textequ reg8To32( regCL )
            mout    cl2ecx=%cl2ecx
            mov     cl2ecx, 0
            
dl2edx      textequ reg8To32( regDL )
            mout    dl2edx=%dl2edx
            mov     dl2edx, 0
            
ah2eax      textequ reg8To32( regAH )
            mout    ah2eax=%ah2eax
            mov     ah2eax, 0
            
bh2ebx      textequ reg8To32( regBH )
            mout    bh2ebx=%bh2ebx
            mov     bh2ebx, 0
            
ch2ecx      textequ reg8To32( regCH )
            mout    ch2ecx=%ch2ecx
            mov     ch2ecx, 0
            
dh2edx      textequ reg8To32( regDH )
            mout    dh2edx=%dh2edx
            mov     dh2edx, 0
            
sil2esi     textequ reg8To32( regSIL )
            mout    sil2esi=%sil2esi
            mov     sil2esi, 0
            
dil2edi     textequ reg8To32( regDIL )
            mout    dil2edi=%dil2edi
            mov     dil2edi, 0
            
bpl2ebp     textequ reg8To32( regBPL )
            mout    bpl2ebp=%bpl2ebp
            mov     bpl2ebp, 0
            
spl2esp     textequ reg8To32( regSPL )
            mout    spl2esp=%spl2esp
            mov     spl2esp, 0
            
r8b2r8d     textequ reg8To32( regR8B )
            mout    r8b2r8d=%r8b2r8d
            mov     r8b2r8d, 0
            
r9b2r9d     textequ reg8To32( regR9B )
            mout    r9b2r9d=%r9b2r9d
            mov     r9b2r9d, 0
            
r10b2r10d   textequ reg8To32( regR10B )
            mout    r10b2r10d=%r10b2r10d
            mov     r10b2r10d, 0
            
r11b2r11d   textequ reg8To32( regR11B )
            mout    r11b2r11d=%r11b2r11d
            mov     r11b2r11d, 0
            
r12b2r12d   textequ reg8To32( regR12B )
            mout    r12b2r12d=%r12b2r12d
            mov     r12b2r12d, 0
            
r13b2r13d   textequ reg8To32( regR13B )
            mout    r13b2r13d=%r13b2r13d
            mov     r13b2r13d, 0
            
r14b2r14d   textequ reg8To32( regR14B )
            mout    r14b2r14d=%r14b2r14d
            mov     r14b2r14d, 0
            
r15b2r15d   textequ reg8To32( regR15B )
            mout    r15b2r15d=%r15b2r15d
            mov     r15b2r15d, 0
            


            
            
            
            mout    8-bit to 64-bit register conversion
            
al2rax      textequ reg8To64( regAL )
            mout    al2rax=%al2rax
            mov     al2rax, 0
            
bl2rbx      textequ reg8To64( regBL )
            mout    bl2rbx=%bl2rbx
            mov     bl2rbx, 0
            
cl2rcx      textequ reg8To64( regCL )
            mout    cl2rcx=%cl2rcx
            mov     cl2rcx, 0
            
dl2rdx      textequ reg8To64( regDL )
            mout    dl2rdx=%dl2rdx
            mov     dl2rdx, 0
            
ah2rax      textequ reg8To64( regAH )
            mout    ah2rax=%ah2rax
            mov     ah2rax, 0
            
bh2rbx      textequ reg8To64( regBH )
            mout    bh2rbx=%bh2rbx
            mov     bh2rbx, 0
            
ch2rcx      textequ reg8To64( regCH )
            mout    ch2rcx=%ch2rcx
            mov     ch2rcx, 0
            
dh2rdx      textequ reg8To64( regDH )
            mout    dh2rdx=%dh2rdx
            mov     dh2rdx, 0
            
sil2rsi     textequ reg8To64( regSIL )
            mout    sil2rsi=%sil2rsi
            mov     sil2rsi, 0
            
dil2rdi     textequ reg8To64( regDIL )
            mout    dil2rdi=%dil2rdi
            mov     dil2rdi, 0
            
bpl2rbp     textequ reg8To64( regBPL )
            mout    bpl2rbp=%bpl2rbp
            mov     bpl2rbp, 0
            
spl2rsp     textequ reg8To64( regSPL )
            mout    spl2rsp=%spl2rsp
            mov     spl2rsp, 0
            
r8b2r8      textequ reg8To64( regR8B )
            mout    r8b2r8=%r8b2r8
            mov     r8b2r8, 0
            
r9b2r9      textequ reg8To64( regR9B )
            mout    r9b2r9=%r9b2r9
            mov     r9b2r9, 0
            
r10b2r10    textequ reg8To64( regR10B )
            mout    r10b2r10=%r10b2r10
            mov     r10b2r10, 0
            
r11b2r11    textequ reg8To64( regR11B )
            mout    r11b2r11=%r11b2r11
            mov     r11b2r11, 0
            
r12b2r12    textequ reg8To64( regR12B )
            mout    r12b2r12=%r12b2r12
            mov     r12b2r12, 0
            
r13b2r13    textequ reg8To64( regR13B )
            mout    r13b2r13=%r13b2r13
            mov     r13b2r13, 0
            
r14b2r14    textequ reg8To64( regR14B )
            mout    r14b2r14=%r14b2r14
            mov     r14b2r14, 0
            
r15b2r15    textequ reg8To64( regR15B )
            mout    r15b2r15=%r15b2r15
            mov     r15b2r15, 0
            


            
            
            
            mout    16-bit to 32-bit register conversion
            
ax2eax      textequ reg16To32( regAX )
            mout    ax2eax=%ax2eax
            mov     ax2eax, 0
            
bx2ebx      textequ reg16To32( regBX )
            mout    bx2ebx=%bx2ebx
            mov     bx2ebx, 0
            
cx2ecx      textequ reg16To32( regCX )
            mout    cx2ecx=%cx2ecx
            mov     cx2ecx, 0
            
dx2edx      textequ reg16To32( regDX )
            mout    dx2edx=%dx2edx
            mov     dx2edx, 0
                    
si2esi      textequ reg16To32( regSI )
            mout    si2esi=%si2esi
            mov     si2esi, 0
            
di2edi      textequ reg16To32( regDI )
            mout    di2edi=%di2edi
            mov     di2edi, 0
            
bp2ebp      textequ reg16To32( regBP )
            mout    bp2ebp=%bp2ebp
            mov     bp2ebp, 0
            
sp2esp      textequ reg16To32( regSP )
            mout    sp2esp=%sp2esp
            mov     sp2esp, 0
            
r8w2r8d     textequ reg16To32( regR8W )
            mout    r8w2r8d=%r8w2r8d
            mov     r8w2r8d, 0
            
r9w2r9d     textequ reg16To32( regR9W )
            mout    r9w2r9d=%r9w2r9d
            mov     r9w2r9d, 0
            
r10w2r10d   textequ reg16To32( regR10W )
            mout    r10w2r10d=%r10w2r10d
            mov     r10w2r10d, 0
            
r11w2r11d   textequ reg16To32( regR11W )
            mout    r11w2r11d=%r11w2r11d
            mov     r11w2r11d, 0
            
r12w2r12d   textequ reg16To32( regR12W )
            mout    r12w2r12d=%r12w2r12d
            mov     r12w2r12d, 0
            
r13w2r13d   textequ reg16To32( regR13W )
            mout    r13w2r13d=%r13w2r13d
            mov     r13w2r13d, 0
            
r14w2r14d   textequ reg16To32( regR14W )
            mout    r14w2r14d=%r14w2r14d
            mov     r14w2r14d, 0
            
r15w2r15d   textequ reg16To32( regR15W )
            mout    r15w2r15d=%r15w2r15d
            mov     r15w2r15d, 0


            
            
            
            mout    16-bit to 64-bit register conversion
            
ax2rax      textequ reg16To64( regAX )
            mout    ax2rax=%ax2rax
            mov     ax2rax, 0
            
bx2rbx      textequ reg16To64( regBX )
            mout    bx2rbx=%bx2rbx
            mov     bx2rbx, 0
            
cx2rcx      textequ reg16To64( regCX )
            mout    cx2rcx=%cx2rcx
            mov     cx2rcx, 0
            
dx2rdx      textequ reg16To64( regDX )
            mout    dx2rdx=%dx2rdx
            mov     dx2rdx, 0
                    
si2rsi      textequ reg16To64( regSI )
            mout    si2rsi=%si2rsi
            mov     si2rsi, 0
            
di2rdi      textequ reg16To64( regDI )
            mout    di2rdi=%di2rdi
            mov     di2rdi, 0
            
bp2rbp      textequ reg16To64( regBP )
            mout    bp2rbp=%bp2rbp
            mov     bp2rbp, 0
            
sp2rsp      textequ reg16To64( regSP )
            mout    sp2rsp=%sp2rsp
            mov     sp2rsp, 0
            
r8w2r8      textequ reg16To64( regR8W )
            mout    r8w2r8=%r8w2r8
            mov     r8w2r8, 0
            
r9w2r9      textequ reg16To64( regR9W )
            mout    r9w2r9=%r9w2r9
            mov     r9w2r9, 0
            
r10w2r10    textequ reg16To64( regR10W )
            mout    r10w2r10=%r10w2r10
            mov     r10w2r10, 0
            
r11w2r11    textequ reg16To64( regR11W )
            mout    r11w2r11=%r11w2r11
            mov     r11w2r11, 0
            
r12w2r12    textequ reg16To64( regR12W )
            mout    r12w2r12=%r12w2r12
            mov     r12w2r12, 0
            
r13w2r13    textequ reg16To64( regR13W )
            mout    r13w2r13=%r13w2r13
            mov     r13w2r13, 0
            
r14w2r14    textequ reg16To64( regR14W )
            mout    r14w2r14=%r14w2r14
            mov     r14w2r14, 0
            
r15w2r15    textequ reg16To64( regR15W )
            mout    r15w2r15=%r15w2r15
            mov     r15w2r15, 0


            
            
            
            mout    32-bit to 64-bit register conversion
            
eax2rax     textequ reg32To64( regEAX )
            mout    eax2rax=%eax2rax
            mov     eax2rax, 0
            
ebx2rbx     textequ reg32To64( regEBX )
            mout    ebx2rbx=%ebx2rbx
            mov     ebx2rbx, 0
            
ecx2rcx     textequ reg32To64( regECX )
            mout    ecx2rcx=%ecx2rcx
            mov     ecx2rcx, 0
            
edx2rdx     textequ reg32To64( regEDX )
            mout    edx2rdx=%edx2rdx
            mov     edx2rdx, 0
                    
esi2rsi     textequ reg32To64( regESI )
            mout    esi2rsi=%esi2rsi
            mov     esi2rsi, 0
            
edi2rdi     textequ reg32To64( regEDI )
            mout    edi2rdi=%edi2rdi
            mov     edi2rdi, 0
            
ebp2rbp     textequ reg32To64( regEBP )
            mout    ebp2rbp=%ebp2rbp
            mov     ebp2rbp, 0
            
esp2rsp     textequ reg32To64( regESP )
            mout    esp2rsp=%esp2rsp
            mov     esp2rsp, 0
            
r8d2r8      textequ reg32To64( regR8D )
            mout    r8d2r8=%r8d2r8
            mov     r8d2r8, 0
            
r9d2r9      textequ reg32To64( regR9D )
            mout    r9d2r9=%r9d2r9
            mov     r9d2r9, 0
            
r10d2r10    textequ reg32To64( regR10D )
            mout    r10d2r10=%r10d2r10
            mov     r10d2r10, 0
            
r11d2r11    textequ reg32To64( regR11D )
            mout    r11d2r11=%r11d2r11
            mov     r11d2r11, 0
            
r12d2r12    textequ reg32To64( regR12D )
            mout    r12d2r12=%r12d2r12
            mov     r12d2r12, 0
            
r13d2r13    textequ reg32To64( regR13D )
            mout    r13d2r13=%r13d2r13
            mov     r13d2r13, 0
            
r14d2r14    textequ reg32To64( regR14D )
            mout    r14d2r14=%r14d2r14
            mov     r14d2r14, 0
            
r15d2r15    textequ reg32To64( regR15D )
            mout    r15d2r15=%r15d2r15
            mov     r15d2r15, 0



            mout    toUpper demonstrations

HelloWorld  textequ toUpper( <Hello, World> )
            mout    HelloWorld=%HelloWorld

LCAlphas    textequ toUpper( abcdefghijklmnopqrstuvwxyz )
            mout    LCAlphas=%LCAlphas

UCAlphas    textequ toUpper( ABCDEFGHIJKLMNOPQRSTUVWXYZ )
            mout    UCAlphas=%UCAlphas

digits      textequ toUpper( 0123456789 )
            mout    digits=%digits



            mout    8-bit isReg tests

isAL        =       isReg( al )
            mout    isAL=%(isAL and 1)
isBL        =       isReg( bl )
            mout    isBL=%(isBL and 1)
isCL        =       isReg( cl )
            mout    isCL=%(isCL and 1)
isDL        =       isReg( dl )
            mout    isDL=%(isDL and 1)
            
isAH        =       isReg( ah )
            mout    isAH=%(isAH and 1)
isBH        =       isReg( bh )
            mout    isBH=%(isBH and 1)
isCH        =       isReg( ch )
            mout    isCH=%(isCH and 1)
isDH        =       isReg( dh )
            mout    isDH=%(isDH and 1)
            
isSIL       =       isReg( sil )
            mout    isSIL=%(isSIL and 1)
isDIL       =       isReg( dil )
            mout    isDIL=%(isDIL and 1)
isBPL       =       isReg( bpl )
            mout    isBPL=%(isBPL and 1)
isSPL       =       isReg( spl )
            mout    isSPL=%(isSPL and 1)
            
isR8B       =       isReg( r8b )
            mout    isR8B=%(isR8B and 1)
isR9B       =       isReg( r9b )
            mout    isR9B=%(isR9B and 1)
isR10B      =       isReg( r10b )
            mout    isR10B=%(isR10B and 1)
isR11B      =       isReg( r11b )
            mout    isR11B=%(isR11B and 1)
isR12B      =       isReg( r12b )
            mout    isR12B=%(isR12B and 1)
isR13B      =       isReg( r13b )
            mout    isR13B=%(isR13B and 1)
isR14B      =       isReg( r14b )
            mout    isR14B=%(isR14B and 1)
isR15B      =       isReg( r15b )
            mout    isR15B=%(isR15B and 1)





            mout    16-bit isReg tests

isAX        =       isReg( ax )
            mout    isAX=%(isAX and 1)
isBX        =       isReg( bx )
            mout    isBX=%(isBX and 1)
isCX        =       isReg( cx )
            mout    isCX=%(isCX and 1)
isDX        =       isReg( dx )
            mout    isDX=%(isDX and 1)
                    
isSI        =       isReg( si )
            mout    isSI=%(isSI and 1)
isDI        =       isReg( di )
            mout    isDI=%(isDI and 1)
isBP        =       isReg( bp )
            mout    isBP=%(isBP and 1)
isSP        =       isReg( sp )
            mout    isSP=%(isSP and 1)
            
isR8W       =       isReg( r8w )
            mout    isR8W=%(isR8W and 1)
isR9W       =       isReg( r9w )
            mout    isR9W=%(isR9W and 1)
isR10W      =       isReg( r10w )
            mout    isR10W=%(isR10W and 1)
isR11W      =       isReg( r11w )
            mout    isR11W=%(isR11W and 1)
isR12W      =       isReg( r12w )
            mout    isR12W=%(isR12W and 1)
isR13W      =       isReg( r13w )
            mout    isR13W=%(isR13W and 1)
isR14W      =       isReg( r14w )
            mout    isR14W=%(isR14W and 1)
isR15W      =       isReg( r15w )
            mout    isR15W=%(isR15W and 1)
            


            mout    8-bit register values
            
alReg       =       is8BitReg( al )
            mout    alReg  = %alReg
blReg       =       is8BitReg( bl )
            mout    blReg  = %blReg
clReg       =       is8BitReg( cl )
            mout    clReg  = %clReg
dlReg       =       is8BitReg( dl )
            mout    dlReg  = %dlReg

ahReg       =       is8BitReg( ah )
            mout    ahReg  = %ahReg
bhReg       =       is8BitReg( bl )
            mout    bhReg  = %bhReg
chReg       =       is8BitReg( ch )
            mout    chReg  = %chReg
dhReg       =       is8BitReg( dh )
            mout    dhReg  = %dhReg

silReg      =       is8BitReg( sil )
            mout    silReg  = %silReg
dilReg      =       is8BitReg( dil )
            mout    dilReg  = %dilReg
bplReg      =       is8BitReg( bpl )
            mout    bplReg  = %bplReg
splReg      =       is8BitReg( spl )
            mout    splReg  = %splReg

r8bReg      =       is8BitReg( r8b )
            mout    r8bReg  = %r8bReg
r9bReg      =       is8BitReg( r9b )
            mout    r9bReg  = %r9bReg
r10bReg     =       is8BitReg( r10b )
            mout    r10bReg  = %r10bReg
r11bReg     =       is8BitReg( r11b )
            mout    r11bReg  = %r11bReg
r12bReg     =       is8BitReg( r12b )
            mout    r12bReg  = %r12bReg
r13bReg     =       is8BitReg( r13b )
            mout    r13bReg  = %r13bReg
r14bReg     =       is8BitReg( r14b )
            mout    r14bReg  = %r14bReg
r15bReg     =       is8BitReg( r15b )
            mout    r15bReg  = %r15bReg


            mout    16-bit Register Values
            
axReg       =       is16BitReg( ax )
            mout    axReg  = %axReg
bxReg       =       is16BitReg( bx )
            mout    bxReg  = %bxReg
cxReg       =       is16BitReg( cx )
            mout    cxReg  = %cxReg
dxReg       =       is16BitReg( dx )
            mout    dxReg  = %dxReg

siReg       =       is16BitReg( si )
            mout    siReg  = %siReg
diReg       =       is16BitReg( di )
            mout    diReg  = %diReg
bpReg       =       is16BitReg( bp )
            mout    bpReg  = %bpReg
spReg       =       is16BitReg( sp )
            mout    spReg  = %spReg

r8wReg      =       is16BitReg( r8w )
            mout    r8wReg  = %r8wReg
r9wReg      =       is16BitReg( r9w )
            mout    r9wReg  = %r9wReg
r10wReg     =       is16BitReg( r10w )
            mout    r10wReg  = %r10wReg
r11wReg     =       is16BitReg( r11w )
            mout    r11wReg  = %r11wReg
r12wReg     =       is16BitReg( r12w )
            mout    r12wReg  = %r12wReg
r13wReg     =       is16BitReg( r13w )
            mout    r13wReg  = %r13wReg
r14wReg     =       is16BitReg( r14w )
            mout    r14wReg  = %r14wReg
r15wReg     =       is16BitReg( r15w )
            mout    r15wReg  = %r15wReg

            mout    32-bit Register Values
            
eaxReg      =       is32BitReg( eax )
            mout    eaxReg  = %eaxReg
ebxReg      =       is32BitReg( ebx )
            mout    ebxReg  = %ebxReg
ecxReg      =       is32BitReg( ecx )
            mout    ecxReg  = %ecxReg
edxReg      =       is32BitReg( edx )
            mout    edxReg  = %edxReg

esiReg      =       is32BitReg( esi )
            mout    esiReg  = %esiReg
ediReg      =       is32BitReg( edi )
            mout    ediReg  = %ediReg
ebpReg      =       is32BitReg( ebp )
            mout    ebpReg  = %ebpReg
espReg      =       is32BitReg( esp )
            mout    espReg  = %espReg

r8dReg      =       is32BitReg( r8d )
            mout    r8dReg  = %r8dReg
r9dReg      =       is32BitReg( r9d )
            mout    r9dReg  = %r9dReg
r10dReg     =       is32BitReg( r10d )
            mout    r10dReg  = %r10dReg
r11dReg     =       is32BitReg( r11d )
            mout    r11dReg  = %r11dReg
r12dReg     =       is32BitReg( r12d )
            mout    r12dReg  = %r12dReg
r13dReg     =       is32BitReg( r13d )
            mout    r13dReg  = %r13dReg
r14dReg     =       is32BitReg( r14d )
            mout    r14dReg  = %r14dReg
r15dReg     =       is32BitReg( r15d )
            mout    r15dReg  = %r15dReg
            
            mout    64-bit Register Values
            
raxReg      =       is64BitReg( rax )
            mout    raxReg  = %raxReg
rbxReg      =       is64BitReg( rbx )
            mout    rbxReg  = %rbxReg
rcxReg      =       is64BitReg( rcx )
            mout    rcxReg  = %rcxReg
rdxReg      =       is64BitReg( rdx )
            mout    rdxReg  = %rdxReg

rsiReg      =       is64BitReg( rsi )
            mout    rsiReg  = %rsiReg
rdiReg      =       is64BitReg( rdi )
            mout    rdiReg  = %rdiReg
rbpReg      =       is64BitReg( rbp )
            mout    rbpReg  = %rbpReg
rspReg      =       is64BitReg( rsp )
            mout    rspReg  = %rspReg

r8Reg       =       is64BitReg( r8 )
            mout    r8Reg  = %r8Reg
r9Reg       =       is64BitReg( r9 )
            mout    r9Reg  = %r9Reg
r10Reg      =       is64BitReg( r10 )
            mout    r10Reg  = %r10Reg
r11Reg      =       is64BitReg( r11 )
            mout    r11Reg  = %r11Reg
r12Reg      =       is64BitReg( r12 )
            mout    r12Reg  = %r12Reg
r13Reg      =       is64BitReg( r13 )
            mout    r13Reg  = %r13Reg
r14Reg      =       is64BitReg( r14 )
            mout    r14Reg  = %r14Reg
r15Reg      =       is64BitReg( r15 )
            mout    r15Reg  = %r15Reg
            
            
            mout    General-Purpose Register Tests
            
gpAL        =       isGPReg( al )
            mout    gpAL  = %gpAL

gpAX        =       isGPReg( ax )
            mout    gpAX  = %gpAX

gpEAX       =       isGPReg( eax )
            mout    gpEAX  = %gpEAX

gpRAX       =       isGPReg( rax )
            mout    gpRAX  = %gpRAX

gpST        =       isGPReg( st )
            mout    gpST  = %gpST
            

            mout    FPU Register Values
            
stReg       =       isFPReg( st )
            mout    stReg  = %stReg
st0Reg      =       isFPReg( st(0) )
            mout    st0Reg  = %st0Reg
st1Reg      =       isFPReg( st(1) )
            mout    st1Reg  = %st1Reg
st2Reg      =       isFPReg( st(2) )
            mout    st2Reg  = %st2Reg
st3Reg      =       isFPReg( st(3) )
            mout    st3Reg  = %st3Reg
st4Reg      =       isFPReg( st(4) )
            mout    st4Reg  = %st4Reg
st5Reg      =       isFPReg( st(5) )
            mout    st5Reg  = %st5Reg
st6Reg      =       isFPReg( st(6) )
            mout    st6Reg  = %st6Reg
st7Reg      =       isFPReg( st(7) )
            mout    st7Reg  = %st7Reg
            

            mout    MMX Register Values
            
mm0Reg      =       isMMReg( mm0 )
            mout    mm0Reg  = %mm0Reg
mm1Reg      =       isMMReg( mm1 )
            mout    mm1Reg  = %mm1Reg
mm2Reg      =       isMMReg( mm2 )
            mout    mm2Reg  = %mm2Reg
mm3Reg      =       isMMReg( mm3 )
            mout    mm3Reg  = %mm3Reg
mm4Reg      =       isMMReg( mm4 )
            mout    mm4Reg  = %mm4Reg
mm5Reg      =       isMMReg( mm5 )
            mout    mm5Reg  = %mm5Reg
mm6Reg      =       isMMReg( mm6 )
            mout    mm6Reg  = %mm6Reg
mm7Reg      =       isMMReg( mm7 )
            mout    mm7Reg  = %mm7Reg
            

            mout    XMM Register Values
            
xmm0Reg     =       isXMMReg( xmm0 )
            mout    xmm0Reg  = %xmm0Reg
xmm1Reg     =       isXMMReg( xmm1 )
            mout    xmm1Reg  = %xmm1Reg
xmm2Reg     =       isXMMReg( xmm2 )
            mout    xmm2Reg  = %xmm2Reg
xmm3Reg     =       isXMMReg( xmm3 )
            mout    xmm3Reg  = %xmm3Reg
xmm4Reg     =       isXMMReg( xmm4 )
            mout    xmm4Reg  = %xmm4Reg
xmm5Reg     =       isXMMReg( xmm5 )
            mout    xmm5Reg  = %xmm5Reg
xmm6Reg     =       isXMMReg( xmm6 )
            mout    xmm6Reg  = %xmm6Reg
xmm7Reg     =       isXMMReg( xmm7 )
            mout    xmm7Reg  = %xmm7Reg
xmm8Reg     =       isXMMReg( xmm8 )
            mout    xmm8Reg  = %xmm8Reg
xmm9Reg     =       isXMMReg( xmm9 )
            mout    xmm9Reg  = %xmm9Reg
xmm10Reg    =       isXMMReg( xmm10 )
            mout    xmm10Reg  = %xmm10Reg
xmm11Reg    =       isXMMReg( xmm11 )
            mout    xmm11Reg  = %xmm11Reg
xmm12Reg    =       isXMMReg( xmm12 )
            mout    xmm12Reg  = %xmm12Reg
xmm13Reg    =       isXMMReg( xmm13 )
            mout    xmm13Reg  = %xmm13Reg
xmm14Reg    =       isXMMReg( xmm14 )
            mout    xmm14Reg  = %xmm14Reg
xmm15Reg    =       isXMMReg( xmm15 )
            mout    xmm15Reg  = %xmm15Reg
            

            mout    YMM Register Values
            
ymm0Reg     =       isYMMReg( ymm0 )
            mout    ymm0Reg  = %ymm0Reg
ymm1Reg     =       isYMMReg( ymm1 )
            mout    ymm1Reg  = %ymm1Reg
ymm2Reg     =       isYMMReg( ymm2 )
            mout    ymm2Reg  = %ymm2Reg
ymm3Reg     =       isYMMReg( ymm3 )
            mout    ymm3Reg  = %ymm3Reg
ymm4Reg     =       isYMMReg( ymm4 )
            mout    ymm4Reg  = %ymm4Reg
ymm5Reg     =       isYMMReg( ymm5 )
            mout    ymm5Reg  = %ymm5Reg
ymm6Reg     =       isYMMReg( ymm6 )
            mout    ymm6Reg  = %ymm6Reg
ymm7Reg     =       isYMMReg( ymm7 )
            mout    ymm7Reg  = %ymm7Reg
ymm8Reg     =       isYMMReg( ymm8 )
            mout    ymm8Reg  = %ymm8Reg
ymm9Reg     =       isYMMReg( ymm9 )
            mout    ymm9Reg  = %ymm9Reg
ymm10Reg    =       isYMMReg( ymm10 )
            mout    ymm10Reg  = %ymm10Reg
ymm11Reg    =       isYMMReg( ymm11 )
            mout    ymm11Reg  = %ymm11Reg
ymm12Reg    =       isYMMReg( ymm12 )
            mout    ymm12Reg  = %ymm12Reg
ymm13Reg    =       isYMMReg( ymm13 )
            mout    ymm13Reg  = %ymm13Reg
ymm14Reg    =       isYMMReg( ymm14 )
            mout    ymm14Reg  = %ymm14Reg
ymm15Reg    =       isYMMReg( ymm15 )
            mout    ymm15Reg  = %ymm15Reg


            mout    whichReg- generic register encoding
            
whAL        textequ whichReg( al )
            mout    whAL  = %whAL
            
wAX         textequ whichReg( ax )
            mout    wAX  = %wAX
            
wEAX        textequ whichReg( eax )
            mout    wEAX  = %wEAX
            
wRAX        textequ whichReg( rax )
            mout    wRAX  = %wRAX
            
wST         textequ whichReg( st )
            mout    wST  = %wST
            
wMM0        textequ whichReg( mm0 )
            mout    wMM0  = %wMM0
            
wXMM0       textequ whichReg( xmm0 )
            mout    wXMM0  = %wXMM0
            
wYMM0       textequ whichReg( ymm0 )
            mout    wYMM0  = %wYMM0
            
wNotReg     textequ whichReg( notAReg )
            mout    wNotReg  = %wNotReg
            


            mout    regSize- Computing register size in bytes
            
rsAL        =       regSize( regAL )
            mout    rsAL  = %rsAL
            
rsAX        =       regSize( regAX )
            mout    rsAX  = %rsAX
            
rsEAX       =       regSize( regEAX )
            mout    rsEAX  = %rsEAX
            
rsRAX       =       regSize( regRAX )
            mout    rsRAX  = %rsRAX
            
rsST        =       regSize( regST )
            mout    rsST  = %rsST
            
rsMM0       =       regSize( regMM0 )
            mout    rsMM0  = %rsMM0
            
rsXMM0      =       regSize( regXMM0 )
            mout    rsXMM0  = %rsXMM0
            
rsYMM0      =       regSize( regYMM0 )
            mout    rsYMM0  = %rsYMM0
            
rsNotReg    =       regSize( regNone )
            mout    rsNotReg  = %rsNotReg
            end                
  • Below is an example of implementation of the opattr register check

putint Macro (Implementation)
; Demonstration of putInt macro

        option  casemap:none

nl          =       10

            .const
	include	print.inc

; Register values:

regNone     =       0
regAL       =       1
regBL       =       2
regCL       =       3
regDL       =       4
regAH       =       5
regBH       =       6
regCH       =       7
regDH       =       8
regSIL      =       9
regDIL      =       10
regBPL      =       11
regSPL      =       12
regR8B      =       13
regR9B      =       14
regR10B     =       15
regR11B     =       16
regR12B     =       17
regR13B     =       18
regR14B     =       19
regR15B     =       20

regAX       =       21
regBX       =       22
regCX       =       23
regDX       =       24
regSI       =       25
regDI       =       26
regBP       =       27
regSP       =       28
regR8W      =       29
regR9W      =       30
regR10W     =       31
regR11W     =       32
regR12W     =       33
regR13W     =       34
regR14W     =       35
regR15W     =       36

regEAX      =       37
regEBX      =       38
regECX      =       39
regEDX      =       40
regESI      =       41
regEDI      =       42
regEBP      =       43
regESP      =       44
regR8D      =       45
regR9D      =       46
regR10D     =       47
regR11D     =       48
regR12D     =       49
regR13D     =       50
regR14D     =       51
regR15D     =       52

regRAX      =       53
regRBX      =       54
regRCX      =       55
regRDX      =       56
regRSI      =       57
regRDI      =       58
regRBP      =       59
regRSP      =       60
regR8       =       61
regR9       =       62
regR10      =       63
regR11      =       64
regR12      =       65
regR13      =       66
regR14      =       67
regR15      =       68

regST       =       69
regST0      =       70
regST1      =       71
regST2      =       72
regST3      =       73
regST4      =       74
regST5      =       75
regST6      =       76
regST7      =       77

regMM0      =       78
regMM1      =       79
regMM2      =       80
regMM3      =       81
regMM4      =       82
regMM5      =       83
regMM6      =       84
regMM7      =       85

regXMM0     =       86
regXMM1     =       87
regXMM2     =       88
regXMM3     =       89
regXMM4     =       90
regXMM5     =       91
regXMM6     =       92
regXMM7     =       93
regXMM8     =       94
regXMM9     =       95
regXMM10    =       96
regXMM11    =       97
regXMM12    =       98
regXMM13    =       99
regXMM14    =       100
regXMM15    =       101

regYMM0     =       102
regYMM1     =       103
regYMM2     =       104
regYMM3     =       105
regYMM4     =       106
regYMM5     =       107
regYMM6     =       108
regYMM7     =       109
regYMM8     =       110
regYMM9     =       111
regYMM10    =       112
regYMM11    =       113
regYMM12    =       114
regYMM13    =       115
regYMM14    =       116
regYMM15    =       117

; Left to the reader:
; Implement ZMM registers.
; Implement system and special-purpose registers.




; The following text equates allow
; this code to turn a register
; number (the equates above)
; into a register name.

toReg       macro   regNum
            local   register
register    catstr  <reg>,%regNum
            exitm   &register
            endm    ;toReg
                            
reg0        textequ <>
reg1        textequ <al>
reg2        textequ <bl>            
reg3        textequ <cl>
reg4        textequ <dl>
reg5        textequ <ah>
reg6        textequ <bh>
reg7        textequ <ch>
reg8        textequ <dh>
reg9        textequ <sil>
reg10       textequ <dil>
reg11       textequ <bpl>
reg12       textequ <spl>
reg13       textequ <r8b>
reg14       textequ <r9b>
reg15       textequ <r10b>
reg16       textequ <r11b>
reg17       textequ <r12b>
reg18       textequ <r13b>
reg19       textequ <r14b>
reg20       textequ <r15b>

reg21       textequ <ax>  
reg22       textequ <bx>  
reg23       textequ <cx>  
reg24       textequ <dx>  
reg25       textequ <si>  
reg26       textequ <di>  
reg27       textequ <bp>  
reg28       textequ <sp>  
reg29       textequ <r8w> 
reg30       textequ <r9w> 
reg31       textequ <r10w>
reg32       textequ <r11w>
reg33       textequ <r12w>
reg34       textequ <r13w>
reg35       textequ <r14w>
reg36       textequ <r15w>

reg37       textequ <EAX> 
reg38       textequ <EBX> 
reg39       textequ <ECX> 
reg40       textequ <EDX> 
reg41       textequ <ESI> 
reg42       textequ <EDI> 
reg43       textequ <EBP> 
reg44       textequ <ESP> 
reg45       textequ <R8D> 
reg46       textequ <R9D> 
reg47       textequ <R10D>
reg48       textequ <R11D>
reg49       textequ <R12D>
reg50       textequ <R13D>
reg51       textequ <R14D>
reg52       textequ <R15D>

reg53       textequ <RAX>
reg54       textequ <RBX>
reg55       textequ <RCX>
reg56       textequ <RDX>
reg57       textequ <RSI>
reg58       textequ <RDI>
reg59       textequ <RBP>
reg60       textequ <RSP>
reg61       textequ <R8>
reg62       textequ <R9>
reg63       textequ <R10>
reg64       textequ <R11>
reg65       textequ <R12>
reg66       textequ <R13>
reg67       textequ <R14>
reg68       textequ <R15>

reg69       textequ <ST>          
reg70       textequ <ST(0)>         
reg71       textequ <ST(1)>         
reg72       textequ <ST(2)>         
reg73       textequ <ST(3)>         
reg74       textequ <ST(4)>         
reg75       textequ <ST(5)>         
reg76       textequ <ST(6)>         
reg77       textequ <ST(7)>         

reg78       textequ <MM0>         
reg79       textequ <MM1>         
reg80       textequ <MM2>         
reg81       textequ <MM3>         
reg82       textequ <MM4>         
reg83       textequ <MM5>         
reg84       textequ <MM6>         
reg85       textequ <MM7>         

reg86       textequ <XMM0>        
reg87       textequ <XMM1>        
reg88       textequ <XMM2>        
reg89       textequ <XMM3>        
reg90       textequ <XMM4>        
reg91       textequ <XMM5>        
reg92       textequ <XMM6>        
reg93       textequ <XMM7>        
reg94       textequ <XMM8>        
reg95       textequ <XMM9>        
reg96       textequ <XMM10>       
reg97       textequ <XMM11>       
reg98       textequ <XMM12>       
reg99       textequ <XMM13>       
reg100      textequ <XMM14>       
reg101      textequ <XMM15>       

reg102      textequ <YMM0>        
reg103      textequ <YMM1>        
reg104      textequ <YMM2>        
reg105      textequ <YMM3>        
reg106      textequ <YMM4>        
reg107      textequ <YMM5>        
reg108      textequ <YMM6>        
reg109      textequ <YMM7>        
reg110      textequ <YMM8>        
reg111      textequ <YMM9>        
reg112      textequ <YMM10>       
reg113      textequ <YMM11>       
reg114      textequ <YMM12>       
reg115      textequ <YMM13>       
reg116      textequ <YMM14>       
reg117      textequ <YMM15>       


; The following equates allow
; this code to map an 8-bit
; register to its corresponding
; 16-bit register:

reg8To16    macro   reg8
            local   register
register    catstr  <m8_16_>,%reg8
            exitm   &register
            endm    ;toReg

m8_16_1     textequ <ax>    ;Maps al to ax
m8_16_2     textequ <bx>    ;Maps bl to bx
m8_16_3     textequ <cx>    ;Maps cl to cx
m8_16_4     textequ <dx>    ;Maps dl to dx
m8_16_5     textequ <ax>    ;Maps ah to ax
m8_16_6     textequ <bx>    ;Maps bh to bx
m8_16_7     textequ <cx>    ;Maps ch to cx
m8_16_8     textequ <dx>    ;Maps dh to dx
m8_16_9     textequ <si>    ;Maps sil to si
m8_16_10    textequ <di>    ;Maps dil to di
m8_16_11    textequ <bp>    ;Maps bpl to bp
m8_16_12    textequ <sp>    ;Maps spl to sp
m8_16_13    textequ <r8w>   ;Maps r8b to r8w
m8_16_14    textequ <r9w>   ;Maps r9b to r9w
m8_16_15    textequ <r10w>  ;Maps r10b to r10w
m8_16_16    textequ <r11w>  ;Maps r11b to r11w
m8_16_17    textequ <r12w>  ;Maps r12b to r12w
m8_16_18    textequ <r13w>  ;Maps r13b to r13w
m8_16_19    textequ <r14w>  ;Maps r14b to r14w
m8_16_20    textequ <r15w>  ;Maps r15b to r15w

; The following equates allow
; this code to map an 8-bit
; register to its corresponding
; 32-bit register:

reg8To32    macro   reg8
            local   register
register    catstr  <m8_32_>,%reg8
            exitm   &register
            endm    ;toReg

m8_32_1     textequ <eax>   ;Maps al to eax
m8_32_2     textequ <ebx>   ;Maps bl to ebx
m8_32_3     textequ <ecx>   ;Maps cl to ecx
m8_32_4     textequ <edx>   ;Maps dl to edx
m8_32_5     textequ <eax>   ;Maps ah to eax
m8_32_6     textequ <ebx>   ;Maps bh to ebx
m8_32_7     textequ <ecx>   ;Maps ch to ecx
m8_32_8     textequ <edx>   ;Maps dh to edx
m8_32_9     textequ <esi>   ;Maps sil to esi
m8_32_10    textequ <edi>   ;Maps dil to edi
m8_32_11    textequ <ebp>   ;Maps bpl to ebp
m8_32_12    textequ <esp>   ;Maps spl to esp
m8_32_13    textequ <r8d>   ;Maps r8b to r8d
m8_32_14    textequ <r9d>   ;Maps r9b to r9d
m8_32_15    textequ <r10d>  ;Maps r10b to r10d
m8_32_16    textequ <r11d>  ;Maps r11b to r11d
m8_32_17    textequ <r12d>  ;Maps r12b to r12d
m8_32_18    textequ <r13d>  ;Maps r13b to r13d
m8_32_19    textequ <r14d>  ;Maps r14b to r14d
m8_32_20    textequ <r15d>  ;Maps r15b to r15d

; The following equates allow
; this code to map an 8-bit
; register to its corresponding
; 32-bit register:

reg8To64    macro   reg8
            local   register
register    catstr  <m8_64_>,%reg8
            exitm   &register
            endm    ;toReg

m8_64_1     textequ <rax>   ;Maps al to rax
m8_64_2     textequ <rbx>   ;Maps bl to rbx
m8_64_3     textequ <rcx>   ;Maps cl to rcx
m8_64_4     textequ <rdx>   ;Maps dl to rdx
m8_64_5     textequ <rax>   ;Maps ah to rax
m8_64_6     textequ <rbx>   ;Maps bh to rbx
m8_64_7     textequ <rcx>   ;Maps ch to rcx
m8_64_8     textequ <rdx>   ;Maps dh to rdx
m8_64_9     textequ <rsi>   ;Maps sil to rsi
m8_64_10    textequ <rdi>   ;Maps dil to rdi
m8_64_11    textequ <rbp>   ;Maps bpl to rbp
m8_64_12    textequ <rsp>   ;Maps spl to rsp
m8_64_13    textequ <r8>    ;Maps r8b to r8
m8_64_14    textequ <r9>    ;Maps r9b to r9
m8_64_15    textequ <r10>   ;Maps r10b to r10
m8_64_16    textequ <r11>   ;Maps r11b to r11
m8_64_17    textequ <r12>   ;Maps r12b to r12
m8_64_18    textequ <r13>   ;Maps r13b to r13
m8_64_19    textequ <r14>   ;Maps r14b to r14
m8_64_20    textequ <r15>   ;Maps r15b to r15



; The following equates allow
; this code to map a 16-bit
; register to its corresponding
; 32-bit register:

reg16To32   macro   reg16
            local   register
register    catstr  <m16_32_>,%reg16
            exitm   &register
            endm    ;toReg

m16_32_21   textequ <eax>   ;Maps ax to eax
m16_32_22   textequ <ebx>   ;Maps bx to ebx
m16_32_23   textequ <ecx>   ;Maps cx to ecx
m16_32_24   textequ <edx>   ;Maps dx to edx
m16_32_25   textequ <esi>   ;Maps si to esi
m16_32_26   textequ <edi>   ;Maps di to edi
m16_32_27   textequ <ebp>   ;Maps bp to ebp
m16_32_28   textequ <esp>   ;Maps sp to esp
m16_32_29   textequ <r8d>   ;Maps r8w to r8d
m16_32_30   textequ <r9d>   ;Maps r9w to r9d
m16_32_31   textequ <r10d>  ;Maps r10w to r10d
m16_32_32   textequ <r11d>  ;Maps r11w to r11d
m16_32_33   textequ <r12d>  ;Maps r12w to r12d
m16_32_34   textequ <r13d>  ;Maps r13w to r13d
m16_32_35   textequ <r14d>  ;Maps r14w to r14d
m16_32_36   textequ <r15d>  ;Maps r15w to r15d



; The following equates allow
; this code to map a 16-bit
; register to its corresponding
; 64-bit register:

reg16To64   macro   reg16
            local   register
register    catstr  <m16_64_>,%reg16
            exitm   &register
            endm    ;toReg

m16_64_21   textequ <rax>   ;Maps ax to rax
m16_64_22   textequ <rbx>   ;Maps bx to rbx
m16_64_23   textequ <rcx>   ;Maps cx to rcx
m16_64_24   textequ <rdx>   ;Maps dx to rdx
m16_64_25   textequ <rsi>   ;Maps si to rsi
m16_64_26   textequ <rdi>   ;Maps di to rdi
m16_64_27   textequ <rbp>   ;Maps bp to rbp
m16_64_28   textequ <rsp>   ;Maps sp to rsp
m16_64_29   textequ <r8>    ;Maps r8w to r8
m16_64_30   textequ <r9>    ;Maps r9w to r9
m16_64_31   textequ <r10>   ;Maps r10w to r10
m16_64_32   textequ <r11>   ;Maps r11w to r11
m16_64_33   textequ <r12>   ;Maps r12w to r12
m16_64_34   textequ <r13>   ;Maps r13w to r13
m16_64_35   textequ <r14>   ;Maps r14w to r14
m16_64_36   textequ <r15>   ;Maps r15w to r15



; The following equates allow
; this code to map a 32-bit
; register to its corresponding
; 64-bit register:

reg32To64   macro   reg32
            local   register
register    catstr  <m32_64_>,%reg32
            exitm   &register
            endm    ;toReg

m32_64_37   textequ <rax>   ;Maps eax to rax
m32_64_38   textequ <rbx>   ;Maps ebx to rbx
m32_64_39   textequ <rcx>   ;Maps ecx to rcx
m32_64_40   textequ <rdx>   ;Maps edx to rdx
m32_64_41   textequ <rsi>   ;Maps esi to rsi
m32_64_42   textequ <rdi>   ;Maps edi to rdi
m32_64_43   textequ <rbp>   ;Maps ebp to rbp
m32_64_44   textequ <rsp>   ;Maps esp to rsp
m32_64_45   textequ <r8>    ;Maps r8d to r8
m32_64_46   textequ <r9>    ;Maps r9d to r9
m32_64_47   textequ <r10>   ;Maps r10d to r10
m32_64_48   textequ <r11>   ;Maps r11d to r11
m32_64_49   textequ <r12>   ;Maps r12d to r12
m32_64_50   textequ <r13>   ;Maps r13d to r13
m32_64_51   textequ <r14>   ;Maps r14d to r14
m32_64_52   textequ <r15>   ;Maps r15d to r15
                    



; mout-
;
;  Replacement for echo. Allows "%" operator
; in operand field to expand text symbols.

mout        macro   valToPrint
            local   cmd
cmd         catstr  <echo >, <valToPrint>
            cmd
            endm


            
; toUpper
;
;   Converts alphabetic characters to upper case
;   in a text string

toUpper     macro   lcStr
            local   result
            
; Build the result string in "result":

result      textequ <>

; For each character in the source string, conver it to upper case.

            forc    eachChar, <lcStr>

; See if we have a lower case character:

            if      ('&eachChar' ge 'a') and ('&eachChar' le 'z')
            
; If lower case, convert it to the symbol "lc_*" where "*"
; is the lower case character. The equates below will map
; this character to upper case:

eachChar    catstr  <lc_>,<eachChar>
result      catstr  result, &eachChar

            else
            
; If it wasn't a lower case character, just append it
; to the end of the string:

result      catstr  result, <eachChar>

            endif
            endm    ;forc
            exitm   result  ;Return result string
            endm    ;toUpper
            
lc_a        textequ <A>
lc_b        textequ <B>
lc_c        textequ <C>
lc_d        textequ <D>
lc_e        textequ <E>
lc_f        textequ <F>
lc_g        textequ <G>
lc_h        textequ <H>
lc_i        textequ <I>
lc_j        textequ <J>
lc_k        textequ <K>
lc_l        textequ <L>
lc_m        textequ <M>
lc_n        textequ <N>
lc_o        textequ <O>
lc_p        textequ <P>
lc_q        textequ <Q>
lc_r        textequ <R>
lc_s        textequ <S>
lc_t        textequ <T>
lc_u        textequ <U>
lc_v        textequ <V>
lc_w        textequ <W>
lc_x        textequ <X>
lc_y        textequ <Y>
lc_z        textequ <Z>

; isReg-
;
;   Returns true if operand is a register
;   (any register type)

isReg       macro   parm
            local   result
result      textequ %(((opattr &parm) and 10h) eq 10h)
            exitm   <&result>
            endm    ;isReg
 
;--------------------------------------------------------
; lookupReg:
;
; Given a (suspected) register and a lookup table, convert
; that register to the corresponding numeric form.

lookupReg   macro   theReg, regList, regIndex
            local   regUpper, regConst, inst, regLen, indexLen

; Convert (possible) register to upper case:

regUpper    textequ toUpper( theReg )
regLen      sizestr <&theReg>

; Does it exist in regList? If not, it's not a register.

inst        instr   1, regList, &regUpper
            if      inst ne 0

regConst    substr  &regIndex, inst, 1
            if      &regConst eq regLen
            
; It's a  register (in text form). Create an identifier of
; the form "regXX" where "XX" represents the register name:

regConst    catStr  <reg>,regUpper

            ifdef   &regConst

; Return "regXX" as function result. This is the numeric value
; for the register.

            exitm   regConst
            endif
            endif
            endif

; If the parameter string wasn't in regList, then return
; "regNone" as the function result:

            exitm   <regNone>
            endm    ;lookupReg

;------------------------------------------------------------------------------           
; is8BitReg
;
;  Returns reg numeric value if an 8-bit register,
; returns 0 (regNone) if not an 8-bit register.
;
; all8BitRegs is a string with all the 8-bit registers listed (must be upper case).
; all8Lengths is an array of 1-digit register lengths. The index into the string
; matches the starting index of each register in all8BitRegs.

all8BitRegs textequ <ALBLCLDLAHBHCHDHSILDILBPLSPLR8BR9BR10BR11BR12BR13BR14BR15B>
all8Lengths textequ <2020202020202020300300300300300300400040004000400040004000>

is8BitReg   macro   parm
            exitm   lookupReg( parm, all8BitRegs, all8Lengths )
            endm    ;is8BitReg
            

;-------------------------------------------------------------------------------            
; is16BitReg
;
;  Returns reg numeric value if a 16-bit register,
; returns 0 (regNone) if not an 16-bit register.

all16Regs   textequ <AXBXCXDXSIDIBPSPR8WR9WR10WR11WR12WR13WR14WR15W>
all16Lens   textequ <2020202020202020300300400040004000400040004000>

is16BitReg  macro   parm
            exitm   lookupReg( parm, all16Regs, all16Lens )
            endm    ;is16BitReg



;-------------------------------------------------            
; is32BitReg
;
;  Returns reg numeric value if a 32-bit register,
; returns 0 (regNone) if not an 32-bit register.

all32Regs   textequ <EAXEBXECXEDXESIEDIEBPESPR8DR9DR10DR11DR12DR13DR14DR15D>
all32Lens   textequ <300300300300300300300300300300400040004000400040004000>

is32BitReg  macro   parm
            exitm   lookupReg( parm, all32Regs, all32Lens )
            endm    ;is32BitReg


            
; is64BitReg
;
;  Returns reg numeric value if a 64-bit register,
; returns 0 (regNone) if not an 64-bit register.

all64Regs   textequ <RAXRBXRCXRDXRSIRDIRBPRSPR8R9R10R11R12R13R14R15>
all64Lens   textequ <3003003003003003003003002020300300300300300300>

is64BitReg  macro   parm
            exitm   lookupReg( parm, all64Regs, all64Lens )
            endm    ;is64BitReg


; isGPReg-
;
;   Returns the register number constant if
; the register is a general-purpose (8-, 16-,
; 32-, or 64-bit) register.

isGPReg     macro   parm
            local   text

text        textequ is8BitReg(parm)
            if      &text ne regNone
            exitm   text
            endif
                        
text        textequ is16BitReg(parm)
            if      &text ne regNone
            exitm   text
            endif
                        
text        textequ is32BitReg(parm)
            if      &text ne regNone
            exitm   text
            endif
                        
text        textequ is64BitReg(parm)
            if      &text ne regNone
            exitm   text
            endif
                        
            exitm   <0>
            endm    ;isGPReg
            

; isFPReg-
;
;  True if the parameter is one of the
; FPU registers (ST, ST(0), ST(1), etc)
;
; Note that isFPReg returns regST0 for
; the text "ST". If you need to differentiate
; ST and ST(0), you will need to keep the
; original parameter text around.
;
; Because FPU registers have a funny syntax,
; we have to brute-force compare against them.


isFPReg     macro   parm
            ifidni  <&parm>, <st>
            exitm   <regST>
            endif
            ifidni  <&parm>, <ST(0)>
            exitm   <regST0>
            endif
            ifidni  <&parm>, <ST(1)>
            exitm   <regST1>
            endif
            ifidni  <&parm>, <ST(2)>
            exitm   <regST2>
            endif
            ifidni  <&parm>, <ST(3)>
            exitm   <regST3>
            endif
            ifidni  <&parm>, <ST(4)>
            exitm   <regST4>
            endif
            ifidni  <&parm>, <ST(5)>
            exitm   <regST5>
            endif
            ifidni  <&parm>, <ST(6)>
            exitm   <regST6>
            endif
            ifidni  <&parm>, <ST(7)>
            exitm   <regST7>
            endif

            endm    ;isFPReg

; isMMReg
;
;  Returns register value for one of
; the MMX registers (mm0..mm15)

allMMRegs   textequ <MM0MM1MM2MM3MM4MM5MM6MM7>
allMMLens   textequ <300300300300300300300300>

isMMReg     macro   parm
            exitm   lookupReg( parm, allMMRegs, allMMLens )
            endm    ;isMMReg        
            
; isXMMReg
;
;  Returns register value for one of
; the XMM registers (xmm0..xmm15)

isXMMReg    macro   parm
            ifidni  <&parm>, <xmm0>
            exitm   <regXMM0>
            endif
            ifidni  <&parm>, <xmm0>
            exitm   <regXMM0>
            endif
            ifidni  <&parm>, <xmm1>
            exitm   <regXMM1>
            endif
            ifidni  <&parm>, <xmm2>
            exitm   <regXMM2>
            endif
            ifidni  <&parm>, <xmm3>
            exitm   <regXMM3>
            endif
            ifidni  <&parm>, <xmm4>
            exitm   <regXMM4>
            endif
            ifidni  <&parm>, <xmm5>
            exitm   <regXMM5>
            endif
            ifidni  <&parm>, <xmm6>
            exitm   <regXMM6>
            endif
            ifidni  <&parm>, <xmm7>
            exitm   <regXMM7>
            endif
            ifidni  <&parm>, <xmm8>
            exitm   <regXMM8>
            endif
            ifidni  <&parm>, <xmm9>
            exitm   <regXMM9>
            endif
            ifidni  <&parm>, <xmm10>
            exitm   <regXMM10>
            endif
            ifidni  <&parm>, <xmm11>
            exitm   <regXMM11>
            endif
            ifidni  <&parm>, <xmm12>
            exitm   <regXMM12>
            endif
            ifidni  <&parm>, <xmm13>
            exitm   <regXMM13>
            endif
            ifidni  <&parm>, <xmm14>
            exitm   <regXMM14>
            endif
            ifidni  <&parm>, <xmm15>
            exitm   <regXMM15>
            endif
            endm    ;isXMMReg       
            
; isYMMReg
;
;  Returns register value for one of
; the YMM registers (ymm0..ymm15)

isYMMReg    macro   parm
            ifidni  <&parm>, <ymm0>
            exitm   <regYMM0>
            endif
            ifidni  <&parm>, <ymm0>
            exitm   <regYMM0>
            endif
            ifidni  <&parm>, <ymm1>
            exitm   <regYMM1>
            endif
            ifidni  <&parm>, <ymm2>
            exitm   <regYMM2>
            endif
            ifidni  <&parm>, <ymm3>
            exitm   <regYMM3>
            endif
            ifidni  <&parm>, <ymm4>
            exitm   <regYMM4>
            endif
            ifidni  <&parm>, <ymm5>
            exitm   <regYMM5>
            endif
            ifidni  <&parm>, <ymm6>
            exitm   <regYMM6>
            endif
            ifidni  <&parm>, <ymm7>
            exitm   <regYMM7>
            endif
            ifidni  <&parm>, <ymm8>
            exitm   <regYMM8>
            endif
            ifidni  <&parm>, <ymm9>
            exitm   <regYMM9>
            endif
            ifidni  <&parm>, <ymm10>
            exitm   <regYMM10>
            endif
            ifidni  <&parm>, <ymm11>
            exitm   <regYMM11>
            endif
            ifidni  <&parm>, <ymm12>
            exitm   <regYMM12>
            endif
            ifidni  <&parm>, <ymm13>
            exitm   <regYMM13>
            endif
            ifidni  <&parm>, <ymm14>
            exitm   <regYMM14>
            endif
            ifidni  <&parm>, <ymm15>
            exitm   <regYMM15>
            endif
            endm    ;isYMMReg       
            
            
; whichReg-
;
;   Translate text register to numeric
; constant.

whichReg    macro   parm
            local   result, text
text        textequ isGPReg(parm)
result      =       &text
            if      result ne regNone
            exitm   %result
            endif
            
text        textequ isFPReg(parm)
result      =       &text
            if      result ne regNone
            exitm   %result
            endif
            
text        textequ isMMReg(parm)
result      =       &text
            if      result ne regNone
            exitm   %result
            endif
            
text        textequ isXMMReg(parm)
result      =       &text
            if      result ne regNone
            exitm   %result
            endif
            
text        textequ isYMMReg(parm)
result      =       &text
            if      result ne regNone
            exitm   %result
            endif
            
            exitm   %regNone
            endm    ;whichReg
            
            
            
; regSize-
;
;   Given a register number, this macro function
; returns the size, in bytes, of that register:

regSize     macro   regNum
            local   rn
rn          =       &regNum
            if      (rn lt regAL)
            exitm   <0>
            endif
            if      (rn le regR15B)
            exitm   <1>
            endif
            if      (rn le regR15W)
            exitm   <2>
            endif
            if      (rn le regR15D)
            exitm   <4>
            endif
            if      (rn le regR15)
            exitm   <8>
            endif
            if      (rn le regST7)
            exitm   <10>
            endif
            if      (rn le regMM7)
            exitm   <8>
            endif
            if      (rn le regXMM15)
            exitm   <16>
            endif
            if      (rn le regYMM15)
            exitm   <32>
            endif
            exitm   <0>
            endm    ;regSize


;************************************************************************
;
            .code


; putInt
;
;  This macro expects an 8-, 16-, or 32-bit
; general-purpose register argument. It will
; print the value of that register as an
; integer.

putInt      macro   theReg
            local   regVal, sz
regVal      =       isGPReg(theReg)

; Before we do anything else, make sure
; we were actually passed a register:

            if      regVal eq regNone
            .err    <Expected a register>
            endif

; Get the size of the register so we can
; determine if we need to sign extend its
; value:
            
sz          =       regSize(regVal)

; If it was a 64-bit register, report an
; error:

            if      sz gt 4
            .err    <64-bit register not allowed>
            endif

; If it's a 1- or 2-byte register, we will need
; to sign extend the value into EDX:
            
            if      (sz eq 1) or (sz eq 2)
            movsx   edx, theReg
            
; If it's a 32-bit, but is not EDX, we need
; to move it into EDX (don't bother emitting
; the instruction if the register is EDX-
; the data is already where we want it):
 
            elseif  regVal ne regEDX
            mov     edx, theReg
            endif
            
; Print the value in EDX as an integer:

            call    print
            byte    "%d", 0
            endm
                        
                    
            
; Here is the "asmMain" function.

        
            public  asmMain
asmMain     proc
            push    rbx
            push    rbp
            mov     rbp, rsp
            sub     rsp, 56         ;Shadow storage
            
            call    print
            byte    "Value 1:", 0
            mov     al, 55
            putInt  al
            
            call    print
            byte    nl, "Value 2:", 0
            mov     cx, 1234
            putInt  cx
            
            call    print
            byte    nl, "Value 3:", 0
            mov     ebx, 12345678
            putInt  ebx
            
            call    print
            byte    nl, "Value 4:", 0
            mov     edx, 1
            putInt  edx
            call    print
            byte    nl, 0
            
            
allDone:    leave
            pop     rbx
            ret     ;Returns to caller
asmMain     endp
            end

            end                   

Last updated