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.
Is there a better way to INX 4 times?
Moderator: Moderators
- FrankenGraphics
- Formerly WheelInventor
- Posts: 2064
- Joined: Thu Apr 14, 2016 2:55 am
- Location: Gothenburg, Sweden
- Contact:
- 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?
What a neat tip! I don't mind wasting space, PRG is cheap compared to other things one can waste on the NES.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:
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.Code: Select all
lda ByteTable+4, x tax
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.
-
- Posts: 1565
- Joined: Tue Feb 07, 2017 2:03 am
Re: Is there a better way to INX 4 times?
passing in a list, and then size checking each item in the list would be the more complete way of doing it
to which you then invoke it with #STZ ( myByte, myWord, otherByte ) Then it will output 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
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
Code: Select all
lda #0
sta myByte
sta myWord
sta myWord+1
sta otherByte
Last edited by Oziphantom on Wed Jul 26, 2017 1:39 am, edited 1 time in total.
- 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?
Not extending bytes to words, the thing i came up with was this:
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.
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