Slick Kernel
With my prior DPC+ kernels, I used an Event Datastream that would tell the kernel to jump out of its normal loop. After that, the 6507 would spent a lot of CPU time deciding if it was supposed to reposition player 0, reposition player 1, or if it was all done drawing the game display.
I got to thinking and came up with a way were the 6507 no longer has to make any kernel decisions - instead of having an Event Datastream, just have a Jump Datastream. Every entry in the Jump Datastream is initialized with the address of NormalKernel. When a player needs to be repositioned the C code just changes the appropriate Jump Datastream entry to point to the proper reposition kernel.
NormalKernel: ; 19 lda #<DS_NUSIZ_COLUPF ; 2 21 ' resize players/missiles, color for ball lda #<DS_COLUP_HMMB ; 2 23 ' use for missile/ball HMxx ldx DS_GRP1 ; 4 27 lda #<DS_JUMP ; 2 29 sta NextKernel ; 3 32 lda #<DS_JUMP ; 2 34 sta NextKernel+1 ; 3 37 sta HMCLR ; 3 40 ' reset missile/ball HMOVE lda #<DS_HMP0 ; 2 42 sta HMP0 ; 3 45 lda #<DS_HMP1 ; 2 47 sta HMP1 ; 3 50 lda #<DS_GRP0 ; 2 52 sta GRP0 ; 3 55 <- on VDEL, for next scanline lda #<DS_M1M0BL ; 2 57 <- on VDEL, for next scanline sta ENABL ; 3 60 lsr ; 2 62 sta WSYNC ; 3 65/0 R76: ; A holds M0 and M1 ; X holds GRP1 ; GRP0 and BL on VDEL sta HMOVE ; 3 3 stx GRP1 ; 3 6 sta ENAM0 ; 3 9 lsr ; 2 11 sta ENAM1 ; 3 14 jmp (NextKernel) ; 5 19
The prior kernels would then have special reposition routines for the players that would take multiple scanlines to process. In Frantic it takes 4 scanlines while in Space Rocks it takes 2. Without the extra "which event" logic, the time to reposition a player is now down to 1 scanline:
Here's 1 of the 11 reposition kernels for player 0
Resp0Strobe23: ; 19 sta.w RESP0 ; 4 23 lda #<DS_NUSIZ_COLUPF ; 2 25 sta NUSIZ0 ; 3 28 lda #<DS_COLUP_HMMB ; 2 30 sta COLUP0 ; 3 33 ldx DS_GRP1 ; 4 37 lda #<DS_JUMP ; 2 39 sta NextKernel ; 3 42 lda #<DS_JUMP ; 2 44 sta NextKernel+1 ; 3 47 sta HMCLR ; 3 50 ' reset missile/ball HMOVE lda #<DS_HMP0 ; 2 52 sta HMP0 ; 3 55 lda #<DS_HMP1 ; 2 57 sta HMP1 ; 3 60 lda #<DS_GRP0 ; 2 62 sta GRP0 ; 3 65 <- on VDEL, for next scanline lda #<DS_M1M0BL ; 2 67 <- on VDEL, for next scanline sta.w ENABL ; 4 71 lsr ; 2 73 jmp R76 ; 3 76
and here's one for player 1
Resp1Strobe23: ; 19 sta.w RESP1 ; 4 23 lda #<DS_NUSIZ_COLUPF ; 2 25 sta NUSIZ1 ; 3 28 lda #<DS_COLUP_HMMB ; 2 30 sta COLUP1 ; 3 33 ldx DS_GRP1 ; 4 37 lda #<DS_JUMP ; 2 39 sta NextKernel ; 3 42 lda #<DS_JUMP ; 2 44 sta NextKernel+1 ; 3 47 sta HMCLR ; 3 50 ' reset missile/ball HMOVE lda #<DS_HMP0 ; 2 52 sta HMP0 ; 3 55 lda #<DS_HMP1 ; 2 57 sta HMP1 ; 3 60 lda #<DS_GRP0 ; 2 62 sta GRP0 ; 3 65 <- on VDEL, for next scanline lda #<DS_M1M0BL ; 2 67 <- on VDEL, for next scanline sta.w ENABL ; 4 71 lsr ; 2 73 jmp R76 ; 3 76
The major benefit of not having the 6507 spend CPU time making decisions is we can now also do mid-screen repositioning of both missiles:
Resm0Strobe23: ; 19 sta.w RESM0 ; 4 23 lda #<DS_JUMP ; 2 25 sta NextKernel ; 3 28 lda #<DS_JUMP ; 2 30 sta NextKernel+1 ; 3 33 lda #<DS_NUSIZ_COLUPF ; 2 35 sta NUSIZ0 ; 3 38 sta HMCLR ; 3 41 ' reset missile/ball HMOVE ldx DS_GRP1 ; 4 45 lda #<DS_COLUP_HMMB ; 2 47 sta HMM0 ; 3 50 lda #<DS_HMP0 ; 2 52 sta HMP0 ; 3 55 lda #<DS_HMP1 ; 2 57 sta HMP1 ; 3 60 lda #<DS_GRP0 ; 2 62 sta GRP0 ; 3 65 <- on VDEL, for next scanline lda #<DS_M1M0BL ; 2 67 <- on VDEL, for next scanline sta.w ENABL ; 4 71 lsr ; 2 73 jmp R76 ; 3 76 Resm1Strobe23: ; 19 sta.w RESM1 ; 4 23 lda #<DS_JUMP ; 2 25 sta NextKernel ; 3 28 lda #<DS_JUMP ; 2 30 sta NextKernel+1 ; 3 33 lda #<DS_NUSIZ_COLUPF ; 2 35 sta NUSIZ1 ; 3 38 sta HMCLR ; 3 41 ' reset missile/ball HMOVE ldx DS_GRP1 ; 4 45 lda #<DS_COLUP_HMMB ; 2 47 sta HMM1 ; 3 50 lda #<DS_HMP0 ; 2 52 sta HMP0 ; 3 55 lda #<DS_HMP1 ; 2 57 sta HMP1 ; 3 60 lda #<DS_GRP0 ; 2 62 sta GRP0 ; 3 65 <- on VDEL, for next scanline lda #<DS_M1M0BL ; 2 67 <- on VDEL, for next scanline sta.w ENABL ; 4 71 lsr ; 2 73 jmp R76 ; 3 76
as well as the ball
ResblStrobe23: ; 19 sta.w RESBL ; 4 23 lda #<DS_JUMP ; 2 25 sta NextKernel ; 3 28 lda #<DS_JUMP ; 2 30 sta NextKernel+1 ; 3 33 lda #<DS_NUSIZ_COLUPF ; 2 35 sta COLUPF ; 3 38 sta HMCLR ; 3 41 ' reset missile/ball HMOVE ldx DS_GRP1 ; 4 45 lda #<DS_COLUP_HMMB ; 2 47 sta HMBL ; 3 50 lda #<DS_HMP0 ; 2 52 sta HMP0 ; 3 55 lda #<DS_HMP1 ; 2 57 sta HMP1 ; 3 60 lda #<DS_GRP0 ; 2 62 sta GRP0 ; 3 65 <- on VDEL, for next scanline lda #<DS_M1M0BL ; 2 67 <- on VDEL, for next scanline sta.w ENABL ; 4 71 lsr ; 2 73 jmp R76 ; 3 76
It might take a bit of time to digest that code, so here's a summary of what it can do:
- any object (player0, player1, missile0, missile1 or ball) can be repositioned in a single scanline. In the time Frantic takes to reposition 1 player we can now reposition 4 objects.
- players can be set for any size when they're repositioned. In theory they can also be set for duplicate and triplicate, but we don't use that feature because it conflicts with missile usage (ie: if a player is set for multiple copies, so is the corresponding missile).
- players can be set for any color when they're repositioned. Single color sprites only, like seen in Space Rocks. It doesn't support line-by-line color changes like in Frantic.
- players can be shifted right/left on any scanline, which creates the illusion that 2x and 4x sized sprites have more than 8 pixels of horizontal detail. See reply 16 in the Space Rocks homewbrew topic if you're not sure what this means.
- missiles can be set to any size (sizes are 1x, 2x, 4x and 8x) when the missile is repositioned.
- ball color can be changed whenever its repositioned.
The above code has been tested and confirmed to work. A project that takes advantage of these routines will soon be announced.
- 2
23 Comments
Recommended Comments