Jump to content
IGNORED

New to 6507 programming. Running through book by Oscar Toledo, but can't understand this code example


Recommended Posts

Wow, first post here in almost 20 years.

 

Anyway,

 

I'm reading through Programming Atari 2600 Games by Oscar Toledo.  So far I'm enjoying it, but I've hit a wall in trying to understand one of the examples, and I don't want to progress until I understand it.

 

https://github.com/nanochess/book-Atari/blob/master/demo2_4.asm

 

This program creates two space invaders at the middle of the screen and has them each shoot a missile downwards.

 

The snippet in question is this one:

	LDY VPOS	; Load VPOS into Y register.
VISIBLE2:
	STA WSYNC
	LDA #0		; A = $00 Disable missiles
	CPY #0		; Y is zero?
	BNE L2		; Branch if Not Equal.
	LDA #2		; A = $02 Enable missiles
L2:	STA ENAM0	; Enable or disable missile 0
	STA ENAM1	; Enable or disable missile 1
	DEY		; Decrease Y (temporary copy of VPOS)
	DEX
	BNE VISIBLE2

 

VPOS is the vertical position of the missile.  This is the explanation for what is happening:

Quote

The code for the second part of the visual screen is modified to load the current value of the VPOS variable into the Y register, and this is the current vertical position of the bullet. It starts the video line with STA WSYNC and then does the following magic: Compare Y with zero, if it is zero then it enables both missiles, if it isn’t zero then it disables both missiles.

Why does a comparison with zero? Because of the trick of executing the instruction DEY inside this same loop. Let us explain it:

