Jump to content
IGNORED

Coding tricks


Recommended Posts

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. :thumbsup:

Link to comment
Share on other sites

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:

frame1s.jpg

Then on the next frame, reposition to the right 8-pixels

frame2v.jpg

 

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 :D

Edited by ScumSoft
Link to comment
Share on other sites

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)

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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:

frame1s.jpg

Then on the next frame, reposition to the right 8-pixels

frame2v.jpg

It would reduce flicker, if you would not shift by 8 pixel each frame but each scanline.

Link to comment
Share on other sites

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 by Thomas Jentzsch
Link to comment
Share on other sites

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 by Thomas Jentzsch
Link to comment
Share on other sites

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 by ScumSoft
Link to comment
Share on other sites

 

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?)

Link to comment
Share on other sites

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).

Link to comment
Share on other sites

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 by ScumSoft
Link to comment
Share on other sites

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 :D 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 :P

Okay, no more confusion!

Edited by ScumSoft
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

 

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.

  • Like 1
Link to comment
Share on other sites

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 by bogax
  • Like 1
Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...