
Bill Garber wrote:
> "Michael J. Mahon" <mjmahon@aol.com> wrote in message
> news:EvidncT2FKE6a5XfRVn-qQ@comcast.com...
> : John B. Matthews wrote:
> : > In article <4208428C.5C714B48@buckeye-express.com>,
> : >  "Paul R. Santa-Maria" <paulrsm@buckeye-express.com> wrote:
> : >
> : >
> : >>"Michael J. Mahon" wrote:
> : >>
> : >>>Think of "<" as "less" significant, or "smaller", and ">" as
> : >>>"greater" significance, or "larger".  Or think of "<" as the
> : >>>lower addressed (left) part of a 16-bit number and ">" as the
> : >>>higher (right) address.
> : >
> : >
> : > When using Apple, Kyan and various cross-platform assemblers that
> : > use the opposite syntax, I came to think of #< as "left side" (hi)
> : > and #> as "right side" (lo).
> :
> : Ah, but that is a "big endian" view of memory.  ;-)
> :
> : >>Or, do what I do.  #VAL gives the low byte, and #VAL/256 gives
> : >>the high byte.  I never use #<VAL or #>VAL because I own 6502
> : >>assemblers that use them in exactly the opposite way.
> : >
> : > Excellent! Looking back I see that I used this in macros.
> :
> : I have also used this in macros, since it allows taking
> : the MSByte of any expression, not just a variable.
> :
> : I have never been very concerned about the "portability"
> : of assembly code to other assemblers, since most of my
> : programs use macros and other features that tend to be
> : peculiar to each assembler.  My standardization on Merlin
> : came early and has persisted.
> 
> Let me at this point verify for my own record that a "Macro"
> is a snippet of code that performs a function that I do a lot and
> I just insert the Macro name where I want this done. Am I at
> all correct???  For example, instead of placing in a jump to a
> place where this code would be, I simply insert the macro name
> and the assembler adds that snippet of code at that location.
> This is just to rectify my own mind. Are their any other short-
> cuts that you can use to simplify your source code??   :o)
> 
> Pages in manual will suffice so I can read up on them. Please,
> bive manual name and page number with each example, if you
> would happen to know or have it handy.

Macros are generally what you describe, and their syntax and
semantics vary a lot from implementation to implementation.
(Perhaps that is because most macro generators are their author's
_first_ (and last) macro generator, providing little opportunity
for learning.  ;-)

In the late 1950's Doug McIlroy at Bell Labs added the first general
macro expander onto an assembler for the IBM 709.  In a few years,
it developed a quite general string processing/string substitution
capability, which allowed whole computations to be done at assembly
time in the macro expander!

In the 1960's Christopher Strachey's GPM, and Calvin Mooers' and
Peter Deutsch's TRAC defined the general purpose macrogenerator
as a string-oriented computational model.

In the microprocessor era, many of the lessons of the mainframe era
had to be learned all over again, and macro expanders are no exception.
Most microprocessor macro expanders are quite limited in what they can
do, but all can "regurgitate" a macro definition in-line, and most can
substitute actual arguments supplied with the call for formal arguments
used in the definition.  The real power of macros comes with the
inclusion of conditionals, and operations to dissect and concatenate
strings, as well as define new macros as a side effect of an expansion.

Merlin Pro (8) is a relatively limited macro assembler, with limited
substitution and conditional operations, and no capability to define
or redefine macros during expansion (so it is hard to "remember" things
from one expansion to the next, unless it is a numeric value).

Merlin, curiously, also cannot define a label inside a macro, which
makes it hard to create a DO/UNTIL kind of macro set.

Nevertheless, Merlin's macros are a handy way to codify some useful
snippets of assembly code.  They are documented in the on-line manual
in chapter 7, and conditionals and variables at the end of chapter 6.

Some examples I find useful:

Definition:

align   mac                     ; Align modulo parameter
         ds    *-1/]1*]1+]1-*    ; ]1 is the first supplied parameter
         eom

Use:
         align 256               ; Align to next page boundary

Definition:

