I figure posting on here is better than clogging up the forums.
I'm learning a lot by constructing my own kernel. I suppose the first thing to mention is that if you are drawing an asymmetric playfield, you MUST consciously draw the playfield every line. You are forced to update it every line, otherwise the right half will be displayed on the left by the time the beam comes around on the next line.
You can have a 2-line resolution, as in a playfield that has its graphics changed every two lines, but you must still must actively update the left and right sides of the screen every scanline.
Please find attached the newest version of the kernel I am writing. I dropped the missile for player0, and it still aims to have multi-coloured Player0 and Player1. The code should be well numbered and virtually complete, however erroneous it is.
The main issue I have run into now is that I wasn't updating the playfield every scanline. I was loading the left side on scanline 1,
and loading the right side on scanline 2. This would look horrible. It would have a shearing effect on the playfield graphics.
What would happen is that you would have the left side drawn three times, and then the right side drawn once, I think. It would look like this:
|===================================|=======================================||<-LEFT SIDE WRITTEN | LEFT SIDE COPIED ||===================================|=======================================|| LEFT SIDE NOT WRITTEN SO COPIED | RIGHT SIDE WRITTEN ||===================================|=======================================|
Fortunately you can write the Playfield Registers before the scanline has finished.
These are the timings for the left side:
- PF0 -- @55-22
- PF1 -- @66-28
- PF2 -- @0-38
So I think I will have to update the playfields like this:
|=======================================| PRELOAD LINE | UPDATE LEFT PF0 + PF1 (16 CYCLES) ||===================================|=======================================||UPDATE LEFT PF2, RIGHT PF0+PF1 (24)|UPDATE RIGHT PF2, LEFT PF0+PF1 (24 CYC)||===================================|=======================================|
Thinking out loud like this helps me understand what I need to do.
I have enough space in the kernel for 24 cycles per line to update the playfield, but I don't think I have enough time to use 48/76 cycles to draw an asymmetrical playfield.
I may have to write more than a 2 Line Kernel. Either that or I have to give up an asymmetric playfield. I think using Player Graphics in order to draw the environment is looking more and more likely. Either that, or I need to find a faster way to draw an asymmetric playfield.
What I am currently using to draw the playfield is a 5 cycle Indirect Indexed opcode, followed by the write to the register:
LDA (LeftPF0Ptr),y ; 5 STA PF0 ; 3
The whole thing takes 8 cycles.
I could save a cycle by using LDA ZP,X. That would make an entire updating of one side of the playfield take 21 cycles. That would mean an entire scanline of updating the playfield would have 42 instead of 48 cycles.
That would mean I'd only be spending 55% of the scanline updating the playfield instead of 63%, with 48 cycles. That's still an enormous amount of time, though.
If the asymmetric playfield took 48 cycles, I would have 28 cycles left. I would have 34 left if it took 42 cycles.
This is how long each other operation takes in the kernel:
- DoDraw for the player with no colour: 15 cycles
- DoDraw for the missile: 14 cycles
- Calculating the playfield scanline colour: 8 cycles
- DoDraw for the player with colour: 18 cycles
- Drawing the player with no colour: 3 cycles
- Drawing the player with colour:
- Loading the colour from pointer (5 cycles)
- Writing to COLUPX (3 cycles)
- Extra cycles to handle Indirect Indexing for the player graphics (3 cycles)
- STA GRP0 (3 cycles)
- 14 cycles all up.
- I think I could shave some cycles off this. I think instead of doing this:
- LDA (Player0Ptr),y - 5
- STA Player0GFX - 3
- LDA Player0GFX - 3
- STA GRP0 - 3 (Total: 14 cycles)
[*]I could do this:
- LDA (Player0Ptr),y - 5
- TAX - 2
- STX GRP0 - 3 (10 cycles)
[*]Which saves 4 cycles
So assuming I MUST change the colour of the playfield graphics every line, I use up 56 cycles every scanline drawing the asymmetric playfield using Indirect Indexed addressing.
That means I have 20 cycles left every line to do other things. My immediate thoughts right now are:
- I can sacrifice missiles for the NPCs, but now for Che
- Sacrifice the asymmetric playfield
- Sacrifice colour for the players
- Make a 3 or 4 line kernel (I have no idea how to do this)
- Draw the environment with Player Graphics (Not sure how to do this)
- Find a faster draw routine (is SkipDraw faster?)
- I know there is SkipDraw, FlipDraw, DoDraw, and SwitchDraw.
Apparently DoDraw is the slowest.
I think I'll have to give up on anymore work today and have a rest. I'm at the stage now where I can't remember how to add up numbers.