Jump to content



0

Ball Movement


24 replies to this topic

#1 Primordial Ooze OFFLINE  

Primordial Ooze

    Dragonstomper

  • 504 posts
  • Quacker Blaster Lead Programmer
  • Location:United States of America

Posted Tue May 12, 2009 4:33 PM

Can someone tell me if this is good code for moving the ball?

; **************************** Ball Movement Left ********************************

lda ballvxsign	; load the balls x velocity sign

cmp #1			; is the sign 1 ( positive )

bcc SkipMoveBallLeft ; the balls x velocity is negitive so don't move it right

lda ballvx		; load the balls x velocity

clc				  ; clear carry status

sub ballx			; decrease the balls x position by the ball's x velocity

sta ballx			; and store it in ball's x velocity

SkipMoveBallLeft

; **************************** Ball Movement Right ********************************


lda ballvxsign	; load the balls x velocity sign

cmp #0			; is the sign 0 ( negitive )

bcc SkipMoveBallRight; the balls x velocity is negitive so don't move it right

lda ballvx		; load the balls x velocity

clc				  ; clear carry status

adc ballx			; increase the balls x position by the ball's x velocity

sta ballx			; and store it in ball's x velocity

SkipMoveBallRight

Thanks,

Cell Wall Rebound

Edited by Primordial Ooze, Tue May 12, 2009 4:34 PM.


#2 vdub_bobby OFFLINE  

vdub_bobby

    Quadrunner

  • 5,831 posts
  • Boom bam.
  • Location:Seattle, WA

Posted Tue May 12, 2009 4:44 PM

First, there is no "SUB" opcode. :lol:

I'll assume that's a typo. ;)

Also, you want to subtract (SBC) the velocity from the position, not the other way around. And you want to set the carry before a subtraction, not clear it. Otherwise, that code is ok, I guess, though it is pretty bloated. I'd do something like this:
   lda BallX
   clc
   adc BallXVelocity
   sta BallX
Where BallXVelocity is a signed (two's complement) byte that ranges from -128 to 127.

#3 Wickeycolumbus OFFLINE  

Wickeycolumbus

    River Patroller

  • 4,063 posts
  • Location:Michigan

Posted Tue May 12, 2009 4:45 PM

some optimizations can be done :) (and I am sure there are more!)

	ldx ballvx

	lda ballvxsign   ; load the balls x velocity sign
	cmp #1		   ; is the sign 1 ( positive ) 
	bcc SkipMoveBallLeft; the balls x velocity is negitive so don't move it right
	 	txa	  ; load the balls x velocity to A

	sec  ; carry should be set!

	sbc ballx		   ; decrease the balls x position by the ball's x velocity

	sta ballx		   ; and store it in ball's x velocity

SkipMoveBallLeft

; **************************** Ball Movement Right ********************************


		lda ballvxsign   ; load the balls x velocity sign
	bne SkipMoveBallRight

 ;  cmp #0		   ; is the sign 0 ( negitive )

 ;  bcc SkipMoveBallRight; the balls x velocity is negitive so don't move it right

		txa	   ; load the balls x velocity to A

	clc				 ; clear carry status

	adc ballx		   ; increase the balls x position by the ball's x velocity

	sta ballx		   ; and store it in ball's x velocity

SkipMoveBallRight

Not sure where you got SUB from, did you mean SBC?

#4 Primordial Ooze OFFLINE  

Primordial Ooze

    Dragonstomper

  • 504 posts
  • Quacker Blaster Lead Programmer
  • Location:United States of America

Posted Wed May 13, 2009 7:52 AM

Yes, it was a typo and i meant sbc, ballvxsign and ballvysign are regular variables in ram which should only be set to 2 possible values(0/1) depending if the velocity is negitive or positive. What optimisations can i do?

   ldx ballvx

   lda ballvxsign				  ; load the balls x velocity sign

   cmp #1						  ; is the sign 1 ( positive ) 

   bcc SkipMoveBallLeft	   ; the balls x velocity is negitive so don't move it right

   txa								; load the balls x velocity to A

   sec								; carry should be set!

   sbc ballx						; decrease the balls x position by the ball's x velocity

   bvs SkipAlignBallLeft	   ; is the ball's new x position less then 0,

   lda #0							; if it is then set it's x position to 0 instead

   sta ballx						 ; and store it

   lda #1							; set the balls x velocity to positive

   sta ballvxsign				  ; and store it

