Jump to content
IGNORED

What's going on with my code?


jbs30000

Recommended Posts

I can see a couple of places in the code where you are doing "lda 0" which is actually reading TIA register CXM0P instead of loading the accumulator with the immediate value 0. You also need to make sure that the carry flag is set before you do "sbc Player0Y" too. The "adc #SPRITE_HEIGHT" immediately after that instruction will actually be adding SPRITE_HEIGHT+1 when Player0Y is less than your line counter in X.

Link to comment
Share on other sites

The shifting happens because you're updating GRP0 mid-scanline. If the player is to the left of your GRP0 update, the update happens on the scanline in question. If the player is to the right of your GRP0 update, it gets drawn on the next pass of the scanline. (making it appear lower) It's generally referred to as tearing or shearing, and it can happen to COLUP0/1, missiles, and ball updates too.

 

You'll want to update your players near the beginning of the scanline, when the beam is off-screen.

 

If you need to update both GRP0 and GRP1 and time at the beginning of the line is tight, its common to use the VDELP registers to delay the drawing of one of the players until the other is drawn.

Link to comment
Share on other sites

It makes kernel programming a fun part of the job - it winds up being like a jigsaw puzzle, as you try to fit functionality into the parts of the scanline they need to be in... stealing time from one part of the kernel to be more efficient elsewhere.

 

If your missiles only need to be one line tall, you should check out how Combat (or the bB multisprite kernel) handles them. Very compact code.

Link to comment
Share on other sites

Well, so far, (without looking at Combat or bB kernel*) I know how to put in code to display two sprites (single color) and both missiles, with no code left over to display the ball. I even figured that I have enough cycles left over to write to the VDELP1 register as suggested in post 6.

 

And still being a beginner at 2600 asm programming** reading disassembled programs or even Batari kernels isn't easy. I've decided that I'll have to make notes, and probably even charts, on all of the code before I can decipher what's going on.

 

* I tried looking at the bB standard kernel. It was hard to make out.

** I'm not new to asm, I've studied Intel asm. I'm just new to the 2600 registers and timing issues and so on.

Edited by jbs30000
Link to comment
Share on other sites

Well, so far, (without looking at Combat or bB kernel*) I know how to put in code to display two sprites (single color) and both missiles, with no code left over to display the ball. I even figured that I have enough cycles left over to write to the VDELP1 register as suggested in post 6.

 

And still being a beginner at 2600 asm programming** reading disassembled programs or even Batari kernels isn't easy. I've decided that I'll have to make notes, and probably even charts, on all of the code before I can decipher what's going on.

 

* I tried looking at the bB standard kernel. It was hard to make out.

** I'm not new to asm, I've studied Intel asm. I'm just new to the 2600 registers and timing issues and so on.

With regard to reading batari Basic kernels, one thing I'd suggest is saving a copy of the assembly listing to another file so you can edit it, as you'll probably want to cut out any lines that are commented out. The standard kernel uses a lot of compiler directives to decide whether to use one section of code or another section of code, depending on which kernel options are being used, and the sections of code that are *not* used will be commented out. If you remove those unused sections, the code that's left-- the code that's actually being used-- will be easier to follow. Note, I'm referring to an assembly listing for a game, not the raw assembly from the include file, because the include file by itself won't have any of the sections commented out. For example, make a very simple batari Basic pogram that doesn't use any options, such as the one below, then compile it and look at the assembly listing from it. The default compiler batch doesn't create an assembly listing, but you can modify the dasm command line so a complete assembly listing will be saved to a separate file.

 

  rem * a simple batari Basic program
loop
  drawscreen
  goto loop

Link to comment
Share on other sites

SeaGTGruff, I always have Dasm create a list file. Thank you for the advice of deleting commented out code. I definitely will do that.

 

There's a pretty good write-up of the combat missile trick in the ATARI 2600 ADVANCED PROGRAMMING GUIDE at minidig.

 

Also, you can just set VDELP1 before your kernel runs. No need to set it during the actual kernel itself. :)

For some reason I was thinking I'd have to write to it every scan-line. I thought that maybe it was like a strobe register.

 

And I'll check out that link. Thank you.

Link to comment
Share on other sites

OK, one last question. I try to find answers myself for any problems I run into, but for the last one, and this one, I'm not sure what to search for.

The code I have puts both players on the screen. So far so good. Player 0 is the movable face and player 1 is a stick figure.

Everything is fine until I move player 0 up or down on the same scanlines as player 1. This messes up both players.

BlankC.asm.binBlankC.asm

Link to comment
Share on other sites

It's your SBC and ADC instructions in the kernel. To get the correct results for SBC the carry needs to be set first (you can do so explicitly with SEC) and to get correct results with ADC you need to clear the carry first. (you can do so explicitly with CLC)

 