• If Y is zero (bullet at zero position, detected with CPY #0), the code will act immediately to enable missiles.

• Then Y is decremented by one, so if it was $00, it will become $ff (because of the turn around of the 8-bit value), and this nonzero value will make the code disable the missiles.

• Now, if at start Y wasn’t zero, the missiles won’t be shown, but Y will be continuously decremented in each row, and when it reaches zero, the missile will be shown at the right screen row.

As I understand, this is what is happening with the code. 

  1. Load the vertical position into Y register.
  2. Start of Visible2 routine
  3. Move to next line
  4. Load 0 into accumulator A
  5. Compare Y (VPOS) to 0
  6. If they are equal to each other (VPOS=0), load 2 into A
  • Start of L2 routine
  • Load value of A (2) into both ENAM0 and ENAM1 which will enable both missiles.
  • Decrement Y by 1
  • Decrement X by 1 (as it draws the remaining scan line)
  • Return to the start of Visible2

     7. If they are not equal to eachother (VPOS <> 0), immediately jump to L2

  • Load value of A (0) into both ENAM0 and ENAM1 which will disable both missiles.
  • Decrement Y by 1
  • Decrement X by 1 (as it draws the remaining scan line)
  • Return to the start of Visible2

 

Later on, it goes to increment VPOS by 1.

 

First of all, what is the "zero position"?  Is 0 measured as the bottom of the screen, top of the screen, from the origin point (sprite)?  And how is it measured?  Going downwards becomes more negative or more positive?  Then it says Y is decremented by one, which would make it $FF instead of $00.  But that sounds like it's saying that the sprites are launched at VPOS 0, then get decremented down to $FF, then disappear?  I'm confused as to what sequence of events is taking here.  This is my first foray into assembly, so I'm having trouble wrapping my head around keeping track of drawing the screen and keeping track of projectiles, etc.

 

Link to comment
Share on other sites

Hey there!

 

The hardware draws the screen scanline by scanline, from top to bottom. According my understanding of your code snippet, VPOS contains the scanline number where the missiles should be shown for this frame. Say VPOS is 10 in this frame, then Y starts at 10 and slowly decreases. A is set to 2 (00000010) only if Y is 0, meaning that the missile sprites are enabled only when Y reaches 0. Before and after that, A is set to 0, disabling the missiles.

What scanline is that one? It depends on the rest of the program. If the code snippet immediately follows the vertical blank, then it will be the 10th (following my example) visible scanline. Instead, if after the vertical blank follows the drawing of the invaders for, say 16 scanlines and only then the snippet starts, then the missiles would be shown in the 26th visible scanline. 

I don't know the rest of the program but I presume that at the beginning of the frame VPOS is increased by 1 or so, so the missiles are progressively shown in later scanlines, that is, closer to the bottom of the screen. And as the missiles don't move horizontally, it is sufficient to set their position once, at the moment they are fired.

I hope this helps!

Edited by hzaccheo
Typo
Link to comment
Share on other sites

Nope, still completely lost. 😆

 

And I'm sure your answer is sufficient I just can't wrap my head around it.  I can track what it's doing with the code.  I just can't understand why it's trying to do it.

 

EDIT: Rather, I think I kind of get it.  Is it that you're trying to sync up ENAM0 on or off only to the scanlines where it is supposed to be drawn?  I still don't get the significant of comparing to 0, though. What is 0 position in this context, and how is it measured?

Edited by WarFreak131
Link to comment
Share on other sites

I suggest running the code in Stella and using the Integrated Debugger to single step through the code. Watching the values change while the screen is drawn will greatly help your understanding of how the code works.

 

This topic should help you get started with the debugger:

 

 

 

 

@tschak909 also made a couple videos about Stella's debugger that can help you get started, though the 2nd appears to be private now 🤔 .  Start with this reply on July 23, 2016 and read through the following comments, especially this reply where I add some additional info.

  • Like 1
Link to comment
Share on other sites

12 hours ago, WarFreak131 said:

s it that you're trying to sync up ENAM0 on or off only to the scanlines where it is supposed to be drawn?

 

Yes! I suggest the following experiment: comment the line

BNE L2 ; Branch if Not Equal.

which basically menas that it will always set A = 2, hence enabling ENAM0 and ENAM1 in every scanline. Run the code now, it should generate a vertical line (or two if there are two missiles).
 

12 hours ago, WarFreak131 said:

I still don't get the significant of comparing to 0, though. What is 0 position in this context, and how is it measured?

Please correct me if I am wrong but it seems you are thinking in (x,y) coordinates, right? But that's not really how it works: in general, a game program must generate 192 scanlines, from top to bottom, and for each scanline it must decide what to draw, what "pixels" to color in that scanline. The value in VPOS is not an absolute coordinate, like "0 means the top of the screen" but just a counter used as a number of scanlines: "enable the missiles only VPOS scanlines from the moment this snippets starts executing".

I hope this helps, and take a look at @SpiceWare's post above for details! 

Link to comment
Share on other sites

I use the online DASM compiler which re-compiles and executes in real time; a huge time saver.  The projectile first appears when Y=$A4=164.  You can only have the missiles appear at Y=164 if you start counting from where the bottom border starts.  You can step through and count the number of steps it takes for them to reappear.

 

But then that raises a question, if the missiles are going off the board, it'll do CPY #0, skip BNE L2, do LDA #2, then enable both ENAM0 and ENAM1.  Why would you enable the missiles if they're going off the screen?  The fact that Y is iterating upwards as the missile progresses flies in the face of L2 which says to decrement Y.

 

Screenshot 2023-11-02 202920.png

Screenshot 2023-11-02 205107.png

 

It appears I'm getting different results when I use the stella debugger.  When the code reaches VISIBLE2, the value of Y is 0. Then it does CPY #0.  According to this web page, https://www.nesdev.org/obelisk-6502-guide/reference.html#CPY

the Z flag should be set, since both values are 0.  But it doesn't, and the C flag is set.

Edited by WarFreak131
Link to comment
Share on other sites

After playing around with the debugger for a while, I think I actually understand it!

 

VPOS is used as a proxy for how many lines need to be drawn before the missile appears.

 

	LDY VPOS	; Load VPOS into Y register.
VISIBLE2:
	STA WSYNC
	LDA #0		; A = $00 Disable missiles
	CPY #0		; Y is zero?
	BNE L2		; Branch if Not Equal.
	LDA #2		; A = $02 Enable missiles
L2:	STA ENAM0	; Enable or disable missile 0
	STA ENAM1	; Enable or disable missile 1
	DEY		; Decrease Y (temporary copy of VPOS)
	DEX
	BNE VISIBLE2

 

In the first iteration of the program, VPOS = 0, meaning Y = 0 on the first pass as well.  Then CPY #0, which is true, so the Z flag should be set.  Skip BNE L2, and perform LDA #2, which will enable the missiles when STA ENAM0/1.  Decrement X (remaining scanlines), and Y (now equal to 255).  Jump back to VISIBLE2 and perform STA WSYNC, which draws the line.  Since the missiles are enabled, they are drawn.

 

On the second loop of VISIBLE2, CPY #0 is false, so it jumps immediately to L2 which disables the missiles because of LDA #0 and STA ENAM0/1.  Then at this point it basically runs down the remaining number of scanlines.  Since Y never equals 0 again by the time the scanlines run out, the missiles are not drawn for the remainder of the screen.

 

Once X becomes 0 via DEX, it exits loop L2.

 

Later in the code, it increments VPOS (now VPOS = 1).  Then it performs LDY VPOS (now Y = 1).  Now it's saying to skip 1 scanline before drawing the missile.

 

On the first pass through VISIBLE2CPY #0 will evaluate to false since Y = 1.  It will immediately jump to L2, which will disable missiles, decrement X and Y, and jump back to VISIBLE2.  It draws an empty line since ENAM0/1 are both 0.  Then on the next CPY #0, since we decremented Y from 1 to 0 before, now the comparison is true, so it skips BNE L2, performs LDA #2, which enables ENAM0/1.  Decrements X and Y and jumps back to VISIBLE2.  When it does STA WSYNC, the missiles are enabled, so it draws them.  In the next loop, Y will decrement to 255, and the whole process repeats.

Edited by WarFreak131
  • Like 2
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...