Skip AlignBallLeft

   sta ballx						 ; otherwise store the balls x position normally

SkipMoveBallLeft

; **************************** Ball Movement Right ********************************

   lda ballvxsign				  ; load the balls x velocity sign

   bne SkipMoveBallRight	 ; the balls x velocity is negitive so don't move it right

   txa								 ; load the balls x velocity to A

   clc								  ; clear carry status

   adc ballx						 ; increase the balls x position by the ball's x velocity

   cmp #192					   ; is the ball's new x position greater then 192?

   bcs SkipAlignBallRight	  ; if it isn't then set the ball x position normally 

   lda #192						 ; otherwise set it's x position to 192 instead

   sta ballx						 ; and store it

   lda #0							; set the balls x velocity to negitive

   sta ballvxsign				  ; and store it

SkipAlignBallRight

   sta ballx						  ; and store it in ball's x velocity

SkipMoveBallRight

Sincerely,

Cell Wall Rebound

Edited by Primordial Ooze, Wed May 13, 2009 8:37 AM.


#5 danwinslow OFFLINE  

danwinslow

    Stargunner

  • 1,748 posts

Posted Wed May 13, 2009 8:37 AM

What optimizations can be done?! Oh man, you've done it now! the Kung-Fu Assembler Monks of temple 6502 will come swarming in with their weapons of mass optimization. Expect a long series of increasingly cryptic messages, until at the end the actual code completely disappears! Nothing will be left except a wisp of incense smoke and a finely groomed rock garden.

#6 Primordial Ooze OFFLINE  

Primordial Ooze

    Dragonstomper

  • 504 posts
  • Quacker Blaster Lead Programmer
  • Location:United States of America

Posted Wed May 13, 2009 8:39 AM

Quote

What optimizations can be done?! Oh man, you've done it now! the Kung-Fu Assembler Monks of temple 6502 will come swarming in with their weapons of mass optimization. Expect a long series of increasingly cryptic messages, until at the end the actual code completely disappears! Nothing will be left except a wisp of incense smoke and a finely groomed rock garden.
Well with all the extra code i added, i figure that i'm gonna need it, or else my project can be considered dead with what i still have to add to make it playable.

#7 vdub_bobby OFFLINE  

vdub_bobby

    Quadrunner

  • 5,831 posts
  • Boom bam.
  • Location:Seattle, WA

Posted Wed May 13, 2009 9:57 AM

View PostPrimordial Ooze, on Wed May 13, 2009 7:39 AM, said:

Quote

What optimizations can be done?! Oh man, you've done it now! the Kung-Fu Assembler Monks of temple 6502 will come swarming in with their weapons of mass optimization. Expect a long series of increasingly cryptic messages, until at the end the actual code completely disappears! Nothing will be left except a wisp of incense smoke and a finely groomed rock garden.
Well with all the extra code i added, i figure that i'm gonna need it, or else my project can be considered dead with what i still have to add to make it playable.
See my post above. There is no reason to use an entire byte to store the sign of the velocity. Use a single byte to hold the velocity AND the sign.

Read about twos complement and signed integers.

If you want to make the velocity negative, do this:
   lda #-1
   sta ballvx
If you want to make the velocity positive, do this:
   lda #1
   sta ballvx
If you want to make the velocity zero, do this:
   lda #0
   sta ballvx
Then when you want to apply the velocity, do this:
   lda ballvx
   clc
   adc ballx
   sta ballx
This will work whether velocity is positive, negative, or zero! And it is easily extensible to larger velocities AND adding velocities (i.e., if you want to add acceleration) - the signs will take care of themselves!
Example of acceleration:
   lda ballvx
   clc
   adc ballax
   sta ballvx
This code will work. Doesn't matter what the sign of velocity or acceleration is. You just have to be careful (like whenever you are working with byte arithmetic) not to overflow - but of course, that's what the overflow flag is for.

The 6502 was designed to make signed arithmetic easy. There is no reason to store the sign of a number in a separate place from the number itself.

