It is currently Sat Sep 23, 2017 7:40 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 34 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
PostPosted: Mon Jul 24, 2017 9:52 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10012
Location: Rio de Janeiro - Brazil
Yeah, you definitely have to mind the ends of the table if you plan on having values wrapping around. Complete freedom will require you to have 2 tables back to back (512 bytes total) and use the lower table for adding and the upper table for subtracting.

BTW, another advantage of a $00-$ff table is being able to perform operations between the accumulator and the index registers, such as ADC, SBC, AND, ORA, EOR... (e.g. A + X = ADC ByteTable, x).


Top
 Profile  
 
PostPosted: Mon Jul 24, 2017 10:56 am 
Offline
Formerly WheelInventor

Joined: Thu Apr 14, 2016 2:55 am
Posts: 861
Location: Gothenburg, Sweden
You could also make the table smaller if you know your Y and X transfers in your TYX/TXY substitutes are always going to be smaller than the table size. Making macros out of TYX, TXY, and the table inclusion, you could set your assembler to output an error if the param exceeds the limit of the table size you've chosen.

_________________
http://www.frankengraphics.com - personal NES blog


Top
 Profile  
 
PostPosted: Mon Jul 24, 2017 12:03 pm 
Offline
User avatar

Joined: Fri Jul 21, 2017 4:38 am
Posts: 31
Wow thanks for all the info, guys!


Top
 Profile  
 
PostPosted: Mon Jul 24, 2017 1:19 pm 
Offline

Joined: Wed Nov 30, 2016 4:45 pm
Posts: 84
Location: Southern California
Just calling it "four_count," are you sure you'll know what that is if you come back to it in a couple of years? I would call it something INX_4X to make it more clear what it's doing, and then if you want to tell the reason or significance, put that in the comment to the right.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources


Top
 Profile  
 
PostPosted: Mon Jul 24, 2017 1:24 pm 
Offline
User avatar

Joined: Fri Jul 21, 2017 4:38 am
Posts: 31
Garth wrote:
Just calling it "four_count," are you sure you'll know what that is if you come back to it in a couple of years? I would call it something INX_4X to make it more clear what it's doing, and then if you want to tell the reason or significance, put that in the comment to the right.


I commented it :) But yeah I think your name is better.


Top
 Profile  
 
PostPosted: Mon Jul 24, 2017 1:41 pm 
Offline
Formerly WheelInventor

Joined: Thu Apr 14, 2016 2:55 am
Posts: 861
Location: Gothenburg, Sweden
I think garths' comment on the comment ( :lol: ) reflected on what is often viewed as good vs bad commenting practice

Bad practice:
Describe what the macro literally does. This adds clutter, which will make important comments harder to find.
For example, you can just aswell read the content of the macro (inx inx inx inx) aswell as the current comment and get the same info: 4x inx. Moreover, if the name reflects it, you can get that info from the code calling the macro, too, which would make such a comment reduntant both in your macro file and your main source file/s.

Good practice:
Comment what it is supposed to do, its reason for being there, what you mean to achieve.
If the goal of the block is too basic/evident, omit comment.

Best practice (IMO - sometimes a bit overkill):
Same as good, but also add a description what arguments do, what they expect, possible caveats using this macro, and what registers/flags are affected by the macro, if not evident. Mostly needed in more complex macros.

_________________
http://www.frankengraphics.com - personal NES blog


Last edited by FrankenGraphics on Mon Jul 24, 2017 1:47 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Mon Jul 24, 2017 1:46 pm 
Offline
User avatar

Joined: Fri Jul 21, 2017 4:38 am
Posts: 31
Yeah, excellent points. I'll clean it all up when I get home. At the moment I'm still struggling to get the code working when in an external asm file. Works when in main file... odd. lol.


Top
 Profile  
 
PostPosted: Mon Jul 24, 2017 2:29 pm 
Offline
Formerly WheelInventor

Joined: Thu Apr 14, 2016 2:55 am
Posts: 861
Location: Gothenburg, Sweden
Hm.. It sounds like your assembler assumes another path for your .included files than you'd expect. NESASM3 users might want to chime in on that.

_________________
http://www.frankengraphics.com - personal NES blog


Top
 Profile  
 
PostPosted: Mon Jul 24, 2017 2:34 pm 
Offline
User avatar

Joined: Fri Jul 21, 2017 4:38 am
Posts: 31
FrankenGraphics wrote:
Hm.. It sounds like your assembler assumes another path for your .included files than you'd expect. NESASM3 users might want to chime in on that.


I checked the docs, paths are correct and no issues assembling (which I did get when I named the file incorrectly) so I think it's my code. I'll have another go tonight.


Top
 Profile  
 
PostPosted: Mon Jul 24, 2017 11:38 pm 
Offline

Joined: Tue Feb 07, 2017 2:03 am
Posts: 240
FrankenGraphics wrote:
I think garths' comment on the comment ( :lol: ) reflected on what is often viewed as good vs bad commenting practice

