Language…
6 users online: Ethanawanghaha, ForthRightMC, Metal-Yoshi94,  Saphros, Slash-18, TheRestingBird - Guests: 84 - Bots: 142
Users: 67,615 (2,010 active)
Latest user: Ethan745

The Wonderful World of Macros!

AdvancedASM Coding


1. What IS a macro anyway?

A macro, simply put, is a shortcut to write things. If you have a common piece of code in Asar that you use over and over with very little or no changes, you can turn it into a macro and save a lot of time and effort, plus it lets you change it without searching and replacing each copy. It also can act sort of like a function, allowing you to pass variables to it. Macros can be a powerful tool that can shorten code and make coding easier.


2. How do macros work?

Macros are not true functions or subroutines in the same way C functions or subroutines are. They are more like defines. When you call a macro, the macro's contents get inserted where you call them. The difference is, a macro can be more then one line and contain most anything you want, including code, and you can additionally set arguments or variables that get inserted wherever you want.


3. How do I make a macro?

Macros are easy to make, if you know how they work. The first thing you need to do is declare the name and what augments it uses. To do this make a line in the asm file like this:

Code
macro name()


Note that "name" can be almost anything (as long as it's not a special character. For simplicity's sake, I will say just stick with letters and numbers), but each macro has to has to have it's own name.

After you made that line, every line after it is part of the macro until you end it. To end a macro, you have to put "endmacro" on a line by it's self.


4. How do I use a macro?

Now you should know how to make a basic macro, but how is it used? First we should learn how to "call" or run a macro. To do this, we use the "%" character in front of our macro name like this:

Code
%name()


Now when we call a macro the contents of a macro will replace the macro call. So if we do this:

Code
macro name()
LDA #$24
endmacro

%name()


Now "%name()" will be replaced by "LDA #$24". You can put as much code as you want in a macro, and even non-code things like "db" or "org" or most anything else Asar understands. There is even a special sort of label for macros. If you start a label name with the "?" character inside a macro, each time the macro is run the "?" will be replaced with something new, so you can branch to it without having to worry if it is redefined.


5. How do I use arguments?

Using arguments or variables allows you to replace parts of the macro with whatever you want. You may have noticed that the macro name I used is followed by "()". This is a required part of a macro. If you don't want to use arguments, just leave it empty. Otherwise, in between the "(" and the ")" is where you put the names of arguments or variables you use. Same rules apply to these names as the macro name. Here is an example:

Code
macro name(arg1)


Again "arg1" is an example. Inside a macro, you can insert an argument by placing the name of the argument inside "<" and ">" for example:

Code
macro name(arg1)
LDA #<arg1>
endmacro


Then when you call the macro, you simply put the text you want to insert in between the "(" and ")" like this:

Code
%name($24)


and the result will be:

Code
LDA #$24


You can have as many as you like, just make sure each one has a "," after it, in both the macro and the call, like this:

Code
macro name(arg1, arg2)
LDA #<arg1>
STA <arg2>
endmacro

%name($01, $19)


Which will result in:

Code
LDA #$01
STA $19


Now isn't that simple? :3

One last note: A macro call, as far as I know, can only be done on it's own line.


6. Some examples and stuff

Here are some example macros I made:

Code
; Loads a snes pal color into a, must be in 16-bit mode
macro rgb(r, g, b)
	LDA.w #<b><<5|<g><<5|<r>
endmacro

; Makes a rats tag for the space between two labels
macro rats(start, end)
	db "STAR"		; Write RATS tag
	dw <end>-<start>-1
	dw <end>-<start>-1^$FFFF
endmacro

; Re-points a stim image to a new location or label
macro ImagePointer(slot, pointer)
	org <slot>*3+$8084D0
	dl <pointer>
endmacro

; Re-points a layer 3 bg to a new location or label
macro TileSetL3pointer(set, slot, pointer)
	org <set>*3+<slot>*3+$859000
	dl <pointer>
endmacro


Also, did you know you can use an argument for a macro to decide what macro to call? I found a few uses for that. :3
Hrm, I figured this'd be made someday. If I'm not mistaken however, it doesn't reduce insert size, it just improves readability, right?

World Community Grid: Thread | Team
 
Correct, Macros do not decrease insert size in any way. It's just a fast way to place the same code over and over again.
So macros are the same as functions, right?
So basically, whenever the macro is called, it doesn't exactly GO TO the macro, but INSERTS the macro? I personally don't see the point of it, but it seems interesting.
Though there are times where it is useful. It's mostly a shortcut, not a function, but there are times where it's simply faster to use a shortcut then a function if the function is short. Also like I said and do in my examples, you can use it for any xkas command. Also it makes unrolled loops much simpler, as done in the limitless sprite patch.
Your layout has been removed.
Since I've seen it several times, I should probably post about it:

Code
; Makes a rats tag for the space between two labels
macro rats(start, end)
	db "STAR"		; Write RATS tag
	dw <end>-<start>
	dw <end>-<start>~
endmacro




It doesn't work. Better make it known before people start wondering why data gets corrupted in their ROMs for no apparent reason.

@Yakov: it's closest to an 'inline function' if you want to think of it in that sense. It just duplicates the block within the macro definition (with arguments set) wherever you 'call' the macro.

@randoguy: they are definitely useful for repetitive insertion of code/data. Unrolled loops as mentioned are a huge plus. VRAM patch in LM 1.70+ made extensive use of macros and it would've been thousands of lines longer without them. Beats copy/pasting code over and over again.

Macros are great, especially on the SNES since 'inlining' functions is useful since CPU time comes at a greater premium then ROM space (literally more megabytes then megahertz =)). But for handy blocks of code you might need many times (like in the OP) they are useful for that too. Any time you find yourself copy pasting a block of code (where JSR doesn't fit the purpose) then consider using a macro.
Smkdan I looked in a hex editor like you suggested and it seemed perfectly fine to use ~. (The rats tag was correct, and to verify I put a correct rats tag directly after it.)
I own a community of TF2 servers!

ASMT - A new revolutionary ASM system, aka 65c816 ASseMbly Thing
SMWCP - SMW Central Presents a Product- tion long name

frog

http://esolangs.org/wiki/MarioLANG
Originally posted by smkdan
It doesn't work. Better make it known before people start wondering why data gets corrupted in their ROMs for no apparent reason.


WELL IT SHOULD! >___<

Maybe I can use xor instead...

Originally posted by fakescrapperguyperson
Smkdan I looked in a hex editor like you suggested and it seemed perfectly fine to use ~. (The rats tag was correct, and to verify I put a correct rats tag directly after it.)


Maybe it's something that is fixed or broken in the unofficial xkas. I should hex it myself...


Your layout has been removed.
XOR has always worked! The only other correction is really minor, but the tag sizes should be free space -1. It won't break anything if you insert something that reserves one more byte than needed,even though it's not correct.

@fakesacper: I get incorrect size fields everytime I try that. Redownloaded xkas for good measure but it still messes up. What source file did you use that made a correct RATS tag?

edit: if there's more than one app in use, the tags should be written in a way that it works on all considering that it's very little effort to just XOR.
In general, it might be good to reserve that byte anyway, as padding.

Edit: Decided to fix the macro anyway. :3
Your layout has been removed.
It's worth noting that you can store your macros in an external file so they don't clutter up your code. Example:

Code
INCSRC sprites/<file>.asm


Just toss it in before the INIT routine and you should be good to go. Also be sure that you throw the file you're pulling from in the same directory as SpriteTool (/*Tool/otherthingsthatusemacros).

This was worth the 1.5 year bump.

AdvancedASM Coding