Jump to content
IGNORED

"Sierra Maestra", an Early WIP


vidak

Recommended Posts

I believe you forgot to clear the HMP0 value to 0 after positioning Player 0. Every time you strobe HMOVE, it moves all the objects that aren't set to 0. Calling sta HMCLR resets all HMxx registers to 0. If you do that after positioning Player 0, I think it will fix all the issues. But be careful not to write to HMCLR right after HMOVE. You need to wait 20+ cycles or so to keep from messing up the HMOVE operation.

 

When I submitted this post, I saw SpiceWare had covered this already. :D

 

Another thing I learned is that if you are doing an HMOVE at cycle 73 rather than after WSYNC (to avoid the black "comb" lines, like in my Nyan Cat project), the HMxx values are different so that a zero actually moves the object. You would have to set each non-moving object's HMxx to #$80 instead.

 

Here's a handy link to a table that shows how much HMOVE will move each object and in which direction, depending on when you strobe HMOVE during a scanline (the table is at the bottom).

Edited by JeremiahK
Link to comment
Share on other sites

Another thing I learned is that if you are doing an HMOVE at cycle 73 rather than after WSYNC (to avoid the black "comb" lines, like in my Nyan Cat project), the HMxx values are different so that a zero actually moves the object. You would have to set each non-moving object's HMxx to #$80 instead.

 

 

Strobing HMOVE will raise a flag that causes horizontal blanking to be extended by 8 color clocks. Each sprite is essentially a counter that is not clocked during hblank, and so this will effectively move the sprite 8 pixels to the right (as it will take 8 more color clocks until the counter reaches the value that triggers rendering); the side effect are the black lines.

 

In order to facilitate other movement values, strobing HMOVE will trigger the TIA to start sending extra clock pulses that will drive the sprite counters. The amount of pulses that is sent to each sprite depends on the value of the high nibble of HMXX. The highest bit is internally inverted, so a value of 0 will cause 8 extra clocks, amounting to zero movement, 7 will cause 15 extra clocks, amounting to 7 pixels movement to the left.

 

During the visible part of the scanline, the extra clocks will interfere with the regular clock pulses. The details depend on the exact TIA revision; it is assumed that, on most chips, the extra clocks fall together with the regular ones and have no effect at all. Either way, this is the reason for the timing restrictions on HMOVE.

 

At the end of the scanline, the flag that prolongs hblank is cleared. If you strobe HMOVE before this, the extended blanking will not happen, and all extra clocks will cause a shift of one pixel to the left. This is the reason for the idiosyncrasies of late HMOVE. If you strobe HMOVE before the line ends **and** before the first extra clock is sent, you can achieve 15 pixels of movement to the left this way.

 

On a sidenote, this also explains most of the starfield effect: If you write HMxx while the extra pulses are sent, you can set it to a value below the extra pulse counter **before** the stop condition has been reached. This will cause the sprite to receive extra clocks until the next HMOVE and causes the starfield :)

Edited by DirtyHairy
  • Like 2
Link to comment
Share on other sites

The highest bit is internally inverted, so a value of 0 will cause 8 extra clocks, amounting to zero movement, 7 will cause 15 extra clocks, amounting to 7 pixels movement to the left.

Another way of saying this is that the TIA automatically converts 4-bit two's complement into excess-8.

  • Like 2
Link to comment
Share on other sites

I'm a little stuck again.

 

I implemented the STA HMCLR like people suggested, and that fixed the erratic horizontal movement problems.

 

However I now have an issue with the kernel, and the graphics pointers.

 

In order to save time in the kernel, I store Player0's graphics to the Y register at the bottom of the kernel.

 

HOWEVER, the GRP1 calculation routine is starting too early, and is causing the index of the GRP1 graphics to be loaded into the Y register, which is what is causing the black band of artefacts in each band of the screen where GRP0 doesn't appear.

 

Could someone explain to me how my pointers and Y offset variables are working? I can't seem to understand how to line up the (a) Y offset; and (b) graphics pointer.

 

I think I am also running out of time in my kernel...

Anyway, if anyone could have a look, I'd be very grateful : )

post-61331-0-96160500-1514276977_thumb.png