Edited by vdub_bobby, Wed May 13, 2009 10:02 AM.


#8 Primordial Ooze OFFLINE  

Primordial Ooze

    Dragonstomper

  • 504 posts
  • Quacker Blaster Lead Programmer
  • Location:United States of America

Posted Wed May 13, 2009 10:21 AM

   ldx ballvx

   txa							; load the balls x velocity to A

   sec							; carry should be set!

   sbc ballx					  ; decrease the balls x position by the ball's x velocity

   bvs SkipAlignBallLeft		  ; is the ball's new x position less then 0,

   lda #0						 ; if it is then set it's x position to 0 instead

   sta ballx					  ; and store it

   lda #1						 ; set the balls x velocity to positive

   sta ballvx					 ; and store it

Skip AlignBallLeft

   sta ballx					  ; otherwise store the balls x position normally

SkipMoveBallLeft

; **************************** Ball Movement Right ********************************

   txa							; load the balls x velocity to A

   clc							; clear carry status

   adc ballx					  ; increase the balls x position by the ball's x velocity

   cmp #192					   ; is the ball's new x position greater then 192?

   bcs SkipAlignBallRight		 ; if it isn't then set the ball x position normally 

   lda #192					   ; otherwise set it's x position to 192 instead

   sta ballx					  ; and store it

   lda #-1						; set the balls x velocity to negitive

   sta ballvx					 ; and store it

SkipAlignBallRight

   sta ballx					  ; and store it in ball's x velocity

SkipMoveBallRight

Is this better, please let me know.

Sincerely,

Cell Wall Rebound

Edited by Primordial Ooze, Wed May 13, 2009 10:35 AM.


#9 vdub_bobby OFFLINE  

vdub_bobby

    Quadrunner

  • 5,831 posts
  • Boom bam.
  • Location:Seattle, WA

Posted Wed May 13, 2009 11:07 AM

You're mixing a few things up here.

ballx is an unsigned integer, I assume - and I also assume that you want it to range between 0 and 159, not 0 and 192.

And you are still subtracting position from velocity when you should be subtracting velocity from position.

And, again, if you are using a signed integer for velocity - like you should be - there is no need for separate "left" and "right" routines.

If you want to test for boundaries, you're better off directly testing position, like:
   ldx ballvx
   lda ballx
   clc
   adc ballvx
   cmp #240
   bcc NotLessThanZero
   lda #0
   ldx #1
NotLessThanZero
   cmp #160
   bcc NotMoreThan159
   lda #159
   ldx #-1
NotMoreThan159
   sta ballx
   stx ballvx
That's untested, but I think it should work...

#10 Primordial Ooze OFFLINE  

Primordial Ooze

    Dragonstomper

  • 504 posts
  • Quacker Blaster Lead Programmer
  • Location:United States of America

Posted Wed May 13, 2009 12:33 PM

View Postvdub_bobby, on Wed May 13, 2009 1:07 PM, said:

You're mixing a few things up here.

ballx is an unsigned integer, I assume - and I also assume that you want it to range between 0 and 159, not 0 and 192.

And you are still subtracting position from velocity when you should be subtracting velocity from position.

And, again, if you are using a signed integer for velocity - like you should be - there is no need for separate "left" and "right" routines.

If you want to test for boundaries, you're better off directly testing position, like:
   ldx ballvx
   lda ballx
   clc
   adc ballvx
   cmp #240
   bcc NotLessThanZero
   lda #0
   ldx #1
NotLessThanZero
   cmp #160
   bcc NotMoreThan159
   lda #159
   ldx #-1
NotMoreThan159
   sta ballx
   stx ballvx
That's untested, but I think it should work...
Ok, ty how do i make ballvx a signed integer?
ballvx = $84	; ball's x velocity ( original definition)
Sincerely,

Cell Wall Rebound

#11 Primordial Ooze OFFLINE  

Primordial Ooze

    Dragonstomper

  • 504 posts
  • Quacker Blaster Lead Programmer
  • Location:United States of America

Posted Wed May 13, 2009 2:56 PM

Since i can no longer edit my post, i will provide an update here:

the line:
ldx #-1
gives the following error:

Quote

