EDIT: I see this blog post may still turn up in search engines. Please use the code maintained here: https://gitlab.com/ca65/ca65hl
This macro code is much cleaner and faster than any of the old code releated to these posts. I always liked the idea of higher level assembly as long as it didn't get too carried away and there was no worry about getting too far away from the opcodes. I was trying to use NESHLA earlier but it just seems to be missing something, and CA65 has a lot more going for it. I decided to try to get some high-level functionality with ca65 macros, and I think I am pretty much done.
I had some rough code going before, but it was a bit sloppy and I think what I have now is pretty good and very near, if not entirely complete. There may be some bugs, but not many. So a summary of the features:
All the macro code is doing is taking a simple expression representing 6502 flags, and evaluating which branch to use, as well as generating some labels. Valid expressions are:
C set C clear Z set Z clear N set N clear V set V clear
You can also always negate the flag check with a no or not in front of these expressions. You can also add an additional set or clear at the end. The set will do nothing, but the clear will negate the 'set'. This make more sense with .define macros:
.define less C clear .define greaterORequal C set .define carry C set .define zero Z set .define equal Z set .define plus N clear .define positive N clear .define minus N set .define negative N set .define bit7 N set .define overflow V set .define bit6 V set
You can create any identifiers you like for different flags as long as they follow the format above. There is a special case for testing for greater or less or equal:
.define greater G set .define lessORequal G clear
This is a fake flag that makes it easier to evaluate the condition.
IF-ELSE-ENDIF
IF-ENDIF blocks can be created and nested without any practical limitation:
lda $1234 cmp #$aa if greater lda $4321 sta $5678 bit $2000 if bit7 set if bit6 clear ldx #3 else ldx #2 endif endif endif
You can add {} on the condition if you like: if {carry clear}
DO-WHILE ... REPEAT-UNTIL
You can start a block with do or repeat and end it with while <condition> or until <condition> . Repeat is identical to the functionality of do, it just reads better sometimes. Can also be nested as needed.
do do lda (address),y sta PPU_DATA iny while not zero inc address+1 dex while not zero
WHILE-ENDWHILE ..
This is a while <condition> do. The do indicates this begins a block. Use an endwhile to close the block.
OTHER NOTES
There is some decent error checking and I have tested quite a bit and am about to try it in my code. Please let me know of any problems if you use this.
Updated: Changed the macro code to use one set of global variable 'constants'. Before this change, a new set of counters would be defined every time that the code was inside a new scope, which sounds good, but I don't see much advantage, so the macro has been changed to all global counters. I actually like it better.
Please see updated code here: http://mynesdev.blogspot.ca/2012/10/ca65-hl-macros-updated-again.html
Added: Ability to call a macro with a .define, let me know if you are interested.
ReplyDelete.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
Please see updated code here: http://mynesdev.blogspot.ca/2012/10/ca65-hl-macros-updated-again.html
Delete