Jump to content
KevKelley

Pfpixel vs Playfield Variable

Recommended Posts

I had been reading about playfield variables and was curious if there would be any benefit versus using pfpixel to turn on or off playfield pixels? Less cycles? Less bytes? Or if there is no real discernable difference except how it may work with a particular line of code one may fit better?

Share this post


Link to post
Share on other sites

The bB page says that pfpixel uses 80 processor cycles every frame. Compare that to turning bits off and on:

 

randomterrain.com/atari-2600-memories-batari-basic-commands.html#cycle_count_bitop

 

If you are using the DPC+ kernel, there are no playfield variables that we can mess with, if I remember correctly.

Share this post


Link to post
Share on other sites

This was standard kernel. I was just trying to slowly understand the workings under the hood. I was gonna play around with using either/or to see if there is a difference. 

 

I had came across it in my reading to try and figure out a workable alternative to what I had done and get the same effect. Currently I had pfpixels moving around. I tried to limit their appearance with all else going on and came across that. I will play around with it later on lunch and update on my findings.

 

Thanks!

Share this post


Link to post
Share on other sites

So I swapped my code with using playfield variables versus turning on or off a pfpixel.  From what I can tell it seems as though it uses less cycles.  I didn't delve entirely into the debugger but I ran the program for a while and under different conditions that the over cycle had occurred with and I did not experience it so I am thinking it may be fixed.  Also on a plus side it uses about 300 bytes less.

I changed this:

 

 if counter = 43 then pfpixel 31 7 on:pfpixel 25 7 off    
 if counter = 51 then pfpixel 30 7 on :pfpixel 31 7 off 
 if counter = 59 then pfpixel 29 7 on :pfpixel 30 7 off 
 if counter = 66 then pfpixel 28 7 on :pfpixel 29 7 off 
 if counter = 73 then pfpixel 27 7 on :pfpixel 28 7 off 
 if counter = 87 then pfpixel 26 7 on :pfpixel 27 7 off 
 if counter = 92 then pfpixel 25 7 on:pfpixel 26 7 off
 if counter =99 then pfpixel 25 7 off

to this:

 if counter = 43 then var31=%10000000   
 if counter = 51 then var31=%01000000   
 if counter = 59 then var31=%00100000   
 if counter = 66 then var31=%00010000   
 if counter = 73 then var31=%00001000   
 if counter = 87 then  var31=%00000100   
 if counter = 92 then var31=%00000010    
 if counter =99 then var31=%00000000   

I understand that my initial method was probably very wasteful and there may be an even better method but I thought this was a good exercise in trying to understand pfpixels and use different ways to change the playfield.

  • Like 1

Share this post


Link to post
Share on other sites

I really want to use pfpixel for procedurally drawn screens.  Alas,  what I've found is that using several pfpixel commands does indeed exacerbate CPU cycle problems.  Also, it seems to use up more ROM space using pfpixel commands than playfield screen sections.  Big bummer there 😕

 

My experiences could very well be my poor coding style in combination with using pfpixel in an unintended way :)

 

I suspect this is something we'll have to make a custom community version of pfpixel to get closer to some of our needs.  Kind of like what we did for the multi sprite kernel pfread.

Share this post


Link to post
Share on other sites

Seeing how this worked, I am going to play around with it and see what is possible. It did surprise me how much was saved. It also makes me wonder how this compares to pfhline of pfvline. I might be able to free up even more!

  • Like 1

Share this post


Link to post
Share on other sites

The game I'm working on would draw pfpixels on a timer and as you can see from the code I posted, I also had it turn on and off pfpixels in a row. I experienced overcycling so I shifted when these were drawn, hence the weird counter numbers like 43 or 87. That kind of worked but I didn't consider other factors like if a pfpixel is removed or potential collision detection with a missile. I do see how pfpixel could work better than a playfield variable but I can see how this could be very beneficial.

 