error: value in 'ldx #-1' must be <$100.

Sincerely,

Cell Wall Rebound

#12 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Wed May 13, 2009 3:23 PM

View PostPrimordial Ooze, on Wed May 13, 2009 3:56 PM, said:

Since i can no longer edit my post, i will provide an update here:

the line:
ldx #-1
gives the following error:

Quote

error: value in 'ldx #-1' must be <$100.

Sincerely,

Cell Wall Rebound
If you want to do a negative number, you subtract it from 256 first. That is, -1 is the same thing as 0 - 1 = 256 - 1 = 255, because 256 and 0 are "the same number" if you'er using 8 bits (i.e., "modulo 256" numbers). If that just went over your head, don't worry about it, just remember the following:

If you're using an 8-bit number, and you want to use it as a signed value (can be positive or negative), then the possible signed values are 0 to 127 for the positive values, and -1 to -128 for the negative numbers.

Positive values will have bit 7 set to 0.

Negative values will have bit 7 set to 1.

You can't load a negative value into a register, so you can't do "LDA #-1" or something like that. But if you subtract the number from 256, it will give you the correct 8-bit value to use for the negative number. I think you might even be able to do that within the assembly instruction, as follows:

	  LDA #256-1
I can't try it until I get home, but the DASM assembler should be smart enough to subtract 256-1 to get 255, then load #255 into the accumulator.

Michael

#13 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Wed May 13, 2009 3:30 PM

View PostPrimordial Ooze, on Wed May 13, 2009 3:56 PM, said:

ldx #-1
gives the following error:

Quote

error: value in 'ldx #-1' must be <$100.
By the way, I think the reason you get that message is because DASM interprets #-1 as #0-1, but it uses 32-bit values, so #0-1 gives you %11111111111111111111111111111111 (I think, or -1 in a 32-bit format) instead of %11111111 (-1 in an 8-bit format). So if you just stick "256" in front of the negative number, you should be okay, as long as you stick to the range 0 to 127 and -1 to -128.

Michael

#14 Primordial Ooze OFFLINE  

Primordial Ooze

    Dragonstomper

  • 504 posts
  • Quacker Blaster Lead Programmer
  • Location:United States of America

Posted Wed May 13, 2009 4:18 PM

hmmm.... this is very interesting but, perplexing. It seems i can move the ball in one direction or the other, and keep it within it boundaries, but if i try to move it in both directions the boundary code seems to go on vacation. Any ideas on why this is happening?

Sincerely,

Cell Wall Rebound

#15 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Wed May 13, 2009 6:35 PM

View PostPrimordial Ooze, on Wed May 13, 2009 6:18 PM, said:

It seems i can move the ball in one direction or the other, and keep it within it boundaries, but if i try to move it in both directions the boundary code seems to go on vacation.
Since the code you posted is moving the ball left and right, I presume that "both directions" refers to the horizontal and vertical directions? Is that correct; you're trying to get vertical movement incorporated without losing horizontal movement?

Michael

#16 Primordial Ooze OFFLINE  

Primordial Ooze

    Dragonstomper

  • 504 posts
  • Quacker Blaster Lead Programmer
  • Location:United States of America

Posted Wed May 13, 2009 6:45 PM

View PostSeaGtGruff, on Wed May 13, 2009 8:35 PM, said:

View PostPrimordial Ooze, on Wed May 13, 2009 6:18 PM, said:

It seems i can move the ball in one direction or the other, and keep it within it boundaries, but if i try to move it in both directions the boundary code seems to go on vacation.
Since the code you posted is moving the ball left and right, I presume that "both directions" refers to the horizontal and vertical directions? Is that correct; you're trying to get vertical movement incorporated without losing horizontal movement?

Michael
find the following line:
	sta ballx; set ball's initial x position

	lda #95

	sta bally; set ball's initial y position

	lda #1

	sta ballvx ; set ball's inital x velocity

   ;sta ballvy ; set ball's inital y velocity

	lda #0

and uncomment both lines:
	sta ballvx; set ball's inital x velocity

	sta ballvy; set ball's inital y velocity
and the ball will move in both directions, but the boundary checking will stop working.

Sincerely,

Cell Wall Rebound