guerrilla020_bin_files.zip

coloured_guerrilla020.asm

Link to comment
Share on other sites

You have a branch that is skipping the code which loads the value for GRP0 into Y. This is why Y never contains the graphics data. The use of LDA (PTR),Y appears to be fine.

    lda #P0_HEIGHT      ; 2 47
    dcp Player0Offset   ; 5 52
    bcc .p0FlipDraw     ; 2 54 (3 54) <- Branch is taken, leaving Y with offset value
    ldy Player0Offset   ; 3 57

    lda (Player0Clr),y  ; 5 62
    sta COLUP0          ; 3 65 
    lda (Player0Ptr),y  ; 5 70
    tay                 ; 2 72

.p0FlipDraw             ;(3 54)
  • Like 1
Link to comment
Share on other sites

Just in response to ZackAttack - the graphics code for GRP0 needs to be skipped until the correct Y position for Player0 is reached. If I remove that branch, then Player0 will be drawn at the earliest possible opportunity. That branch is a part of the FlipDraw routine.

 

I think this kernel will not work in the long run. I think I have three options:

 

1. Use SpiceWare's masking technique

 

2. Use some version of VDELxx in a 2 Line Kernel in order to try and get single line resolution

 

Option 2 would be considerably more difficult than Option 1. There could be an option 3:

 

3. Use DoDraw for GRP1, and use FlipDraw for GRP0.

 

This is just an idea, it will almost certainly not work because it will take too long. It would require decrementing the scanline counter in memory and reloading it into Y every time.

 

Overall my current kernel is too slow to draw 2 multi-coloured sprites. 8bitworkshop.com seems to be able to achieve 2 multicoloured sprites AND a playfield, so I will study that code and see what I can learn. 8bitworkshop uses VDELP0, so I think this may be the way forward.

Link to comment
Share on other sites

I'm not saying you should get rid of the branch. I'm saying that the branch prevents the P0 graphics from being preloaded for the next line. So instead of 0 you get a garbage value. Maybe in pseudo code it could be easier to see.

 

if(drawP0) then

y = graphicForNextLine

end if

 

GRP0 = y <- y only is set if the if evaluates to true.

 

Instead what you want is this

 

 

if(drawP0) then

y = graphicForNextLine

else

y = 0

end if

GRP0 = y <- now y is 0 if it's not time to draw P0

Diff your previous posted asm file with this one to see the small change which makes all the difference. guerrilla-fix-y.asm

 

  • Like 1
Link to comment
Share on other sites

Plenty of time since you only execute one code path or the other.

 

Speaking of time. Since you're using bands there's no need for flipdraw or any other overhead on P1. Just pad the graphics and color data with a few bytes if you want to allow a small amount of vertical movement. Then offset the pointer to effect the vertical position within each band. Another nice thing about the bands is that you can use mask draw for P0 with a mask that's 3 * band height. So a 32 line band would only need 96 bytes for the mask. Then you can do P0 with only 5 cycles of overhead. Just as important, this gets rid of all the branches and makes it a lot easier to make the kernel exactly 76 cycles.

; Updates both sprites in 37 cycles
lda (ptrgrp0),y
and (ptrmask),y
sta GRP0
lda (prtcol0),y
sta COLUP0
lda (ptrgrp1),y
sta GRP1
lda (prtcol1),y
sta COLUP1

One more thing to consider is how P1 is being positioned between bands. If you want to draw anything between the bands you may need to have different kernel fragments that all do the same thing, but with a RESP1 strobe at different times. Then before hand you figure out which fragment to jump to based on where P1 is to be positioned. Then have a few lines to use HMOVE for fine positioning. If you have one line for HMOVE you'd need 160/15 = 11 fragments, but with 3 lines of HMOVE you'd only need 160/45 = 4 different fragments. You'd be left with at least 4 lines between each P1, but you gain the potential for some playfield or other enhancements.

  • Like 1
Link to comment
Share on other sites

I am about to develop a 2LK for the "Lock and Load" part of the game, the second part, which will feature:

  • 2 coloured sprites
  • 1 missile
  • a coloured asymmetrical playfield

