Is there a better way to INX 4 times?

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

User avatar
FrankenGraphics
Formerly WheelInventor
Posts: 2064
Joined: Thu Apr 14, 2016 2:55 am
Location: Gothenburg, Sweden
Contact:

Re: Is there a better way to INX 4 times?

Post by FrankenGraphics »

At lunch, i was trying to think of a solution that would automatically identify if a #stz is to be laid down directly after another, but i'm not familiar with TASS64 and not aware of a ca65 directive that'd be helpful.

Less elegantly, you could of course do it like this:

.macro name addr, anyArg
.ifp02 ;this is ca65:s check if target is 6502
.ifblank (anyArg) ;omitting anyArg is considered normal operation.
lda #0
sta addr
.else ;this is for saving cycles/bytes on the 6502 specifically
sta addr
.endif
.endif
[other processors go here, treat as normal]
.endm

call it like this:
name addr ; lays down lda + sta on 6502, stz on 65816
name addr foo ;lays down just sta on 6502, stz on 65816
name addr foo ;same

Rather than requiring a special value of anyArg, just having one there will tell the assembler to optimize the output for 6502 targets. It will behave, but requires you to know how to interface with the "optimization option", which will require proper commenting in return.


Alternately, you could make a call like this:

name addr1, addr2, addr3 (and so on)

And have a macro which will know how many iterations to run by the number of arguments, and lay down the proper opcodes for you automatically. That's better, but with the caveat that you have a maximum of iterations/arguments defined by how you wrote the macro. I think i'd go with that.
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Re: Is there a better way to INX 4 times?

Post by GradualGames »

tokumaru wrote:I usually reserve a page of ROM for values $00-$ff, so if I wanted I could do the following to increment X by 4:

Code: Select all

  lda ByteTable+4, x
  tax
This is a little faster than INX x4 (6 cycles vs. 8) while also occupying 4 bytes, but I definitely wouldn't use 256 bytes of ROM just for this. This table has many other uses though, such as simulating TXY ("ldy ByteTable, x") and TYX ("ldx ByteTable, y") instructions, in addition to the quick increments/decrements by constant numbers to index registers.

Many would consider this table a waste of space, but it has already made it possible for me to avoid temporary variables and also write slightly faster code in loops (thus saving a significant amount of cycles), by making the index registers more capable than usual.
What a neat tip! I don't mind wasting space, PRG is cheap compared to other things one can waste on the NES.
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: Is there a better way to INX 4 times?

Post by Oziphantom »

passing in a list, and then size checking each item in the list would be the more complete way of doing it

Code: Select all

IsParamDirectAddress .function i; i.e. $30 or $d020 not VIC_BACKCOL etc
.endf type(i) == bits

STZ .macro
    .for z = 0, z < len(\1), z = z + 1
        lda #0 
        .proff
            .if IsParamDirectAddress(\1[z])
                .pron
                    sta \1[z]
                .proff
            .else
                .pron
                    sta (\1[z])+range(size(\1[z]))
                .proff
            .endif
        .pron
    .next 
.endm
to which you then invoke it with #STZ ( myByte, myWord, otherByte ) Then it will output

Code: Select all

lda #0
sta myByte
sta myWord
sta myWord+1
sta otherByte
sadly tass doesn't have a way to detect the current size of A or index in 65816 mode, so it can rep/sep as needed and assert that its in the right mode. So for 65816 extra macros that silently pass-though to the main on on 6502 are still needed. However such features are on the developers list of "to add", along with collapsible rep/seps . Once the optimiser pass is good enough that we can trust it to automatically handle optimisations or at least trivial cases, it could just remove the extra LDA #0 from doing repeated #STZ making the above moot ;)
Last edited by Oziphantom on Wed Jul 26, 2017 1:39 am, edited 1 time in total.
User avatar
FrankenGraphics
Formerly WheelInventor
Posts: 2064
Joined: Thu Apr 14, 2016 2:55 am
Location: Gothenburg, Sweden
Contact:

Re: Is there a better way to INX 4 times?

Post by FrankenGraphics »

Not extending bytes to words, the thing i came up with was this:

Code: Select all

.macro recurse_stz a1, a2, a3, a4, a5, a6, a7, a8 
;------------------------------------------------------------
;Used inside macro mstz. Can also be called next after a mstz 
;to wipe up to another 8 targets.  
;------------------------------------------------------------	
	.ifblank a1 ;if no arguments are left on the macros' pseudo-stack, exit. 
		.exitmac
	.else
		.ifp02 
			sta a1 ;NOTE! This assumes you've already set A to 0, persumably via .macro mstz
		.else ; assume a processor with opcode stz
			stz a1 
	.endif
	recurse_stz a2, a3, a4, a5, a6, a7, a8	;pipe all remaining arguments in a recursion: a2 -> a1, a3-> a2 and so on.   
.endm


.macro mstz addr1, addr2, addr3, addr4, addr5, addr5, addr6, addr7, addr8 
;------------------------------------------------------------
;Description: 
;Target agnostic STZ substitute. "mstz" stands for macro stz, 
;to differentiate it from the opcode mnemonic "STZ".
;Behaviour:
;For 6502, it will lay down 1 LDA immediate, 
;and n STAs where n is the number of given arguments (max 8).
;For anything else/undefined, it will lay down n STZ:s
;Affects:
;A in 6502 mode, none in any other mode.
;------------------------------------------------------------
	.if .paramcount = 0
		.warning  "mstz: No arguments were passed; macro ignored."
		.exitmac 
	.endif 
	.ifp02 ;6502 has no stz, so we need to load a #0 in preparation
		lda #0 ;NOTE! This affects the A register, unlike STZ
	.endif
	recurse_stz addr1, addr2, addr3, addr4, addr5, addr5, addr6, addr7, addr8
.endm
But even so, you could potentially run into worries - you must know that you don't need to keep whatever was in A when porting a block using this macro from 65816 to 6502. So i guess that proves your point about mermaids.
Post Reply