Edited by Primordial Ooze, Wed May 13, 2009 6:52 PM.


#17 vdub_bobby OFFLINE  

vdub_bobby

    Quadrunner

  • 5,831 posts
  • Boom bam.
  • Location:Seattle, WA

Posted Wed May 13, 2009 7:45 PM

Just do lda #<-1

Or use an older version of DASM, like me. ;)

#18 Primordial Ooze OFFLINE  

Primordial Ooze

    Dragonstomper

  • 504 posts
  • Quacker Blaster Lead Programmer
  • Location:United States of America

Posted Wed May 13, 2009 7:58 PM

View Postvdub_bobby, on Wed May 13, 2009 9:45 PM, said:

Just do lda #<-1

Or use an older version of DASM, like me. ;)
We fixed that problem already. :roll: If you read my previous post, when i move the ball in both directions the boundary checking code stops working. :x

Sincerely,

Cell Wall Rebound

#19 nonner242 OFFLINE  

nonner242

    River Patroller

  • 3,407 posts
  • ALL your base ALL belong to us!!!!!!!!!!!!!!
  • Location:On a Ohio rooftop...Sniping

Posted Wed May 13, 2009 8:56 PM

So this has nuthing to do with nuts?
DAMN! :D

#20 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Wed May 13, 2009 9:45 PM

View PostPrimordial Ooze, on Wed May 13, 2009 9:58 PM, said:

when i move the ball in both directions the boundary checking code stops working. :x
I think you've got two problems:

(1) If ballx is the left edge of the ball, then you need to subtract a little bit from the right boundary's position to compensate for the width of the ball.

(2) As the ball is moving left or right, it occasionally jumps a bit too far, which indicates that your horizontal positioning routine has a slight glitch in it somewhere.

#2 is the main problem, because the ballx position doesn't jump to "keep step" with the ball's actual position-- i.e., ballx still goes up by 1, but the ball's position jumps a few extra color clocks. The difference accumulates as the ball gets closer to the right boundary, so by the time the ballx value finally gets to the right boundary value, the ball has already moved off the right edge of the screen and wrapped around to the left side.

If the problem goes away when you comment out a line, then I'm guessing it's a page-crossing issue in the positioning loop. And sure enough...

	399  f8fe				   PositionSpriteLoop
	400  f8fe
	401  f8fe			   e9 0f			  sbc	#15
	402  f900
	403  f900			   b0 fc			  bcs	PositionSpriteLoop
	404  f902
	405  f902			   49 07			  eor	#7
To fix #1, try setting BALLRIGHTBOUNDRY to $9b instead of $9d.

To fix #2, add this line just before the PositionSprite subroutine:

	  align 256
That will keep all of the code in the PositionSprite subroutine on the same page. You don't actually need to add that much space-- you could just use this instead:

	  .hex ff ff
since you only need to move the start of the loop by 2 bytes to put it at the beginning of the page-- but the "align 256" is probably safer.

Michael

#21 vdub_bobby OFFLINE  

vdub_bobby

    Quadrunner

  • 5,831 posts
  • Boom bam.
  • Location:Seattle, WA

Posted Thu May 14, 2009 12:51 AM

View PostPrimordial Ooze, on Wed May 13, 2009 5:58 PM, said:

We fixed that problem already. :roll:
No need to be an ass, especially since you're asking us to do your work for you.

#22 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Thu May 14, 2009 6:25 AM

View PostPrimordial Ooze, on Wed May 13, 2009 8:58 PM, said:

View Postvdub_bobby, on Wed May 13, 2009 9:45 PM, said:

Just do lda #<-1

Or use an older version of DASM, like me. ;)
We fixed that problem already.
There are almost always different ways to solve a problem, and it's nice to know what they all are so you can choose the one you like the best, or that works best for your particular situation. So you've got four solutions to the -1 issue:

(1) Figure out the equivalent unsigned value on your own and use it-- i.e., LDA #255.
(2) Use LDA #256-1.
(3) Use LDA #<-1.
(4) Use a compiler (or a different version of one) that will just give you the lo byte of -1 when you say LDA #-1.

And there are at least four solutions to the movement issue caused by the page-crossing:

