I like NESHLA but it's too limiting, and so I moved on to ca65 for various reasons. The things I liked about NESHLA I figured I could do without or get close enough to the same functionality with macros. I decided to recreate the if functionality with macros and I think it is working well. If anyone is interested I'll post the code up somewhere. What I am able to do is stuff like:
Code:
if {carry set}
; do code
endif
;or
if {equal}
; blah blah
endif
if {less}
; blah blah
endif
It should work with any number of nested ifs and should be easy enough to add your own keywords.
Look at a 6502 manual, There are opcodes for specific operations like this!
They are Branching Instrucions!
EDIT:
IF Carry Set = BCS
IF Equal = BEQ
IF Less = BMI(?)
I'm sure he knows that Hamtaro, since he made the macros and all (and the macros do translate to branch instructions when assembled). Assembly typically lacks indentation and logical blocks, so it's understandable that some people prefer to use macros to make things a little bit less low-level.
Hamtaro126 wrote:
IF Carry Set = BCS
IF Equal = BEQ
IF Less = BMI(?)
The macro would actually change carry set to BCC and equal to BNE since I want to enter the block of code if the flag is set.
In normal 6502 assembly Less is BCC, greater or equal is BCS (after a CMP instruction). That is how I implement it in the macro at least - NESHLA used the N flag >:(
Movax12 wrote:
NESHLA used the N flag >:(
Which is OK if you're dealing with signed numbers. The carry flag can be used for unsigned comparisons, while N and V should be used for signed numbers.
I think my brain would think about that better in terms of "is the result negative or not?" rather than less or greater, but I see your point.
So far I have:
Code:
; carry set
; carry clear
; no carry
; not carry
; C
; not C
; C set
; C clear
; less
; not less
; greater_equal
; not greater_equal
; zero
; zero clear
; zero set
; not zero
; equal
; not equal
; Z
; not Z
; Z set
; Z clear
; plus
; not plus
; positive
; not positive
; minus
; negative
; not minus
; not negative
; N
; not N
; N set
; N clear
; bit7
; bit7 set
; bit7 clear
; not bit7
; V
; overflow
; overflow set
; overflow clear
; not overflow
; V
; V set
; V clear
; not V
; bit6
; bit6 clear
; bit6 set
; not bit6
I'm not sure if I am implementing the macro as well as possible, but as long as I stick to the above formats I'm certain it will work. The code is here:
http://sharetext.org/dDge
tokumaru wrote:
The carry flag can be used for unsigned comparisons, while N and V should be used for signed numbers.
Is there a standard test on 6502 for whether unsigned + signed (e.g. position + change) has overflowed unsigned?
Would it be hard to make macros for greater, not greater, less_equal, not less_equal, that use a branch on Z that jumps over a branch on C?
Would "else" be hard?
tepples wrote:
Would it be hard to make macros for greater, not greater, less_equal, not less_equal, that use a branch on Z that jumps over a branch on C?
Not hard at all. It also wouldn't be hard to implement do-while loops, or repeat-until.
Quote:
Would "else" be hard?
I briefly thought about that, it might not be too hard.. I'll think about it.
So I was implementing ELSE and I realized that trying to track IF/ENDIF pairs with numbers and math doesn't work. It may work most of the time, but it doesn't work all the time. The only proper way to do it is a stack, and actually it's much easier.
So ELSE is working and IF / ENDIF should be 100% reliable as far as matching up the code blocks properly.
http://shorttext.com/f3qe4k
I added greater and not greater. I also made some the flag checks more restrictive, like a flag name (Z for example) has to be followed by 'set' or 'clear'. I may add a do while loop and get back to actually coding some 6502. If anyone uses this and needs the code to be relocatable, change the jmp in the else macro to clv/bvc.
http://pastebin.com/PKjw89u8EDIT: small changes:
http://pastebin.com/Hvfr4EQh
I've polished this up quite a bit, there is some information here:
http://mynesdev.blogspot.ca/2012/09/ca6 ... acros.htmlThe expression evaluation code has gone from a huge pile of .IFs down to this:
Code:
.macro process_expression_FLAGS flagtest, flag, flagisset
; Find a value for which flag we are checking and return:
_n_ .set ( (.xmatch(.left(1, {flagtest}) , no)) .or (.xmatch(.left(1, {flagtest}) , not)) ) ; not or no prefix
flag .set (.xmatch(.mid(_n_,1, {flagtest}) , C)) * 1 + (.xmatch(.mid(_n_,1, {flagtest}) , Z)) * 2 + (.xmatch(.mid(_n_,1,{flagtest}) , N)) * 3 + (.xmatch(.mid(_n_,1,{flagtest}) , V)) * 4 + (.xmatch(.mid(_n_,1,{flagtest}) , G)) * 5
flag_set_default .set (.xmatch(.mid(_n_+1,1, {flagtest}), set)) * 1 + (.xmatch(.mid(_n_+1,1, {flagtest}), clear)) * -1
.ifnblank .mid(_n_+2,1, {flagtest}) ; user added clear or set, also accept 'do' from "while <exp> do" syntax
invert_flag .set .xmatch(.mid(_n_+2,1, {flagtest}), clear) * -1 + .xmatch(.mid(_n_+2,1, {flagtest}), set) * 1 + .xmatch(.mid(_n_+2,1, {flagtest}), do) * 1
.else
invert_flag .set 1 ; no clear or set added, that's okay make it a 1
.endif
invert_flag .set invert_flag * (_n_ * -2 + 1)
.if ( (flag = 0) .or (flag_set_default = 0) .or (invert_flag =0))
.error "Unknow expression in flag test."
.fatal ""
.endif
flagisset .set ((flag_set_default * invert_flag) > 0) ; This will always result in a negative or positive, positive being flag is being tested for
.endmacro
It's working well I think, I'll publish all the code soon.
Updated! I am done for now - I'm going to try to actually use it in code. Any feedback welcomed. Code is available at the blog link I posted.
I'm trying out your macro package, and it seems it can't handle local labels within the conditions like in the following snippet:
Code:
cmp #JOY_A
if equal
jmp @Freeze
endif
cmp #JOY_B
if equal
jmp @Melt
endif
lda #0
rts
Removing the '@' from my label names works fine. While I realize that your macros are supposed to reduce the need for local labels, it would be nice if it didn't disable their usage in this way. Do you think it would be possible to make your macro package support this?...
Bananmos wrote:
Do you think it would be possible to make your macro package support this?...
As far as I know, it's not possible. The macros need to generate labels, and they'll always mess with the local (@) labels. I thought it might be possible to fix this by generating the label inside a scope, but looks like the @ labels don't care about scopes, so they'll get invalidated when any normal label comes. Then I thought it might be possible to generate the label using "foo = *" or "foo := *", but that also invalidates the local labels. As does "foo .set 123". That's all the possible workarounds I can think of...
P.S. Movax, why are you using .error followed by .fatal "", and not only .fatal?
.error outputs a line number with the string.
.fatal stops the assembly, but doesn't give a line number.
There are some minor issues with this too, but the worst error is if the branch is too far, ca65 won't tell you were the problem is in the main code, just in the macro. The branch generation could be changed to always use a jmp with a branch over and I've added an option to do that which isn't too complicated if anyone wants. It's too bad there is no way to decide if the branch is long or not in the macro code.
I don't see a way to use cheap local labels due to the generation of normal labels from the if macro(s)
Is there a reason why you're not using
macro-local labels?
I also have a bit of a problem with the Creative Commons license, which isn't really meant for code. One of the
technicalities making it incompatible with some other licenses is the provision for requiring downstream users to remove credits. I'd have gone with
this one.
tepples wrote:
Is there a reason why you're not using
macro-local labels?
I also have a bit of a problem with the Creative Commons license, which isn't really meant for code. One of the
technicalities making it incompatible with some other licenses is the provision for requiring downstream users to remove credits. I'd have gone with
this one.
Wrong thread? Anyway, it's not possible to use macro-local labels, because they are not visible from one macro to another. And even then, I have a feeling that they'll invalidate the local @ labels too, because under the hood CA65 is simply replacing their name with a unique identifier.
Oops, my bad. Fortunately, phpBB 3 lets moderators move posts from one topic to another.
After adding some .proc/.endproc directives, I guess the lack of local labels ain't that bad. The constructs do make my AI code and my in-game mapeditor code look a bit more readable, and this is exactly the place where I'd like to have some more readability and no having to think twice over what I'm writing, at the cost of less efficient code. (was considering doing all AI in Atalan, but it turned out to be too buggy so using these macros is a less drastic alternative)
Not sure about them in the rest of my game engine though, as I kind of want to keep my branches optimal there, and having to start thinking about what kind of branches the conditional constructs result in kind of defeats their purpose
There isn't a point to changing already completed and working code I don't think, though I did change a lot of mine, but mainly for testing purposes (I didn't ever run into a problem). The conditions will always assemble into one branch instruction except for greater / not greater so there should be no optimizing issues. (Greater should be substituted with greaterORequal where possible by comparing to a value+1)
I just had a hard-to-track down bug and realized that it again was due to label restrictions... it seems that introducing any sort of scoped labels in your file prevents you from using it. So this dummy example will fail to compile:
Code:
.SETCPU "6502X"
.include "hla.inc"
.CODE
if equal
.byte $00
endif
.proc MyProc
if equal
jsr $0000
endif
.endproc
But removing the if/endif which is outside the proc compiles fine. In this case, the two scopes are completely separate and don't interact in any way... so shouldn't it be possible to work around the label restriction here somehow, short of putting them into separate .asm files and compiling them separately? i.e, by somehow resetting the label counter before declaring MyProc, putting things in the same state as they are when you begin assembly?..
If you keep all your code inside a .scope or a .proc there should be no problem. I am a bit confused as to exactly the details of the issue (just looked at it for a couple minutes), but I think I could resolve the problem if this is something you need to be able to do, let me know if you really require this. - I'm probably going to play with it anyway...
EDIT: So I decided to change the code to work in that situation, I like it better - the problem was the way the macros were using the variable 'constants' for tracking numbers. I pasted the code at the blog link:
http://mynesdev.blogspot.ca/2012/09/ca6 ... acros.htmlBut really it's probably better to keep your code inside a .proc
Oh, btw - I added an option to create a long jump in the IF macro which is in that code - I'm pretty sure it is working properly.
Quote:
So I decided to change the code to work in that situation, I like it better - the problem was the way the macros were using the variable 'constants' for tracking numbers
Thanks! Everything that failed prevously seems to work nicely now
Btw, can I come with one more improvement suggestion?... I saw on the previous page of this thread a discussion of comparing numbers as "greater/less" with respet to signed/unsigned numbers. The thing is that to handle this decently, you probably need to have distinct namings for this similar to what the x86 assembly instructions have:
http://unixwiz.net/techtips/x86-jumps.htmlIn summary, when using unsigned numbers the x86 assembly instructions use the "above"/"below" terminology, but when the numbers are signed it uses the "greater than"/"less than" terminology. It really doesn't take very long to get used to which is appropriate for unsigned/signed numbers, so I would recommend having some similar naming in your macro pack to be able to easily do both signed and unsigned comparison.
I don't want to add too much complexity to the macro code, even adding the greater and lessORequal I wasn't sure about.
You can use the syntax to call an additional macro like this example if you want more complexity:
Code:
.define padpressed(buttons) Z clear do_code padpressedMAC buttons
.macro padpressedMAC buttons
lda _pads_new_pressed
and #(buttons)
.endmacro
;...
if padpressed BUTTON_A|BUTTON_START
;...
endif
This will check for Z clear, so instead you could write some code and check for N flag based on the information here (section 5):
http://www.6502.org/tutorials/compare_beyond.html#5
I swore I wasn't going to do this, but I've done a lot of work to make the ability to call another macro quite a bit more useful. From a user (of this macro pack) perspective, all you need to do is make a .macro "function" like this example:
Code:
.macro padpressed buttons
lda _pads_new_pressed
and #(buttons)
set_flag_test Z clear
.endmacro
So if you use any of the conditional macros, you can code like:
Code:
if padpressed BUTTON_A
; do stuff
endif
The difference here is that the macro function can specify what CPU flags to check and there is no inline function like before.
This allows for quite a bit of flexibility and I have both a signed and unsigned expression evaluation working that I'll post soon. Example:
Code:
if comp a > #3
;code
endif
Or signed:
Code:
if scomp a <= #(< -120)
;...
endif
The signed compare generates a bit of code and trashes reg a, but both can handle any comparison except for comparing registers to each other.
EDIT: () Brackets will be needed around any high/low byte operators
Updated! Try it out and let me know if there are any issues, it is somewhat untested, but I expect it almost bug free. There is a link to download a demo program and nes rom:
Small write-up:
http://mynesdev.blogspot.ca/2012/10/ca6 ... dated.htmlDownload:
https://app.dumptruck.goldenfrog.com/p/b9UI5-8_ck
How far can this be taken? Can you make asm look like a higher level language? I seem to remember a book in the early 90's about object oriented assembly. I assumed they used macros and stylistic rules to ape C++
MASM has stuff like .if/.else/.endif/.while/.break built in. A lot of modern assemblers have things like that, though sufficiently powerful macros can probably do all of that (at the expense of longer assembly times).
I thought .if directives in assembly language were evaluated at compile time, like C++ #if. At least that's how ca65 handles .if.
There's a lot less standardization when it comes to assemblers. MASM has directives that do both things:
IF vs
.IF.
I don't think there is much of a limit on how far you could go with enough macro code. As it is, none of these generate a lot of code - the signed comparison generates the most. If more complicated expressions were wanted they would have to result in more complex code being output. Interesting that MASM has support for this kind of thing.
EDIT: Actually there is a pretty bad error in the code highlevel.h due to a search and replace doing more than I expected, I'll update this post when it is fixed.. Fixed, links still valid.
Thanks for the tip about .macro "functions"... they really help making my code look nicer as testing various state flags in the AI code is just an if CUSTOM_CONDITION
The and/or support you talked about in another thread sure sounded interesting, even though this is already very useful as it stands.
I feel I kind of rushed things a bit before, so I'm trying to get things polished up a bit more this time but I'm almost ready to release some more stuff after I write up some decent documentation too.
I'm using dopple's smbdis.asm to test the macros, so maybe I can share that as well.
Still working on the documentation but I wanted to share this..
I'll document it better later, time to head to work..
http://mynesdev.blogspot.ca/2012/10/ca6 ... again.htmlhttp://pastebin.com/azMMvh4r .. updated 1 times.
Documentation updated! I will add more but it explains most things well.
Another post on this topic, I tried to explain a bit about how it is working, sort of in between technical and more explanative, I hope this proves useful to others:
http://mynesdev.blogspot.ca/2012/10/hl- ... nical.html
I've decided to keep this code updated here:
https://www.assembla.com/code/ca65hl/git/nodesI'm also going to use the wiki on that page to document it's use, though there is not much there yet.
This version also includes integrated <, >, <>, >= <= operators (unsigned) as well as the assignment macro and
assignment macro supported operators &, |, ^ ( bitwise) +, - (clear/set carry) --, ++ (with carry), >>, <<, *, / (times and divide also shift left or right with powers of two.)
It will also default to behaving as if any non zero result is true if no cpu flags are specified and (hopefully) it makes sense to do so.
Announcing a new feature addition. Now featuring support for parentheses in expressions! Although I am confident I have everything working, please let me know if you find any mistakes. I would consider this untested, beta code.
https://www.assembla.com/code/ca65hl/git/nodes/develFollowing the same rules as the previous version, you can test 'expressions' that represent or result in a CPU flag being set/clear and branch appropriately. The latest code allows parentheses to create more complex logical conditions, as well as a negate operator that can distribute across parenthesis. The code generated aims to be efficient and will short circuit as soon as the outcome can be determined.
The only limitation is that all OR logic must be before all AND logic in the same parentheses set. ( Add parentheses to work around this.)
Example:
Code:
; branch to label:
* = 8000
foo = $00
bar = $01
baz = $03
myLabel = * + $50
if ( ( foo >= #$03 && ! bar ) || ((zero && negative) || baz = #1)) goto myLabel
; code output:
8000 A5 00 LDA $00
8002 C9 03 CMP #$03
8004 90 04 BCC $800A
8006 A5 01 LDA $01
8008 F0 46 BEQ $8050
800A D0 02 BNE $800E
800C 30 42 BMI $8050
800E A5 03 LDA $03
8010 C9 01 CMP #$01
8012 F0 3C BEQ $8050
; if-endif ( else supported )
* = 8000
foo = $00
bar = $01
baz = $03
if ( !( bar & #$03 && baz == N set ) || (( V set || baz < #$10 ) || foo = #1) )
nop
endif
; code output:
8000 A5 01 LDA $01
8002 29 03 AND #$03
8004 F0 12 BEQ $8018
8006 A5 03 LDA $03
8008 10 0E BPL $8018
800A 70 0C BVS $8018
800C A5 03 LDA $03
800E C9 10 CMP #$10
8010 90 06 BCC $8018
8012 A5 00 LDA $00
8014 C9 01 CMP #$01
8016 D0 01 BNE $8019
8018 EA NOP
8019
Quick note: Added for-next style loop. Nestable.
1)C-style of loop:
for ( <thing to do 1st>, <Flag to test - continue while true >, <stuff to do at end of loop> )
Example:
Code:
for ( x := #$3, not negative, dex )
; code
next
; more complex:
for ( x := foo, (x > #10) && (foo <> #1), dex:dex)
; some code
next
2) BASIC-style syntax:
This actually tries to optimize some, and will break if you mess with your counter register or variable without thinking:
Code:
for x := #$AA to #$10 step -3
;some code
next
It will loop until your counter hits the first invalid (for the loop) value. If possible it will skip CMP and use BPL/BMI or a lone BNE. 'step' can be omitted and a step of -1 or 1 decided on if possible. You can use variables rather than immediate values, but no optimizations are possible.
https://www.assembla.com/code/ca65hl/git/nodes/develNext is to fix 'elseif'.
Nested 'elseif' seems to be working properly: (random nonsense code)
Looks interestingly. Will be great to watch video as everything works.
Are you saying you would like to see a video? What specifically would you like to see in a video on this topic?
Movax12 wrote:
What specifically would you like to see in a video on this topic?
Nothing specifically, just want to understand
How macro operators work. And how you can use operators in disassembler. This only works in Mario Disasm, or it can be used with any disassembler?
Anyway thanks.
This works with the assembler (ca65). I'm really not sure where I would start with a video, or if this topic really lends itself well to a video. Perhaps someday I'll make a video of something. The wiki
here explains how the macros work, but the latest information in this thread is not documented in the wiki just yet.
I still harbor fantasies of this becoming more like batari BASIC. I think "all" it would take is a canned kernel to update the screen and some functions for tiles, sprites, input and sound.
End users would still have to make sure not to use up too many cycles but that's life.
But Atari, despite being harder to make stuff for, is sumpler in what it is needed to do and such. I don't think you'd be able to make anything scrolling/map-updating+sound+sprites with a little basic thingy. Maybe if you made it work on modules, that'd be cool to try out.
3gengames wrote:
But Atari, despite being harder to make stuff for, is sumpler in what it is needed to do and such. I don't think you'd be able to make anything scrolling/map-updating+sound+sprites with a little basic thingy. Maybe if you made it work on modules, that'd be cool to try out.
Yeah. batari BASIC does work in the way you just described. It has different canned kernels for a specific set of needs.
set kernel_options pfheights pfcolors
(use the canned kernel that has adjustable playfield heights & colors)
would give you a different game engine than
set kernel_options pfheights playercolors
(use kernel that allows adjustable playfield height and the first sprite can have multiple colors)
Likewise I'd imagine an NES version would have different kernels whether you want single screen games using no MMC or side-scrolling using MMC1.
I have all kinds of modular stuff going on for my game project. I have a global config file that has a bunch of options that can vastly change what is output. This part of the project stands on its own though, and I like the fact it doesn't need any library code or memory on it's own. I do imagine that I would release the rest of my ideas and some library stuff at some point, which may be closer to batari BASIC. The flexibility of the syntax with ca65hl is already much more developed however.
Movax12 wrote:
I have all kinds of modular stuff going on for my game project. I have a global config file that has a bunch of options that can vastly change what is output. This part of the project stands on its own though, and I like the fact it doesn't need any library code or memory on it's own. I do imagine that I would release the rest of my ideas and some library stuff at some point, which may be closer to batari BASIC. The flexibility of the syntax with ca65hl is already much more developed however.
Are you familiar with NESHLA?
http://neshla.sourceforge.net/Does this project compare with that (as far as results not implementation)?.
Odd that the sub-subject header is wrong on the last two posts.. forum bug?
Anyway, yes, read the 1st post, I used to use NESHLA. I would consider the abilities of ca65hl to be comparable but more advanced.
Movax12 wrote:
Odd that the sub-subject header is wrong on the last two posts.. forum bug?
If you push the quote button, phpBB 3 copies the quoted post's subject into your post's subject. Otherwise, it copies the first post's current subject (which the Subject Fairy may have since edited) into your post's subject. If you click quote, delete the entire quoted post, and write something else entirely, your post still gets the quoted post's subject.
Could you make some kind of central site with all of your code? Tried to find something on your blog, but it is mixed with disassembly of SMB and whatnot. Also your code formatting makes my eyes hurt (hint: using blue color for background, white for keywords and yellow for code works only in 80x25 terminal that uses DOS font, in 320x240, on anything different it just hurt people's eyes). Anyway, since I'm learning NES assembly now (with ca65), your macro will be useful for me.
Check page 3 of this thread for the assembla link. Check out the wiki. Sorry you don't like the colors, my eyes like it.
Thanks! Have a
on me!
Anyway, since you are pretty knowledgeable, could you do some macros for following things:
- Setting tile ID in nametable at specific x,y, so I can plot tiles onto nametable (very important if you are going to make something more advanced than scrolling static screen)
- Plotting 16-bit numbers on screen for things like score, etc. (as decimals)
I won't mislead you: I am quite noob (yet) when it comes to NES development and this would give me boost I need to explore this further.
darkhog, as a beginner NES software developer, you'd really better to forget about macros for now, until you learn some 6502 assembly and the NES HW basics (memory map, at least), maybe by reading through the Nerdy Nights. These two things you asking aren't how the things on the NES works. Setting up a VRAM address or a RAM pointer to given x,y with a macro could work, but it'll lead to inefficient code, forcing you to provide x,y in a specific, not-so-optimal way. Displaying score with a macro is just nonsense, it should be done with a subroutine instead, because macro will duplicate the (not so short) code at every call, which will give program memory overhead for near-zero CPU speed gain. Not to mention that there are many ways to display score, each one has its specifics and should be used accordingly.
Shiru wrote:
darkhog, as a beginner NES software developer, you'd really better to forget about macros for now, until you learn some 6502 assembly and the NES HW basics (memory map, at least), maybe by reading through the Nerdy Nights. These two things you asking aren't how the things on the NES works. Setting up a VRAM address or a RAM pointer to given x,y with a macro could work, but it'll lead to inefficient code, forcing you to provide x,y in a specific, not-so-optimal way. Displaying score with a macro is just nonsense, it should be done with a subroutine instead, because macro will duplicate the (not so short) code at every call, which will give program memory overhead for near-zero CPU speed gain. Not to mention that there are many ways to display score, each one has its specifics and should be used accordingly.
Then as subroutines, geez...
Also for setting specific tile on specific x/y I was thinking about stuff like that:
Code:
;store previous values of registers
sta zp_tempa
stx zp_tempx
sty zp_tempy
lda #$3b ; load tile to put on tilemap
ldx #5 ;load x of tile
ldy #5 ; load y of tile
jsr place_tile
;restoring old values of registers:
lda zp_tempa
ldx zp_tempx
ldy zp_tempy
Without routine like that making discrete changes to nametable such as putting score, updating lifebars, etc. is impossible if you don't want to update whole nametable.
Also I was using displaying score as example. Another one may be displaying current level number, etc. - anything that involves displaying decimal 16bit number on screen. I just want general routine to display decimal numbers, that's all.
To translate a 16-bit number from binary to decimal, you could use
this subroutine that takes about 700 cycles (6 scanlines) to get the digits, and then you could make another subroutine that runs during vblank and prints the digits to the screen. In my current project, there are four steps: get the digits, convert them to an ASCII string, render the string to tiles, and copy the tiles to the screen.
Well, macros vs subrotines is not 'geez', they are competely different things, related to different entities (specific translator vs CPU). This difference means that you are asking a random guy who is good is in making macros for cc65 in a thread about macros for cc65 to give you some random code, i.e. you are asking to do completely different thing.
If you are understand how the NES video hardware workds, you should understand that setting a tile in a nametable is not so straightforward thing. If your nametable is just 1024 bytes in the main RAM, it is one thing. If it is in the VRAM (actual nametable), and the rendering is disabled, it is another. If you need to update tiles when rendering is enabled (your case, as you have mentioned scrolling), this is a whole range of different things: updating sequences of random tiles, updating columns or rows, updating only tiles or attributes, etc, etc, etc. A lot of things should be considered to provide some solution to the task. It can't be as simple as 'please make me a macro', it is a whole topic to be discussed, with certain level of knowledge considered (about the HW, about your specific needs, etc).
darkhog, I'm more than happy to help you with a specific macro question if you would like, but macros aren't subroutines, though they can call subroutines, it's not the same thing.
Writing a macro to do some nametable functions is doable, but, as Shiru says, there are many different things that need to be considered, and such a macro would have to be very generic with lots of options to suit different uses, or very specific to what is needed at the time.
If your macro was writing to a vram buffer, for example, you still need to have a separate routine to copy that data to screen when NMI was triggered.
Think of a macro as a routine that is called when assembling the code, that outputs 6502 assembly, or other macros until only 6502 assembly is left. The assembler then assembles that code. The macro can not eliminate actually writing the code.