A few questions about this.

 

  1. Will the playfield be drawn between bands?
  2. Is the missile going to be limited to just a few pixels per band?
  3. How tall did you plan on making the PF pixels?
  4. What's the largest/tallest PF pixel you'd accept?
  5. Will there be more than one PF image for this mode of the game?
  6. Can the PF be limited to the middle 32 PF pixels so that updating PF0 can be avoided?
  7. What are you trying to draw with the PF?
Link to comment
Share on other sites

I don't think it's true that I'm only executing one code path or the other - I am executing both code paths when GRP0 and GRP1 are both drawn in the same band.

 

I will get back to you about the lock and load section! My short answer is that I will only be drawing the middle 32 pixels - I'd like to have as high a resolution as possible.

 

I am hoping to have at most three different backgrounds. One for the beach, one for the jungle, and another for the mountains.

 

This part of the game will not have bands of soldiers. It will only have 2 multicolored sprites on the screen. I will also use 8x width effects to create different objects.

Link to comment
Share on other sites

The lock and load section of the game is kind of a small strategy game. You can move, block, load, or shoot. The idea is to chase down your opponent soldier and shoot them. If they block in the same turn as you shoot, they avoid any damage.

 

I will be drawing a beach background, a jungle background, and a mountain background.

Link to comment
Share on other sites

Ah okay. I agree. That is the problem.

 

Anyway, I'm back from my enforced relaxation now, and I am going to attempt a new rewrite of the kernel using the masking method, which is undeniably faster.

 

Again, thank you for all your help :)

Link to comment
Share on other sites

  • 3 weeks later...

Okay. This project is still alive.

I am about to implement a new kernel - the bitwise AND masking kernel that SpiceWare used in Stay Frosty - which ZackAttack recommends.

If you'd like to hear a radio interview I did about this project for a radio station in my home state of Western Australia, CLICK HERE.

Link to comment
Share on other sites

This is my newest attempt at a complete kernel rewrite.

 

It incorporates the masking technique and graphics padding that were suggested to me.

 

It is now SO fast that I have 23 cycles left over. (76 - 53 = 23)

 

I think I will incorporate playfield graphics! I wasn't even aiming to do so with this particular kernel!

;---------------------------------
;
; KERNEL MACRO
;
;---------------------------------

        MAC SCREEN_BANDS 
.BAND   SET {1}

;=================================
;
; Load Line Counter for this band
;
;=================================

    ldy Heights+.BAND

;=================================
;
; Preload GRP0 (Che) Graphics
;
;=================================

    lda (Player0Ptr+.BAND*2),y  ; 5  5
    and (Player0Msk+.BAND*2),y  ; 5 10
    tax                         ; 2 12
    lda (Player0Clr+.BAND*2),y  ; 5 17
    tay                         ; 2 19


;=================================
; Position GRP1 independently for
; each band of the screen.
;
; Accumulator holds X value.
;=================================

    lda ObjectX+.BAND+1

.PositionGRP1

    sec       
    sta WSYNC

;----------------------------------------------------- ENTER FIRST SCANLINE
    
    stx GRP0        ; 3  3
    sty COLUP0      ; 3  6
    
.DivideLoop1
    sbc #15         ; 2  8
    bcs .DivideLoop1 ; 2 10
    eor #7          ; 2 12
    asl             ; 2 14
    asl             ; 2 16
    asl             ; 2 18
    asl             ; 2 20
    sta RESP1       ; 2 23 <- set object position
    sta HMP1        ; 3 26
    sta WSYNC
;------------------------------------------------------ ENTER SECOND SCANLINE
    sta HMOVE           ; 3  3
    
;=================================
; We haven't had time to preload
; any graphics, so now we have to
; rush and try and make sure we have
; something to draw on this line
;=================================

;=================================
;
; Load Scanline Counter Again
; and Decrement
;
;=================================

    ldy Heights+.SEC              ; 3  6
    dey                           ; 2  8



    lda (Player0Ptr),y  ; 5 13
    and (Player0Msk),y  ; 5 18
    sta GRP0            ; 3 21
    lda (Player0Clr),y  ; 5 26
    sta COLUP0          ; 3 29      <-- delayed. So we'll have to restrict
                        ;               Che's movement on the left of the
                        ;               screen?