inc16   mac                     ; Increment 16-bit word
         inc   ]1
         do    ]1+1/$100         ; If ]1 is non-page zero
         bne   *+5               ; - No carry.
         else                    ; Else if ]1 on page zero
         bne   *+4               ; - No carry.
         fin
         inc   ]1+1              ; Propagate carry.
         eom

Use:
         inc16 count             ; Increment 16-bit count

Definition:

cmp16   mac                     ; Compare 16-bit words
         lda   ]1                ; Lo byte of first operand
         cmp   ]2                ; Lo byte of second operand
         lda   ]1+1              ; Hi byte of first operand
         sbc   ]2+1              ; Hi byte of second operand
         eom

Use:
         cmp16 end;ptr           ; Compare 'end' to 'ptr'
         bcs   :loop             ; Loop if end .ge. ptr

As you can see, macros can save re-creating standard patterns
of code and, when used properly, can actually contribute to
ease of understanding the source code.

Macros are also very useful in table generation, allowing
the table to be expressed in terms of its meaning instead
of its data representation.  Microcomputer macro expanders
are somewhat limited to use for this, in my experience.

Another fundamental use of macros is to contain the effects
of a decision about how something is implemented--abstraction.
In this case, the definition of the macro(s) can be changed
at any time and the program reassembled to incorporate that
change.  For example, the macro "initACIA" could be used to
abstract from exactly what was needed to init a particular
ACIA, so that the remaining code would be independent of
that choice.

Closed subroutines can be used similarly, but at the cost
of linkage instructions and possible parameter passing.
In many cases, a macro expands into a very few instructions,
so that linkage instructions would be a considerable penalty.

Many developers use macros to encapsulate the parameter
setup and calling for subroutines, so that they can easily
change parameter passing and register assignments later if
it should be useful.

Sorry for getting a bit carried away, but for many years
I saw clever macros as the solution to many problems.  ;-)

-michael

New Applesoft BASIC interface for NadaNet networking!
Home page:  http://members.aol.com/MJMahon/



Paul R. Santa-Maria wrote:
> "Michael J. Mahon" wrote:
> 
>>I have been frustrated by my inability to get Merlin to define a
>>global label in a macro that is referenceable outside a macro, and
>>this, unfortunately, is no exception.
>>Do you know a way to accomplish this?
> 
> 
> Do you mean this?
> 
>                 1             ORG   $5678      
>                 2    TESTMAC  MAC              
>                 3             NOP              
>                 4    ]VAR     EQU   *          
>                 5             NOP              
>                 6             EOM              
>                 7    ]VAR     =     $1234      
> 5678: 34 12     8             DA    ]VAR       
>                 9             >>>   TESTMAC    
> 567A: EA        9             NOP              
>                 9    ]VAR     EQU   *          
> 567B: EA        9             NOP              
>                 9             EOM              
> 567C: 7B 56     10            DA    ]VAR       

Almost.  This is a way to pass a value from a macro
_forward_ in a program.  And I would have expected
to use a global label. (Although, from your earlier
example, clearly "global label" definitions inside
a Merlin macro expansion are treated as variables).

But what I often need is a way to pass a value from
a macro called late in a program back to an address
context earlier in the program.  Put another way, I
want the label evaluated during pass 1, and the value
used during pass 2.  I have found no way to do this
in Merlin.  Outside a macro, a simple global label
does this job perfectly.

Of course, if the value is used to determine the
length of an instruction or data area, then it would
have to be a pass 1 value.

(For example, if I planned to do an "lda x", then x
would have to be known in pass 1 when the "lda" was
encountered, since it could be a 2- or 3-byte op
depending on whether x was on page 0 or not.  But
if I instead used "ldaa x", which forces Merlin
to use the 3-byte absolute address format, then x
could be a pass 2 value (since its value is not
needed to keep an accurate location counter.)

I find it expecially frustrating, since in my simple
string substitution model of macro expansion it just
works with no extra mechanisms whatsoever.

>>I also usually write the "]1+1" part as "1+]1"
>>so that it can handle indexed operands.
> 
> 
> Another great tip!  Thanks again.

Glad you like it!  You've got me questioning my admittedly
fragmentary model of Merlin's macro scheme.  ;-)

-michael

New Applesoft BASIC interface for NadaNet networking!
Home page:  http://members.aol.com/MJMahon/