Bad practice:
Describe what the macro literally does. This adds clutter, which will make important comments harder to find.
For example, you can just aswell read the content of the macro (inx inx inx inx) aswell as the current comment and get the same info: 4x inx. Moreover, if the name reflects it, you can get that info from the code calling the macro, too, which would make such a comment reduntant both in your macro file and your main source file/s.

Good practice:
Comment what it is supposed to do, its reason for being there, what you mean to achieve.
If the goal of the block is too basic/evident, omit comment.

Best practice (IMO - sometimes a bit overkill):
Same as good, but also add a description what arguments do, what they expect, possible caveats using this macro, and what registers/flags are affected by the macro, if not evident. Mostly needed in more complex macros.

I disagree with these statements, well... wish to expand upon...
There are 3 uses for macros.
1.) Long complicated thing that I do often enough and want to tidy as its a black box and I just don't care. For example
Code:
;@name Clear Interupts
;@desc disables NMI on CIA, IRQs on CIA and VIC, sei
;@parent IRQ
ClearInterupts .macro
   sei
   lda #$7f
   sta $dc0d       ;turn off all types of cia irq/nmi.
   sta $dd0d
   lda $dc0d
   lda $dd0d
   lda #$ff
   sta $D019
   lda #$00
   sta $D01a
   sta $dc0e
   sta $dc0f
   sta $dd0e
   sta $dd0f
   lda $d01e
   lda $d01f
.endm
;@end
I do it once per project, maybe twice, fire and forget. Describing what this does exactly would be silly and long and not important.
2.) Macro to replace this missing thing, which should be named as on the tin, for example
Code:
;@name STore Zero
;@param address
;@desc writes 0 to address
;@parent STA
STZ .macro
   lda #0
   sta \1
.endm
;@end

;@name ADd with Carry offset by X Word
;@param address
;@param address
;@desc address@w + (address@w),x will clear carry
;@parent ADC
ADC_X_W .macro
   clc
   lda \1
   adc \2,x
   sta \1
   lda (\1)+1
   adc (\2)+1,x
   sta (\1)+1
.endm
;@end
This makes the code tighter, and stops my eyes getting lost in boiler plate, while allowing me to re target to say a 65816 latter and make use of its built in abilities, whilst keeping the code easy to read and allowing me to see what is used and trashed where. And 3.) take something that is custom to the situation and make it easier to read, and hence form a "MACRO Language", For Example
Code:
MOVE_NEXT_ENT .macro
    inx
    cpx #kMaxNumEnts
    .if abs(*-EntLoop) < 127
    bne EntLoop
    .else
    beq +
    jmp EntLoop

    .fi
.endm

The problem with the 3rd case is it magically requires X to be the thing it needs to be, and after you have taken a break from coding and you come back to your game, or even if you have been spending time on the Title screen logic and not touch an ent for a while, then you come back make a change and boom, bug. Why because you forgot that magic macro needs X to be Current Ent still. And after a while you will open up your macro file and find the macro and then see what went wrong. A safer way would be to make it
Code:
MOVE_NEXT_ENT .macro
    inc ENT_NUM
    ldx ENT_NUM
    cpx #kMaxNumEnts
    .if abs(*-EntLoop) < 127
    bne EntLoop
    .else
    beq +
    jmp EntLoop

    .fi
.endm
so now it just works, less efficient, but shouldn't have any issues unless you magically hope that X is not changed after the macro is "not taken". Lets make this macro
Code:
inxCpxEq .macro
    inx
    cpx \1
    .if abs(*-\2) < 127
    bne \2
    .else
    beq +
    jmp \2

    .fi

So before I had
Code:
  ... do things
  MOVE_NEXT_ENT
 .. other things

Now I have
Code:
   ... do things
  inxCpxEq #kMaxNumEnts,EntLoop
 ... other things
the 2nd case you can instantly see that it A.) uses X and relies upon X having a specific value, B.) see exactly what it compares against and C.) see exactly where it jumps to, without having to track down some other macro file, which you won't keep in alphabetical order, then look it up and be OH.. as you brain will see the text MOVE_NEXT_ENT and think, well that gets the next ent, so so problems with it, and gloss over it.

C has the pre-processor and it was used for much evil, all subsequent languages have done their best to clobber the #defines see C#, Java et al . Speak with an old time C programmer and they will tend to go Roy Batty on you ;) Macros are mermaids, they will sing to you... type less code... be more readable and you won't need to add comments.... come deeper... add more... see how nice it looks... and then when you are in the middle of the ocean, they will turn and eat you. So they are advanced, and should only be attempted by people who know what they are doing, have strong discipline and are set in their ways. The guide is if you use a MACRO language only use macros, once you start inlining normal code with the macro code you start to open your self to pain.


Top
 Profile  
 