I wanna learn more about what goes on under the hood and why this uses less. In Bag Boy and Manatee Madness I essentially redraw the entire (or parts) of the playfield and it never had overcycle problems versus a couple pixels being turned on simultaneously. I guess this gets me closer to learning assembly...

Share this post


Link to post
Share on other sites

do fewer if statements

 

  temp1 = counter/8 - 5
  if !counter & 7 && temp1 < 8  then var31 = dat[temp1]

  data dat
  $80, $40, $20, $10, $08, $04, $02, $00
end 

  • Like 2

Share this post


Link to post
Share on other sites

Ah. I have been slow to use data statements but I understand the principles. I suppose in this instance it would work well because it is a sequence versus a one-off. I will definitely have to check this out later. I was planning on trying to play around with these variables to see how far I can push it.

Share this post


Link to post
Share on other sites
Posted (edited)
18 hours ago, Gemintronic said:

I really want to use pfpixel for procedurally drawn screens.  Alas,  what I've found is that using several pfpixel commands does indeed exacerbate CPU cycle problems.  Also, it seems to use up more ROM space using pfpixel commands than playfield screen sections.  Big bummer there 😕

 

My experiences could very well be my poor coding style in combination with using pfpixel in an unintended way :)

 

I suspect this is something we'll have to make a custom community version of pfpixel to get closer to some of our needs.  Kind of like what we did for the multi sprite kernel pfread.

Yep, from my experience and experimentation i get the same results that pfpixel can be very costly in both ROM and cycles. I suspect when the code is cross compiled to asm it bloats substantially causing high ROM usage and demanding lots of processing time. It;s all good for a few pixels flipped a frame yet drawing full screen is not even feasible with the pfpixel command. It seems data tables is the better method

Edited by TwentySixHundred
  • Like 1

Share this post


Link to post
Share on other sites
10 hours ago, bogax said:

do fewer if statements

 

 

  temp1 = counter/8 - 5
  if !counter & 7 && temp1 < 8  then var31 = dat[temp1]

  data dat
  $80, $40, $20, $10, $08, $04, $02, $00
end 

 

Thanks!  I just swapped the code and this uses 40 less bytes.

 

7 minutes ago, TwentySixHundred said:

Yep, from my experience and experimentation i get the same results that pfpixel can be very costly in both ROM and cycles. I suspect when the code is cross compiled to asm it bloats substantially causing high ROM usage and demanding lots of processing time. It;s all good for a few pixels flipped a frame yet drawing full screen is not even feasible with the pfpixel command. It seems data tables is the better method

I started to play around with my my pfhlines to see if this would also help.  For a short pfhline of about 5 pixels I was able to save about 50 bytes BUT I found that if my line extended across a couple playfield variables it may not be worth using it because then I would have to write up some checks to make sure the right pixels turn on or off.  This may be helpful later on.  I had experienced an issue earlier on where I was trying to turn off a long pfhline and ran into some overcycling so I solved it by having it turn off shorter segments on a timer.  This might help free up some more space and cycles.

Share this post


Link to post
Share on other sites

my point was that you're doing a bunch of if statements that you don't need to do most of the time

 

actually this makes more sense

and if that last byte in the table is meant to be a 1 then you could use the

table the kernel uses

 

  const v31_data = setbyte


  if counter & 7 then skip_v31
  temp1 = counter/8 - 5
  if temp1 < 8  then var31 = v31_data[temp1]
skip_v31

  • Like 1

Share this post


Link to post
Share on other sites

I understand it makes sense. I know my code is probably bloated with unnecessary statements. As I have been coming up with things I plug it in and see what works. 

 

I had one question. What do you mean by the table the kernel uses? Looking at your code I assume that each playfield variable is set up using a table so instead of making a new data table for the variable you just alter the existing one?

Share this post


Link to post
Share on other sites

the kernel has a table called setbyte that it uses for setting pixels in the playfield and other stuff

