Thomas Jentzsch Posted April 9, 2011 Share Posted April 9, 2011 an alternative lda SPRITE,x ; ? abcdefgh and RorAndTbl,y ; ? abcd0000 clc adc SPRITE,x ; a bcd0efgh ror ; h abcd0efg of course you have to invert the mask(s) and if you know the carry will be clear you could leave out the clc and possibly gain a couple cycles Good catch. Quote Link to comment Share on other sites More sharing options...
ScumSoft Posted April 9, 2011 Author Share Posted April 9, 2011 (edited) I like the suggestions given so thanks for your time. I'll be working on my level generation code this weekend, after that I will fully implement these new sprite rotation ideas. Thanks for the help. Since this thread is about me posting code and getting feedback, I might as well get some feedback on my display output kernal and masking routine. I no doubt overcomplicated the design of it, so refinement is always welcome! The basic idea(implemented already and works well) I had was split the screen into 2 48-pixel sprites that are updated in sections each frame, visually like this: Then on the next frame, reposition to the right 8-pixels So in order to move a sprite, we rotate/mask an 8/16-byte buffer for each sprite we want to draw. Each strip of pixel data on the screen is indexed 0 through 5, but treated as a 12-byte index. Since both frames share a 6-byte buffer for display output I initially index 0 to 11, then translate down to which of the 6-bytes were really talking to for the next frame data. I ran into an issue with mid-byte positioning, but eventually got that figured out with the masking routine here: (Variable names changed for clarity and to address only one sprite for example purposes) ;******************************** ; [MASKING ROUTINES] ;******************************** MaskData: lda #15 ;[]+2 16 byte sprite sta Counter ;[]+3 Byte index counter lda P0slot ;[]+3 Check slot number, even or odd (indexed 0 to 11) Frame1 is even slots, 2 is odds ;- so if the player origin is in an Odd slot, then moving to the right would place him in an Even slot, and vice versa lsr ;[]+2 Odd values always have bit 1 set bcs OddSlots ;[]+2/3 Branch if carry set EvenSlots: ;Slots 0,2,4,6,8,10 in GFXoutput ;This was tricky, since I have to know which frame I am on for correct masking order lda FrameNum ;[]+3 Load current frame number and #10 ;[]+2 Frame counts 0,2[,4,6 in my 4 frame kernal], so AND with #10 to determine even/odd frames beq .MaskR ;[]+2/3 CHANGE PLACES! Mask in reverse order .MaskN ;Mask Normal order ;Data used in Frame1 ldy P0shift ;[]+3 Sprite shift amount ldx MaskTable,Y ;[]+4 Get proper bit masking by shift amount ldy Counter ;[]+3 Fetch sprite index 15 to 0 lda P0buffer,Y ;[]+4 Get sprite data to work on sax P0buffer,Y ;[]+4 Apply mask and save new data lda #$FF ;[]+2 Compare value, needed for addressing a 0 index? dcp Counter ;[]+5 Decrement and compare bne .MaskN ;[]+2/3 More sprite data to work on? rts ;[]+6 Done, return .MaskR ;Mask Reverse order ;Data will be used in Frame2 ldy P0shift ;[]+3 Sprite shift amount lda MaskTable,Y ;[]+4 Get proper bit masking by shift amount eor #$FF ;[]+2 Reverse mask tax ;[]+2 Used for SAX instruction ldy Counter ;[]+3 Fetch sprite index 15 to 0 lda P0buffer,Y ;[]+4 Get sprite data to work on sax P0buffer,Y ;[]+4 Apply mask and save new data lda #$FF ;[]+2 Compare value, needed for addressing a 0 index? dcp Counter ;[]+5 Decrement and compare bne .MaskR ;[]+2/3 More sprite data to work on? rts ;[]+6 Done, return OddSlots: ;Slots 1,3,5,7,9,11 in GFXoutput lda FrameNum ;[]+3 Load current frame number and #10 ;[]+2 Frame counts 0,2[,4,6 in my 4 frame kernal], so AND with #10 to determine even/odd frames beq .MaskN ;[]+2/3 CHANGE PLACES! Mask Normally here instead of reverse .MaskR2 ;Mask Reverse 2 ;Data will be used in Frame2 but in next slot number ldy P0shift ;[]+3 Sprite shift amount lda MaskTable,Y ;[]+4 Get proper bit masking by shift amount eor #$FF ;[]+2 Reverse mask tax ;[]+2 Used for SAX instruction ldy Counter ;[]+3 Fetch sprite index 15 to 0 lda P0buffer,Y ;[]+4 Get sprite data to work on sax P0buffer,Y ;[]+4 Apply mask and save new data lda #$FF ;[]+2 Compare value, needed for addressing a 0 index? dcp Counter ;[]+5 Decrement and compare bne .MaskR2 ;[]+2/3 More sprite data to work on? inc P0slot ;[]+5 Adjust for mid byte roll over rts ;[]+6 Done, return MaskTable: ;ShiftAMT ;$00,$01,$02,$03,$04,$05,$06,$07 .byte $FF,$7F,$3F,$1F,$0F,$07,$03,$01 It would be nice to eliminate MaskR2 as the only difference vs MaskR is that I need to increase the sprites GFXoutput slot number, as determined by being on the Oddslot set and reverse masking. I will spend more time looking at how other people manage such things and will definitely learn from them. So all the assistance I get is VERY much appreciated Edited April 9, 2011 by ScumSoft Quote Link to comment Share on other sites More sharing options...
bogax Posted April 10, 2011 Share Posted April 10, 2011 It would be nice to eliminate MaskR2 as the only difference vs MaskR is that I need to increase the sprites GFXoutput slot number, as determined by being on the Oddslot set and reverse masking. I just gave it a cursory look and am not really sure what you're doing so sorry if this is non sequitor The only difference I see between MaskR2 and MaskR is the inc POslot instruction at the end so the obvious thing would be to set a flag and inc or not depending on the flag or possibly set an increment value of 0 or 1 (if you need constant time) EvenSlots: ;Slots 0,2,4,6,8,10 in GFXoutput ;This was tricky, since I have to know which frame I am on for correct masking order lda FrameNum ;Load current frame number and #10 ;Frame counts 0,2[,4,6 in my 4 frame kernal], so AND with #10 to determine even/odd frames beq .MaskR ;CHANGE PLACES! Mask in reverse order This seems to be intended to differentiate between odd and even frames in which case you need to and #01 .MaskN ;Mask Normal order ;Data used in Frame1 ldy P0shift ;Sprite shift amount ldx MaskTable,Y ;Get proper bit masking by shift amount ldy Counter ;Fetch sprite index 15 to 0 lda P0buffer,Y ;Get sprite data to work on sax P0buffer,Y ;Apply mask and save new data lda #$FF ;Compare value, needed for addressing a 0 index? dcp Counter ;Decrement and compare bne .MaskN ;More sprite data to work on? rts ;Done, return The sax I'm (not really) familiar with takes an immediate value. so sax P0buffer,Y makes no sense to me. Counter starts out positive and counts down so bpl should do ie dec Counter, bpl .MaskN and you can leave out the lda #$FF assuming you don't need a to be $FF for some other reason (and obviously Counter will be $FF when you fall through the bpl) Quote Link to comment Share on other sites More sharing options...
ScumSoft Posted April 10, 2011 Author Share Posted April 10, 2011 I use (AND #10) since my frame counter counts only even values, so I check if I am on frames 2 or 4 for the odds. I use it as an offset to a frame jump table, so I need it to increment twice for convenience later. Otherwise I would just do a LSR to see if bit one is set for odd frames. SAX will AND the Acc with the X register and Store in memory. Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted April 10, 2011 Share Posted April 10, 2011 The basic idea(implemented already and works well) I had was split the screen into 2 48-pixel sprites that are updated in sections each frame, visually like this: Then on the next frame, reposition to the right 8-pixels It would reduce flicker, if you would not shift by 8 pixel each frame but each scanline. Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted April 10, 2011 Share Posted April 10, 2011 I use (AND #10) since my frame counter counts only even values... Not sure why you count each frame twice, but this should read AND #%10. Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted April 10, 2011 Share Posted April 10, 2011 (edited) Why are you always doing this? lda #$FF ;[]+2 Compare value, needed for addressing a 0 index? dcp Counter ;[]+5 Decrement and compare bne .MaskN ;[]+2/3 More sprite data to work on? If I didn't miss something, this works better: dec Counter ;[]+5 Decrement bpl .MaskN ;[]+2/3 More sprite data to work on? EDIT: bogax noted that already too. Edited April 10, 2011 by Thomas Jentzsch Quote Link to comment Share on other sites More sharing options...
bogax Posted April 10, 2011 Share Posted April 10, 2011 I use (AND #10) since my frame counter counts only even values... Not sure why you count each frame twice, but this should read AND #%10. OH, duh! (palm-to-forehead) (I've been wracking my brains trying to figure that one out) Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted April 10, 2011 Share Posted April 10, 2011 (edited) You should use a 2nd MaskTable to avoid EOR #$FF, tax. Also that MaskR2 loop seems superfluous. lda FrameNum ;[]+3 Load current frame number and #%10 ;[]+2 Frame counts 0,2[,4,6 in my 4 frame kernal], so AND with #10 to determine even/odd frames beq .MaskN ;[]+2/3 CHANGE PLACES! Mask Normally here instead of reverse inc P0slot ;[]+5 Adjust for mid byte roll over jmp .MaskR ;[]+3 or use a branch that fits Edited April 10, 2011 by Thomas Jentzsch Quote Link to comment Share on other sites More sharing options...
ScumSoft Posted April 10, 2011 Author Share Posted April 10, 2011 (edited) Shifting the Players each scanline takes too much time and I don't have any cycles left over to update the playfield. It would certainly look better but shifting 8 pixels is a compromise with little more flicker I've made for now. I was unaware that DEC modified the flags, so that is why I overlooked its operation. I've since updated my code where I've been using DCP thank you. [edit]You've posted while I was typing this out. If something looks really dumb then just ask me since it most likely is, I am still very new to programming and trying new things just for the sake of doing them. I was using two mask tables before and when I rewrote the Mask routines I switched to EOR #$FF for some reason, I'll switch back to the second table then. Since my 4 frame kernal flicks quite a bit I probably won't use it, but that is what FrameNum handles. It counts 0,2,4,6 which is used to index the JumpTable for which kernal to use, then in the overscan I determine what the frame was by AND #$0A (I typed AND #10 which is the same), as it returns 0 if I am on Frames 1 or 3. That way I know which order to mask the bytes in. FrameNum is incremented twice before each frame, sorry I forgot to mention this. MaskR2 is indeed superfluous, but I just couldn't think of a method to fit INC P0slot into the normal routines without a bunch of checks. So just to get things working for now I threw the extra code in till a better method is found. Which is where you come in to guide me in my ways. I'll meet anyone half way if you think the answers are so simple I should already know them, just lead the way and I'll understand. Edited April 10, 2011 by ScumSoft Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted April 10, 2011 Share Posted April 10, 2011 Oops that would be a typo on my part, it should be HEX 10, not decimal 10. so AND #$10 is the correct command. It let's me know when I am on Frames 2 and 4. Are you 100% sure? You are checking bit 3 and not bit 1. Why? Quote Link to comment Share on other sites More sharing options...
bogax Posted April 10, 2011 Share Posted April 10, 2011 It would be nice to eliminate MaskR2 as the only difference vs MaskR is that I need to increase the sprites GFXoutput slot number, as determined by being on the Oddslot set and reverse masking. Having looked a little closer It looks to me like all those loops are basically the same If you have an even slot and an even frame or if you have an odd slot and an odd frame you invert the mask. If you have an odd slot and an odd frame you inc POslot. You mention reverse order but I don't see any reverse order. I assume you want this as fast as possible, looks like there's stuff you could pull out of the loops. eg POshift doesn't change. (does it?) Quote Link to comment Share on other sites More sharing options...
ScumSoft Posted April 10, 2011 Author Share Posted April 10, 2011 Oops that would be a typo on my part, it should be HEX 10, not decimal 10. so AND #$10 is the correct command. It let's me know when I am on Frames 2 and 4. Are you 100% sure? You are checking bit 3 and not bit 1. Why? That reply I made then quickly fixed would be the typo I should proof before I hit reply. Sorry to confuse! It should be anded with decimal 10 or HEX (A). Quote Link to comment Share on other sites More sharing options...
ScumSoft Posted April 10, 2011 Author Share Posted April 10, 2011 (edited) Having looked a little closer It looks to me like all those loops are basically the same If you have an even slot and an even frame or if you have an odd slot and an odd frame you invert the mask. If you have an odd slot and an odd frame you inc POslot. You mention reverse order but I don't see any reverse order. I assume you want this as fast as possible, looks like there's stuff you could pull out of the loops. eg POshift doesn't change. (does it?) It would be rather lengthy to explain the Slot implementation I came up with, so I'll try and explain it as concise as I can. My 96-pixel playfield is segmented to a 6-byte buffer which is updated every frame, numbered 0 through 5. All sprite data is updated into this buffer each scanline ready to be drawn on the next scanline. It is an interlaced kernal with black Logic scanlines where this is performed. As such I translate the 96-pixel positions to a virtual 12-byte buffer (used abstractly in code) to determine which slot the player resides in. Say the player is in slot 0. If we shift right 3 pixels he will now be 3 pixels into slot 1. However slot 1 is drawn on Frame 2, and is really slot 0. So if I number the slots 0 through 11 instead, and then do a - lda P0slot ;Divide slot by 2 lsr ;- sta P0slot ;Save result afterwards, then I get slots 0 through 5 each frame. But I get to address the slots 0 through 11 when working on them. I'm pretty sure I overcomplicated things by nature, but this is how my brain saw it working so I implemented it to the best of my current skill set. I needed to determine which slot gets the overflowed sprite data, I didn't write any notes as to why I had to increase the slot number, but I am pretty sure it had to do with making sure the slot used during drawing frame 2 would alway match the correct overflow slot and vice versa. You can ignore the need for that routine right now if it is cumbersome to work with, I'll get it reimplemented in an elegant way later on if need be. Edited April 10, 2011 by ScumSoft Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted April 10, 2011 Share Posted April 10, 2011 That reply I made then quickly fixed would be the typo I should proof before I hit reply. Sorry to confuse! It should be anded with decimal 10 or HEX (A). Now I am completely confused. Quote Link to comment Share on other sites More sharing options...
ScumSoft Posted April 10, 2011 Author Share Posted April 10, 2011 (edited) That reply I made then quickly fixed would be the typo I should proof before I hit reply. Sorry to confuse! It should be anded with decimal 10 or HEX (A). Now I am completely confused. I have that effect on people I always meant for it to be decimal 10, but I typed by total accident that it was supposed to be Hex (10). However decimal 10 is indeed the correct one needed. [edit]Correct only in the fact that I didn't mean Hex 10 as mentioned before. AND #2 works the same for this Okay, no more confusion! Edited April 10, 2011 by ScumSoft Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted April 10, 2011 Share Posted April 10, 2011 However decimal 10 is indeed the correct one needed. That's %00001010. Really? Quote Link to comment Share on other sites More sharing options...
ScumSoft Posted April 10, 2011 Author Share Posted April 10, 2011 Ah well I supposed this is another oversight since I could just AND #2 and have it work the same way. Quote Link to comment Share on other sites More sharing options...
bogax Posted April 10, 2011 Share Posted April 10, 2011 That reply I made then quickly fixed would be the typo I should proof before I hit reply. Sorry to confuse! It should be anded with decimal 10 or HEX (A). For the first 16 values of FrameNum ie 0-15, if you and with decimal 10 you take the beq branch when FrameNum 0,1,4,5 the rest fall thru and that repeats for every subsequent 16 values. That doesn't look like odd frames to me except for the first 8 ie 0-7 The odd frames fall thru. Quote Link to comment Share on other sites More sharing options...
ScumSoft Posted April 10, 2011 Author Share Posted April 10, 2011 That reply I made then quickly fixed would be the typo I should proof before I hit reply. Sorry to confuse! It should be anded with decimal 10 or HEX (A). For the first 16 values of FrameNum ie 0-15, if you and with decimal 10 you take the beq branch when FrameNum 0,1,4,5 the rest fall thru and that repeats for every subsequent 16 values. That doesn't look like odd frames to me except for the first 8 ie 0-7 The odd frames fall thru. FrameNum only counts 4 frames, 0,2,4,6 that was it then I reset it to 0. So worry not anymore about my Frame counter, all it does is index a jump later to the correct frame kernal, which is aligned to the position offsets of P0 and P1 for drawing in the Pixel slots. You can safely disregard its use in the Masking routines. Quote Link to comment Share on other sites More sharing options...
bogax Posted April 10, 2011 Share Posted April 10, 2011 It would be rather lengthy to explain the Slot implementation I came up with, so I'll try and explain it as concise as I can. I'm just looking at your routine I don't know enough about the context it's in to tell if my assumptions are correct so let me show you my reasoning. First I'm assuming that the FrameNum is multiplied by two so that if bit one of FrameNum is set it's an odd frame and you want to and with 10 binary ldy P0shift ;Sprite shift amount ldx MaskTable,Y ;Get proper bit masking by shift amount ldy Counter ;Fetch sprite index 15 to 0 lda P0buffer,Y ;Get sprite data to work on sax P0buffer,Y ;Apply mask and save new data lda #$FF ;Compare value, needed for addressing a 0 index? dcp Counter ;Decrement and compare bne .MaskN ;More sprite data to work on? Assuming POshift doesn't change during the loop you can pull that lookup out of the loop. I'd just stick the mask in y for quick access Now you don't need to use x in the loop so why not use x for Counter? Something like: ldx POshift ldy MaskTable,x ldx #$15 .LOOP tya and P0buffer,x sta P0buffer,x dex bpl .LOOP The mask needs to be inverted if POslot and FrameNum are either both odd or both even. you can get that by eoring them. lda FrameNum lsr eor POslot lsr ;carry will be 0 if FrameNum and POslot are the same lda #$FF adc #$00 ;add that to $FF a will be 00 if carry was 1 and $FF if carry was 0 ldx POshift eor Masktable,x tay Need a flag if FrameNum and POslot are both odd so we will know to increment POslot. Here's one way: lda FrameNum lsr and POslot lsr ;carry is one if both were odd php ;stash it on the stack for later So you'd end up with something like this: lda FrameNum lsr and POslot lsr ;carry is one if both were odd php ;stash it on the stack for later lda FrameNum lsr eor POslot lsr ;carry will be 0 if FrameNum and POslot are the same lda #$FF adc #$00 ;add that to $FF a will be 00 if carry was 1 and $FF if carry was 0 ldx POshift eor MaskTable,x tay ldx #$15 .LOOP tya and P0buffer,x sta P0buffer,x dex bpl .LOOP plp bcc .SKIP inc POslot rts .SKIP I hope I got that all correct at least you should get an idea of what I'm suggesting. I expect that could be streamlined some. Obviously it's untested. 1 Quote Link to comment Share on other sites More sharing options...
ScumSoft Posted April 10, 2011 Author Share Posted April 10, 2011 Actually do see what your talking about, I'm a little too tired to check it all right now, but I'll definitely check it out. Thanks for the continued assistance. Quote Link to comment Share on other sites More sharing options...
bogax Posted April 12, 2011 Share Posted April 12, 2011 (edited) I'm still not sure if that's even close to what you want, but just for the hell of it I tryed to see how many cycles I could squeeze out of that preamble to the loop. This is the best I could come up with. If we can assume that bit 0 of FrameNum will always =0 and noting that if we add two bits (call them F, S) the sum is F eor S and the carry is F and S lda POslot ; xxxxxxS ? S=bit 0 of POslot and #$01 ; 000000S ? ora FrameNum ; xxxxxFS ? F is bit 1 of FrameNum. assumes bit 0 of FrameNum always =0 and #$03 ; 00000FS ? lsr ; 000000F S adc #$00 ; 00000AE 0 add S to F the sum, E, is F eor S the carry out, A, is F and S lsr ; 000000A E Z flag =0 for F and S =0 php lda #$FF adc #$00 ;if the carry is 1 the result will be $00 else $FF ldx POshift eor MaskTable,x tay ldx #$15 .LOOP tya and P0buffer,x sta P0buffer,x dex bpl .LOOP plp beq .SKIP inc POslot .SKIP rts Maybe I was wrong and it can't be streamlined much Only saves four cycles. Not sure it's worth it, apart from requiring bit 0 of FrameNum to be 0 its less obvious what's going on. But since you wanted to minimize cylces, there it is. Edited April 12, 2011 by bogax 1 Quote Link to comment Share on other sites More sharing options...
ScumSoft Posted April 13, 2011 Author Share Posted April 13, 2011 Yeah FrameNums bit 0 is always 0. Just needed my shifts and bit masks optimized a bit. I am no longer over cycles in the overscan and have 152 cycles left, so I am good for now. Thanks for the help! Quote Link to comment Share on other sites More sharing options...
bogax Posted April 17, 2011 Share Posted April 17, 2011 ... lsr ; 000000A E Z flag =0 for F and S =0 ... I see I goofed that comment up. Perhaps it would be better phrased like this lsr ; 000000A E Z flag will be set if F and S =0 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.