PostPosted: Tue Jul 25, 2017 1:22 am 
Offline
Formerly WheelInventor

Joined: Thu Apr 14, 2016 2:55 am
Posts: 861
Location: Gothenburg, Sweden
A macro can have more uses than that. For example, you can set target platform in your config or at the top of main and your macros can adjust accordingly, automatically replacing a 6502 workaround with a more efficient 65816 opcode for you at assembly time without needing to search and replace.

But yeah i agree, it's a balance. You shouldn't obfuscate code just for the sake of it.

Macros not being in alphabetical order is a non-argument, though. Ctrl-F is always faster/more convenient than browsing.

_________________
http://www.frankengraphics.com - personal NES blog


Top
 Profile  
 
PostPosted: Tue Jul 25, 2017 1:25 am 
Offline
User avatar

Joined: Fri Jul 21, 2017 4:38 am
Posts: 31
You guys are breaking my 41-year-old brain. LOL


Top
 Profile  
 
PostPosted: Tue Jul 25, 2017 1:57 am 
Offline

Joined: Tue Feb 07, 2017 2:03 am
Posts: 240
FrankenGraphics wrote:
A macro can have more uses than that. For example, you can set target platform in your config or at the top of main and your macros can adjust accordingly, automatically replacing a 6502 workaround with a more efficient 65816 opcode for you at assembly time without needing to search and replace.

But yeah i agree, it's a balance. You shouldn't obfuscate code just for the sake of it.

Macros not being in alphabetical order is a non-argument, though. Ctrl-F is always faster/more convenient than browsing.
see point 2 while allowing me to re target to say a 65816 later and make use of its built in abilities ;)


Top
 Profile  
 
PostPosted: Tue Jul 25, 2017 3:04 am 
Offline
Formerly WheelInventor

Joined: Thu Apr 14, 2016 2:55 am
Posts: 861
Location: Gothenburg, Sweden
Unless i'm missing something (again then), substituting an opcode from another processor, and autoreplacement based on conditional assembly are two different uses though (even if the latter must necessarily include the first). Like letting the macro conditionally select between branch always, and clc+bcs, or even just bcs if we know the carry flag is clear, based on what processor you have defined in your config. your if directives in the macro does the rest for you.

_________________
http://www.frankengraphics.com - personal NES blog


Top
 Profile  
 
PostPosted: Tue Jul 25, 2017 4:16 am 
Offline

Joined: Tue Feb 07, 2017 2:03 am
Posts: 240
Possibly my use of "missing thing" is throwing you, by thing I mean anything you want to do easily, not instruction from CPU Z, my first example being STZ doesn't help the matter ;)

Conditional Assembly doesn't need Macros, it is its own thing. For example taking the STZ example you could just do
Code:
    ...some code
    .if CPU=="6502"
    lda #0
    sta ADDR
    .elsif CPU=="65816"
    stz ADDR
    .fi
    ...more code...
Of which you would use a Macro to make it neater, so you might be tempted to do
Code:
.macro STZ .if CPU=="6502"
    lda #0
    sta \1
    .elsif CPU=="65816"
    stz \1
    .fi

and thus

    ...some code...
   #STZ ADDR
   ...more code....
I don't recommend this, if you have a more complete assembler like TASS64 which has .weak then you can mitigate the issues but in most assemblers you can't. If you put the above in a file, then you must include and correctly define a CPU variable or else you will get assembly issues, and then when you add a new flag to them, you then have to update all your old code and so on. I feel and recommend you separate your conditional and macros such that you have
Code:
6502.mac
STZ .macro
    lda #0
    sta \1
.endm
and
65816.mac
STZ .macro
    stz \1
.endm

Then in your code file do
.if CPU=="6502"
   .include "6502.mac"
.elsif CPU=="65816"
  .include "65816.mac"
.else
  .error "CPU not set please choose 6502 or 65816"
.fi

However I also don't recommend you do this at all... replacing STZ in a macro with the intention of targeting both a NES and SNES will lead you to pain, consider the following snippet
Code:
lda #$80
sta someFlag
#STZ numSprites
sta currEnt
sta ScreenColour
On the NES this will set someFlag to $80 and numSprites, currEnt and ScreenColour to $00
On the SNES this will set someFlag to $80, numSprites to $00 and currEnt and ScreenColour to $80

The correct way to do it is, if you're NES first and want the NES outcome,
Code:
lda #$80
sta someFlag
#STZ numSprites
#STZ currEnt
#STZ ScreenColour
But then that will do a bunch of redundant LDA #0s. If you make code on the SNES and then try to back port it, it will nail you the other way. Beware of mermaids ;) Something like the BRA example you give is safer, while the ADC_X_W case is safe logically ( it will eat more bytes and more clocks on a 6502, but affects the same flags and has the same outcome if I replace it with a 16bit 65816 versions and just do LDA ADC STA at 16 bits.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 34 posts ]  Go to page Previous  1, 2, 3  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 10 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group