it varies depending on how the playfield is structured

in this case it would be (in bB) something like

 

 

  data setbyte

  $80, $40, $20, $10, $08, $04, $02, $01, $01, $02, $04, $08, $10, $20, $40, $80, $80, $40, $20, $10, $08, $04, $02, $01, $01, $02, $04, $08, $10, $20, $40, $80

end

 

I just made v31_data an alias for setbyte (which was totally unnecessary)

 

playfield statements get their own tables for the whole playfield

Share this post


Link to post
Share on other sites

it's true it uses less ROM but the point is it uses less time (and something closer to only the time necessary)

 

Share this post


Link to post
Share on other sites

I guess I never really worry about time until it is too late. I know I tend to try to code and then tweak things after to see how I can improve, comparing my original code to see what I can do differently in the future. I still got lots to learn and am very thankful for your explanations. 

Share this post


Link to post
Share on other sites
Posted (edited)


  I didn't explain very well
  Perhaps some of this is not as obvious as I think

 

  (I'm thinking) we're optimizing for time

 

  First thing I note is that you test for counter values
  and when you find one, you set var31 then test for more values that you 
  know it can't be.

 

  Usually I think of a table look up as (probably) trading ROM space for speed.

 

  In this case you said you'd chosen "weird counter numbers" for timing so I regularized
  The intervals and added a guard condition for multiples of 8
  ie
 

  if counter & 7 then ..
  

  so now 7 out of 8 times you only do one if test

 

  If you really needed the weird numbers you could still
  eg test for values between say, 40 and 100 and skipped 40% of the time
  (if your counter went 0..100) and done only two tests

 

  That's more code and more time but it's probably a net gain

 

  You could go farther and test for numbers that are
  eg equal to - greater than an even multiple of 4 but less than the next odd multiple

  (if that fit the values you were looking for)
  that would add another test but cut out half the possibilities
 

  if counter & 4 then
  

 

  You might do a binary search if you had more weird values

 

  Or you might use a look up table, but then you'd need like 60 entries
  if the values could be anything 40..100

 

  A look up table would still be lot faster even if it didn't save any space
  I didn't really figure it out, but I think in this case
  you'd still save a few bytes of ROM

  And tables can be completely arbitrary

 

  none of this needs assembly

 

  except perhaps to have an idea of the time and space

 

  I would certainly encourage you to learn the assembly

  and read the list file to see what you're getting

 

  and a bit of assembly can be really useful even if you're using bB

 

  I especially like RevEng's suggetion (somewhere in this forum) of getting the assembler 
  to print the difference (amount of code) between two lables
 

Edited by bogax
clarify

Share this post


Link to post
Share on other sites

I plan on looking through the assembly to kind of learn more. I bought the Atari programming book but haven't delved into it too much but I've been looking at all the forum topics to try and get familiar with how it looks and works for when I eventually play around with it. 

 

In my program, when I mentioned "weird" values, what I meant was that when I first ran into overcycling issues I changed some values. I generally have a pfpixel drawn when counter reaches 100. Player0 can also pick up pfpixels. Originally I had the values on the counter at an even set of intervals and it seemed that when it drew and erased too many pfpixels at once it would over cycle. My original attempt at troubleshooting was to just change the values to avoid everything happening all at once until I could figure out a better way. For the most part it worked but it really seemed to just kick the can down the road. When I read about playfield variables it got me thinking.

 

 

Share this post


Link to post
Share on other sites

Now I do wonder, I see the playfield variables are formatted something like var31=%00000000.

 

Is it possible to turn on a single bit from that, like var31{4}=1? Would that essentially work like a pfpixel on/off command? 

 

(I don't have my computer with me otherwise I would run a simple test on my own )

Share this post


Link to post
Share on other sites
3 hours ago, KevKelley said:

Now I do wonder, I see the playfield variables are formatted something like var31=%00000000.

 

Is it possible to turn on a single bit from that, like var31{4}=1? Would that essentially work like a pfpixel on/off command? 

 

(I don't have my computer with me otherwise I would run a simple test on my own )

 yes, but you can't calculate the bit specified
 the number in the brackets has to be a number literal not a variable or an expression

 and it doesn't always show an error if eg you use a variable


 you don't have to do all eight bits if you use the table

 

 dim bitstoswap = b
 dim idx = i

 

 const sbits0 = setbyte + 8


 ; set a bit
 var31 = var31 | sbits0[idx]

 ; clear a bit
 var31 = (sbits0[idx] ^ %11111111) & var31

 ; swap in bits 2, 3, 6
 var31 = ((sbits0[idx] ^ var31) & %01001100) ^ var31

 ; swap in bits 2, 3, 6
 var31 = ((var31 ^ bitstoswap) & %01001100) ^ var31

 


 it would be nice to build macros
 but bB macros are just DASM macros and DASM wouldn't
 understand the indexing so it would have to be done
 in ASM

 

 dim idx = i 

 

 const sbits0 = setbyte + 8


 def set_bit = callmacro stb_m

 def clear_bit = callmacro clb_m


 ; parameters target variable, number of bit to set
 macro stb_m
 asm
 ldx {2}
 lda sbits0,x
 ora {1}
 sta {1}
end
end

 

 ; parameters  target variable, number of bit to clear
 macro clb_m
 asm
 ldx {2}
 lda sbits0,x
 eor #$FF
 and {1}
 sta {1}
end
end

 

 ;  usage
 set_bit var31 idx

 clear_bit var31 idx

 


 

Share this post


Link to post
Share on other sites

Cool. I was looking at bitwise operations on lunch. It is something I haven't really done much with but I see how this can definitely help. When I first started these were probably the more confusing aspects of programming to me. I am slowly getting it. Thanks so very much!

 

 

Share this post


Link to post
Share on other sites

As for overcycle and pfpixel when too many pixels are flipped on a single frame you can just set a _skp label if one those flip conditions are met. Provided, if all your condition statements are in a single code block and a pfpixel flip is executed then goto _skp label. This will ensure for that frame the pfpixel command isn't executed more then once per frame. Spreads the load over multiple frames

Share this post


Link to post
Share on other sites

Yeah. Since I have essentially 3 different code blocks for the generation, elimination, and other pfpixels, that wouldn't work unless I consolidated the code.

 

Another solution I had thought of was to assign a bit and if I pfpixel is picked up it would flip, disable the unnecessary code for a frame, and then reset. Or have a variable so that if the box is picked up at the same time the counter hits a number than to add that variable to the other code. 

 

In the end using the playfield variables was much better. Plus I learned something nee. That I can apply to more applications in the future.

Share this post


Link to post
Share on other sites

When I last left off trying to turn on different different bit from the playfield variables. So after playing around some, i started messing around with XOR commands to change my pfhline draws and it seemed to work well, freeing up a little over 100 bytes.  

 

So I changed this:

 if e{0} then var4=%11111100
 if e{1} then pfhline 6 1 9 on
 if e{2} then pfhline 11 1 14 on
 if e{3} then pfhline 16 1 19 on
 if e{4} then pfhline 21 1 24 on

to this:

 if e{0} then var4=var4^%01111000
 if e{1} then var4=var4^%00000011:var5=var5^%00000011
 if e{2} then var5=var5^%01111000
 if e{3} then var6=var6^%11110000
 if e{4} then var6=var6^%00000111:var7=var7^%00000001

I had started using playfield variables, which is why e{0} originally had a variable but when I got into e{1} and e{4} it stretched over two variables.  Initially I wasn't sure how to flip the bits which is why I kept the pfhlines temporarily.  I use pfhlines in a couple more spots in my program so I will have to fix that up too, which should free up some space.

 

 

Share this post


Link to post
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.

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