Macros

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Post Reply
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Macros

Post by Oziphantom »

To stop derailing the other thread I'm pealing this one off
From the other thread
Garth wrote:
Oziphantom wrote:Macros are nice, but they are mermaids.. they sing a sweet song and send you to your doom if you are not careful. If you make the "safe" its mostly ok. But you have to really plan to properly and understand how they work etc. I did have a lot of macros but I found they tend to make the code less readable and maintainable after a while. ADCB_W, ADCBX_W, IFBLT, IFBLTE, BAGTE etc.
Take a different approach. Instead of using cryptic names, make it really clear what they're doing, and use the parameters to make like a sentence. If your ADCB_W means "Do a double-precision (16-bit) add-with-carry of B and W," you could change the macro name to something like _16bit_ADC, and make the line say for example,

Code: Select all

        _16bit_ADC   B, _and, W    ; B=B+W
(Unfortunately the assembler requires separating parameters with a comma, which is why there's a comma after the _and.) The "_and" (with the underscore or other character to keep the assembler from confusing it with the mnemonic) is an equate that does not actually get used by the macro. It's only there to make things more readable to humans. The comment clarifies where the answer goes. So this would assemble the same as

Code: Select all

        CLC
        LDA   B
        ADC   W
        STA   B
        LDA   B+1
        ADC   W+1
        STA   B+1
The same macro can be used to add different variables which you specify in the parameters, rather than being confined to B and W. Conditional assembly in the macro definition can do optimizations if necessary. Some assemblers let you say in essence, "If there's a fourth parameter, do the following;" so you could use the same macro to add more than just two numbers, and you could invoke it something like this:

Code: Select all

        _16bit_ADC   B, W, _and, offset3    ; B=B+W+offset3
If your IFBLT means "if: branch if less than," and only assembles a BMI, it's not really clarifying or shortening anything. How about something like this instead, where a portion is skipped if the N flag is set:

Code: Select all

        IF_POSITIVE    ; Negative result above causes it to skip the following lines.
           <do_stuff>
           <do_stuff>
           <do_stuff>
        END_IF
or to branch back to the beginning of a loop as long as the result is negative:

Code: Select all

        BEGIN           ; (Or name it "DO" if you like)
           <do_stuff>
           <do_stuff>
           <do_stuff>
        UNTIL_POSITIVE
Then you don't even need a label (although you can still use one if you want to).
The idea of using dummy strings to improve readability is a nice one. (note if you want to avoid the , issue you can switch to tass64. the .fucntion form of macros lets you do thing a,x,_and,b,y and it will work it out just fine ;) )
For me the issue with _16_ADC B, W, _and, offset3 is it puts me in to a C/C++ intrinsic function mindset to which point I start to forget about # although in the example you give you then need _16_ADC_Immed B,W or if the assembler lets you determine a parameter type _16_ADC B,#W but then getting it to be able to do #<#W might be tricky...
The Mermaid part comes from the _16 ADC_8_Immed case

Code: Select all

lda B
clc
adc #W
sta B
bcc +
inc B+1
+
say given

Code: Select all

  ldx #7
- lda 2
  bit 4
  bpl +
  _16_ADC_8_Immed 8,40
  jmp _next
+ _16_ADC_8_Immed 8,20
_next
  dex
  bpl -
spot the bug ;)
I would think that your DO/WHILE LOOP/UNTIL would have the same issue. Unless your assembler is that rare beast that lets you make unique labels? can you Loop in a Loop?

My point with
#ADCBW Add With Carry Byte to Word
#DXP Decrement X branch if Positive
was to make "instructions" and keep the Assembly look and flow.

Code: Select all

BALT - Branch A Less Than
BALT immediate/address branch_target
IF A < value THEN branch
BALT .segment
	cmp \1
	bcc \2
.endm

ISALT - IS Address Less Than
ISALT address immediate/address branch_target
IF (address) < value THEN branch
ISALT .segment
	lda \1
	cmp \2
	bcc \3
.endm
this way I don't have to remember which way 6502 does the comparasing. Does it branch if A is < CMP or if CMP is less than A - ISALT Thing,cmp,dest - however as I said this was stupid ;)
As mentioned I have since abandoned this idea in favor of !!if Thing < Other then DEST and then !!Dest += #5, !!Dest &|= #$f0,#$02, !!Dest = Src + other - #40, loops and 16bit versions of the maths are the next big things to tackle though...
Post Reply