(1) Use align 256.
(2) Use .hex 00 00 (or .byte, or .word, etc.) to insert two bytes so the loop doesn't cross a page boundary.
(3) Use ORG to reposition the start of PositionSprite.
(4) Rearrange your routines so PositionSprite is somewhere safe-- e.g., in front of Start (i.e., PositionSprite would be at $F800, followed by Start).

All of these solutions amount to the same thing-- moving the loop so it doesn't cross a page boundary-- but they aren't all equal. In this case, #1 will waste 7 bytes, #2 will waste only 2 bytes, #3 could waste any number of bytes (depending on the new ORG address), and #4 wouldn't waste any bytes at all.

Michael

#23 Primordial Ooze OFFLINE  

Primordial Ooze

    Dragonstomper

  • 504 posts
  • Quacker Blaster Lead Programmer
  • Location:United States of America

Posted Thu May 14, 2009 11:15 AM

What exactly do you mean by "crossing a page boundry", i don't understand what that means or how exactly i managed to "cross a page boundry"?

Sincerely,

Cell Wall Rebound

#24 danwinslow OFFLINE  

danwinslow

    Stargunner

  • 1,748 posts

Posted Thu May 14, 2009 11:57 AM

View PostPrimordial Ooze, on Thu May 14, 2009 11:15 AM, said:

What exactly do you mean by "crossing a page boundry", i don't understand what that means or how exactly i managed to "cross a page boundry"?

Sincerely,

Cell Wall Rebound

Memory for this processor is organized in 'pages' of 256 bytes. Page 0 is bytes 0-255, page 1 is 256-511, etc. Crossing a page boundary means that while indexing, you have passed over the boundary between two adjacent pages. This means that the lower part of your indexing, or loop control, or however you are keepign track of where you are will have wrapped around from 255 to 0, rather than increasing to 256 ( because of course, all you can store in 8 bits is 0-255). In terms of math, adding one to a byte that contains 255 will produce 0, not 256. This will cause various problems unless accounted for.

Lets say you want to move 16 bytes from one place to another. You set up an index reg, say x, as a counter for the bytes. Using the x register, you bop along moving a byte at a time, and incrementing x as you go. If your start of data is at byte nubmber 32 of some page, say, you could load x with a 32 and just inx after every byte load/store. So x would go from 32 to 48. But, lets say that your data starts at byte 252 of some page. You could load x with 252, and all would be well until you try to cross over to the next page. At that point, you would have incremented the 255 in x and gotten 0, not 256, which means that the rest of your load and stores are going to move data incorrectly from the beginning of the current page rather than the beginning of the next page.

Edited by danwinslow, Thu May 14, 2009 12:04 PM.


#25 SeaGtGruff OFFLINE  

SeaGtGruff

    River Patroller

  • 4,543 posts
  • Location:Georgia, USA

Posted Thu May 14, 2009 10:17 PM

View PostPrimordial Ooze, on Thu May 14, 2009 12:15 PM, said:

What exactly do you mean by "crossing a page boundry", i don't understand what that means or how exactly i managed to "cross a page boundry"?
As Dan said, a "page" is 256 bytes. The 2600 uses a 6507 processor, which is basically a 6502 but with fewer pins, and therefore some reduced capabilities-- namely, it can address only 8k of nemory instead of 64k, plus it doesn't have any interrupts (although you can use the BRK opcode to force an interrupt). Anyway, the 6502-- and hence also the 6507-- uses two bytes to identify each memory address, a "lo byte" and a "hi byte." The hi byte is the page number.

In your code, when you had remarked out the line of code that set the y velocity, the PositionSprite loop didn't cross a page boundary. But when you unremarked that line of code to put it back in the program, the PositionSprite loop got pushed up in memory by 2 bytes, because that's how many bytes were used by the line of code to store the y velocity.

When I looked at the assembly listing for your code (after putting that line back into the program), I saw this:

	399  f8fe				   PositionSpriteLoop
	400  f8fe
	401  f8fe			   e9 0f			  sbc	#15
	402  f900
	403  f900			   b0 fc			  bcs	PositionSpriteLoop
	404  f902
	405  f902			   49 07			  eor	#7