If the carry isn't set for SBC first, or if the carry is set for ADC first, the result is off by one. (assuming it's not the second half of a 16-bit operation, which it isn't here.)

 

Since you haven't set the carry state before each operation, the arithmetic that happens for one player changes the carry state for the next one, depending on it's Y position.

 

Setting the carry explicitly will add more cycles to your kernel. You should look into the skipdraw or switchdraw positioning routines, which are efficient and don't have this issue.

Link to comment
Share on other sites

Actually, what I'm doing should be the skipdraw routine. Actually, it's confusing because in the Andrew Davie tutorials it's listed as skipdraw, but searching these forums and Googling there's also some version which has variables like YPosFromBot, but the only examples I can find use Subpixel positioning, but I'm not interested in that. The pixel drawing routine is fixed at 18 cycles, which is cool, but I don't think it works with lda (sprite ptr),y. Or if it does I don't know how to change the code.

 

Adding sec to both draw routines does fix the problem, but of course adds cycles. In a post about skipdraw there's using an illegal opcode to save two cycles, but it doesn't show how to really use it.

; Thomas Jentzsch Skipdraw 
;========================================================================

;The best way, I knew until now, was (if y contains linecounter):
 tya                   ; 2
; sec                   ; 2 <- this can sometimes be avoided
 sbc SpriteEnd         ; 3
 adc #SPRITEHEIGHT     ; 2
 bcx .skipDraw         ; 2 = 9-11 cycles
; ...

; --------- or ------------

;If you like using illegal opcodes, you can use dcp (dec,cmp) here:
 lda #SPRITEHEIGHT     ; 2
 dcp SpriteEnd         ; 5     initial value has to be adjusted
 bcx .skipDraw         ; 2 = 9
; ...

;Advantages:
;- state of carry flag doesn't matter anymore (may save 2 cycles)
;- a remains constant, could be useful for a 2nd sprite
;- you could use the content of SpriteEnd instead of y for accessing sprite data
;- ???



;========================================================================
;An Example:
;
  ; skipDraw routine for right player
  TXA                          ; 2 A-> Current scannline
  SEC                          ; 2 Set Carry
  SBC slowP1YCoordFromBottom+1 ; 3 
  ADC #SPRITEHEIGHT+1          ; 2 calc if sprite is drawn
  BCC skipDrawRight            ; 2/3 To skip or not to skip?
  TAY                          ; 2
  lda P1Graphic,y              ; 4
continueRight:
  STA GRP0     

;----- this part outside of kernel

skipDrawRight        ; 3 from BCC
  LDA #0            ; 2
  BEQ continueRight ; 3 Return...

I'm pretty much already doing the example code, +1 cycle because I'm using indirect addressing with Y instead of absolute. But I've tried changing the routine to the shorter illegal opcode version, but have no clue how to make it work.

Link to comment
Share on other sites

OK, let's take this:

  TXA                          ; 2 A-> Current scannline
  SEC                          ; 2 Set Carry
  SBC slowP1YCoordFromBottom+1 ; 3 
  ADC #SPRITEHEIGHT+1          ; 2 calc if sprite is drawn
  BCC skipDrawRight            ; 2/3 To skip or not to skip?
  TAY                          ; 2
  lda P1Graphic,y              ; 4
continueRight:
  STA GRP0     

;----- this part outside of kernel

skipDrawRight        ; 3 from BCC
  LDA #0            ; 2
  BEQ continueRight ; 3 Return...

What do I replace with the

 lda #SPRITEHEIGHT     ; 2
 dcp SpriteEnd         ; 5     initial value has to be adjusted
 bcx .skipDraw         ; 2 = 9

It may be obvious, but I'm totally missing it.

Link to comment
Share on other sites

In 19 cycles vs the 20, but + a temp memory location.

 

 ; ------- this part before the kernel
 lda #0
 sta temp1 ; a scratch memory location
 lda player1y
 sta SpriteEnd ; SpriteEnd gets obliterated each time the kernel runs

;

 lda #SPRITEHEIGHT	 ; 2
 dcp SpriteEnd		 ; 5	 initial value has to be adjusted
 bcc .skipDraw		 ; 2 = 9
 ldy SpriteEnd 	 ; 3
 lda P1Graphic,y	 ; 4
continueRight:
  STA GRP0		 ; 3

;----- this part outside of kernel

skipDrawRight		 ; 3 from BCC
  LDA temp1 		 ; 3 - zero-page instead of direct addressing to burn a cycle
  BEQ continueRight	 ; 3 Return...

 

I usually use indirect addressing for the player data (+1 cycle) so I just "nop" during the skipDraw to balance out the +2 cycles in the non-skipDraw branch. (instead of using the zero-page access to balance out the +1 cycle that I used here)

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