quohog Posted September 15, 2020 Share Posted September 15, 2020 Hi! I'm curious how some of you would treat indirect addressing in a loop like I'm about to describe. Every solution I can think of just feels clunky and I have a feeling there's an elegant way to do it just out of reach of my brain. So. I originally wrote my sound manager unlooped, duplicating all code for voice 0 and voice 1, just to get it up and running quick. Now it's bigger and I want to save ROM by putting it into a loop that you run through twice with x = 0 and then 1. Simple, right? For readability sake, lets use a simple pretend version of it below. Say it the original code looked like this: SoundManager subroutine VOICE0: ldy note_index_0 lda (notes_0),y sta AUDF0 VOICE1: ldy note_index_1 lda (notes_1),y sta AUDF1 rts So then the LOOPED version would look like: SoundManagerLooped subroutine ldx #1 VOICE_LOOP: lda note_index_0,x lda ????????????,y sta AUDF0,x dex bpl VOICE_LOOP rts (My real sound manager is way more complicated so the looping saves more space than this, I swear. :D) So can you see the part that's stumping me? The part with all the ???????? If note_index_0 and note_index_1 are both two-byte pointers into ROM, then I can't index note_index_0 with x to get the result. That will just point to the MSB of the same pointer. So I kind of want to multiply x by 2, but that doesn't seem worth the cycles. So right now I'm using a branch: cpx #0 bne do_voice_1 lda (notes_0),y jmp SET_NOTE do_voice_1: lda (notes_1),y SET_NOTE: sta AUDF0,x But that makes me feel dirty and wasteful. And when I did it that way, I only shrunk my routine by 30%, when I was hoping to cut it in half. So is there just some simple answer using clever addressing modes? Or some change I can make to my layout of pointers? I'm afraid the answer is going to be like when you go to the doctor and say, "Doc, my finger hurts when I bend it like this," and the doctor says, "Okay, so don't bend it like that." ? Anyway, thanks for reading. Any suggestions are appreciated. Quote Link to comment Share on other sites More sharing options...
Omegamatrix Posted September 15, 2020 Share Posted September 15, 2020 Sometimes a loop does not save bytes or save as many as you would like. Typically in your example people might try and do something like this: ldx #1 .loopVoices: ldy note_index,X lda (notes),y sta AUDF0,X dex bpl .loopVoices rts To do that both notes for AUDF0 and AUDF1 must be close together and small enough to be indexed by just one pointer. While the loop itself saves 1 byte, the overhead removed for setting the other pointer will save a few more. If the notes are small enough then you might as well align it to a page and use Absolute Y indexing instead of ZP Y. ldx #1 .loopVoices: ldy note_index,X lda Notes,y sta AUDF0,X dex bpl .loopVoices rts Now the loop saves no bytes, but not setting a pointer does (and saves ram). In general: - Try and use the X register as much as possible for zeropage ram indexing, because it saves a byte over using Y. - Look for opportunities to move rom around, so that a pointer doesn't have to be set at all. - If a subroutine is only used once, put it inline instead. 1 Quote Link to comment Share on other sites More sharing options...
quohog Posted September 15, 2020 Author Share Posted September 15, 2020 Thanks, @Omegamatrix! I think my example was misleading. I'm using the pointers because notes_0 might be pointing to one of my sounds in ROM (Eg: SOUND_BELL) and note_1 could be pointing to another (Eg: SOUND_WHACK). So totally arbitrary ROM addresses. Not an orderly list of notes. If that's any clearer. Quote Link to comment Share on other sites More sharing options...
+Andrew Davie Posted September 15, 2020 Share Posted September 15, 2020 For this situation I'd use two blocks of code, like your original version. Anything else looks ugly to me - self-modifying code being one possibility but I can't see any speed savings, and would cost ROM anyway. 1 Quote Link to comment Share on other sites More sharing options...
vitoco Posted September 15, 2020 Share Posted September 15, 2020 9 hours ago, quohog said: So right now I'm using a branch: cpx #0 bne do_voice_1 lda (notes_0),y jmp SET_NOTE do_voice_1: lda (notes_1),y SET_NOTE: sta AUDF0,x But that makes me feel dirty and wasteful. I'm doing almost the same thing in my own routine, but twice, because I put both (C+V) and (x+F) bytes in a single stream of data (as words instead of bytes), increasing Y register twice in a loop to read both. "x" would be a duration indicator using the upper 3 bits of the frecuency byte (not implemented yet). 6 hours ago, Andrew Davie said: For this situation I'd use two blocks of code, like your original version. Anything else looks ugly to me Ouch! Well, it also looks ugly to me. I'll turn into two blocks and see how much better it looks. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.