;=================================
;
; Decrement Scanline Counter
;
;=================================

    dey                 ; 2 31
                        
;=================================
; Preload Che Graphics for THIRD
; scanline.
;=================================

                        
    lda (Player0Ptr),y  ; 5 36
    and (Player0Msk),y  ; 5 41
    sta CheGfxTemp      ; 3 44
    lda (Player0Clr),y  ; 5 49
    sta COLUP0          ; 3 52
                        
;=================================
;
; Decrement Scanline Counter
;
;=================================

    dey                 ; 2 54

                        
; Prime the NUSIZ1 register with the right copies/sizing data

    lda EnvCopies+.BAND ; 3 57
    sta NUSIZ1          ; 3 60    
    

;=================================
;
; Start of the actual kernel
;
;=================================
    

.KernelLoop

    sta WSYNC           ; 3  75/3

;----------------------------------------------------- ENTER THIRD SCANLINE
	
;=================================
;
; Draw Che Graphics in time for left-most
; side of the screen.
;
;=================================

    lda CheGfxTemp      ; 3  3
    sta GRP0            ; 3  6
    lda EnvGfxTemp      ; 3  9
    sta GRP1            ; 3 12
    
;=================================
;
; Calculate Environment Graphics
;
;=================================

    lda (EnvGfxPtr+.BAND*2),y   ; 5 17
    sta EnvGfxTemp              ; 3 20
    lda (EnvClrPtr+.BAND*2),y   ; 5 25
    sta COLUP1                  ; 3 28

;=================================
;
; Calculate Che Graphics
;
;=================================

    lda (Player0Ptr+.BAND*2),y  ; 5 33
    and (Player0Msk+.BAND*2),y  ; 5 38
    sta CheGfxTemp              ; 3 41
    lda (Player0Clr*.BAND*2),y  ; 5 46
    sta COLUP0                  ; 3 49

;=================================
;
; Decrement line counter, and 
; branch out if we're at zero.
;
;=================================
    
    dey                ; 2 51
    bne .KernelLoop    ; 2 53 (3 17)

What I still have left to do is:

 

  • Set up the pointers for this kernel
  • Pad the graphics and adjust the pointers so that the graphics appear at the right scanlines
  • I think there's something else...

I have attached the source, if you'd like to have a look.

coloured_guerrilla021.asm

Link to comment
Share on other sites

OKAY.

 

I have finished coding the pointers for the GRP0 main player character, Che.

 

Almost all the code is lifted from Stay Frosty.

 

Now what I need to do in order to get a full demo working is re-code the pointers for the repeated GRP1 graphics.

 

Please find the attached source code.

coloured_guerrilla022.asm

Link to comment
Share on other sites

Okay I've finished my first attempt at the pointers for GRP1.

But I need some help - could someone assist in some debugging?

 

The masking for GRP0 works, and the graphics pointers for GRP0 work. The colour pointer for GRP0 is wayyyy off, though. It's pointing way too far down, right into the temporary GRP1 colour data table. When I compiled the code the first time, both the colour and graphics pointers for GRP0 worked, but after I fiddled with the GRP1 labels, the colour pointer stopped working. Confusing.

 

The second problem I have is that the graphics and colour pointers for GRP1 don't work at all. I am attempting to statically and manually fix all 5 bands of GRP1 to a single couple of tables... maybe the tables are crossing a page boundary?

 

The two black bands that comprise most of the glitchy GRP1 graphics is the value $2C. I think the location being loaded is $ED10 - Stella debug reports this as CXP1FB.

 

ANOTHER problem I'm having is that the vertical controls appear to be flipped. Pushing down moves Che upwards and vice versa.

 

BUT:

 

There are no more real artifacts as Che, GRP0 moves between bands. This is a huge improvement over the last kernel version.

Anyway, as always, help is always greatly appreciated.

 

Thanks in advance.

 

PS. One weird thing I'm noticing is that the Stella debugger formats my graphics data differently every time I compile a new version of the binary. Sometimes it recognises the graphics data as graphics, and sometimes it doesn't...

coloured_guerrilla023.asm

guerrilla23.zip

post-61331-0-83069600-1517097882_thumb.png

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