The first column is just the line numbers in the assembly listing, so they don't mean anything important. But the second column shows the address where each instruction ends up being placed by the assembler when your code is assembled. The PositionSpriteLoop label (which doesn't actually take up any space) is at address $f8fe, which is also where the first line of code in that loop is stored (the "sbc #15" instruction). The next line ("bcs PositionSpriteLoop") is stored at address $f900. And the line after that ("eor #7") is stored at addressed $f902. So that means the first line-- along with the loop's label-- is stored on page $f8 (the first two hex digits of the address, which is the hi byte), and the branch instruction is stored on page $f9, which is a different page.

When you do a branch, the branch can go forward 127 bytes in the code, or it can go backward 128 (i.e., -128) bytes in the code. A distance of 0 bytes would be the byte that immediately follows the branch instruction-- in this case, "eor #7" that starts as address $f902. You want to branch backward to "PositionSpriteLoop," which is a distance of -4 bytes. Now, the -4 is of no importance to this discussion, but I'm mentioning it to help explain the assembly listing. If you express -4 as an unsigned byte value, you get 252 (i.e., 256 - 4 = 252), and the hex version of 252 is $fc. So that's why the assembled machine code for the "bcs PositionSpriteLoop" is "b0 fc"-- the "b0" represents the "bcs" opcode, and the "fc" means "-4," or branch backwards 4 bytes if the carry flag is set.

Each machine language instruction takes a specific number of machine cycles to execute.

A branch instruction takes 2 cycles to execute if the branch is *not* taken-- i.e., if the program just falls through to the next instruction after the branch, because the condition for the branch was false. ("Was the carry flag set? No? Okay, then just fall through.")

But if the branch *is* taken, then the branch instruction takes 3 machine cycles to execute. On the other hand, "sbc #15" takes only 2 cycles to execute, because it's an immediate mode instruction. So as long as the program keeps looping back, the loop takes a total of 5 cycles-- 2 for the "sbc" and 3 more to branch back to the beginning of the loop. This is equal to 15 color clocks or "horizontal pixel positions" on the scan line, because the processor is running at a third of the speed of the color subcarrier frequency (or "color clock" rate)-- that is, during 1 machine cycle, the scanning beam(s) move forward 3 color clocks or "pixel positions" on the line. So the loop takes 5 cycles, which is 15 color clocks (5 times 3). That's why the loop does a "sbc #15"-- because each time the loop is repeated, the RGB scanning beams move 15 positions.

*But*, if the branch instruction crosses a page boundary-- that is, if the instruction that immediately follows the branch instruction is on one page, but the target of the branch is on a different page-- then the branch instructions takes 4 cycles instead of the usual 3 cycles. This is what happened when you added back in the line that stores the y velocity. As I stated a few paragraphs up, the instruction that immediately follows the branch is at address $f902, which is on page $f9. But the target of the branch-- the "PositionSpriteLoop" label-- is at address $f8fe, which is on page $f8. So the Atari has to go from page $f9 to page $f8 when the branch is taken-- i.e., it has to cross a page boundary-- so the branch takes 4 cycles instead of 3 cycles, which means the entire loop lasts for 6 cycles instead of 5 cycles. That's 18 color clocks instead of 15 color clocks, so the "sbc #15" gets out of whack from the x position counter as the ball is moving from left to right, or from right to left. That's why the ball seems to move smoothly, then jerk forward a bit further than it should, then move smoothly, then jerk forward a bit further than it should, over and over again as the ball moves horizontally. The difference between the x position counter and the ball's actual horizontal position gets larger as the ball moves further to the right, so that by the time the ball's x position counter reaches the value you've set for the right boundary, the ball has already moved off the right edge of the screen and wrapped around to the left side, such that the ball doesn't bounce back when it should.

If you move the loop so it no longer crosses a page boundary-- using any of the four solutions that I suggested-- the loop will go back to taking only 5 cycles to execute, and the ball will move smoothly again, and will also bounce back when you expect it to.

I know that's a lot to try to absorb if you're just learning this stuff, but page-crossings are something you need to learn to watch out for if your program starts to act flakey, because they can throw off the timing of your loops, and precise timing can be very critical on the 2600, especially when it comes to making changes in the middle of a scan line, such as resetting the horizontal position of a sprite.

Michael




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users