Count over 255.

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

Post Reply
User avatar
kikutano
Posts: 102
Joined: Sat May 26, 2018 6:14 am
Location: Italy

Count over 255.

Post by kikutano » Mon Jul 16, 2018 1:00 am

Hello again,
thanks for all of your suggests, I'm learning a lot of things in this forum, but the ASM for Nes always give me new challenges. I will try to explain my problem. In my Arkanoid clone I copied all the tiles on RAM to check the collision detection, everything works great, the collision works, the VRAM is updated correctly so I can see the change on the background... Until the tile 255! :D I know that NES can store only 8 bit value and the best way to work is using 16 addressing, I have no problem to use low and high byte to use the 16 addressing and access to all address on VRAM or on RAM. BUT. I can't really understand how to compute a tile greater than 255. I do something like this:

Code: Select all

  LDA #$00
  STA BALL_POS_X_ON_TILE
  STA BALL_POS_Y_ON_TILE

  LDA BALL_POS_X
  LSR A
  LSR A
  LSR A                    ; Divide by 8
  STA BALL_POS_X_ON_TILE

  LDA BALL_POS_Y          

  LSR A
  LSR A
  LSR A                   ; Divide by 8
  STA BALL_POS_Y_ON_TILE

...

  LDX #$00
ComputeXYOnTile:
  LDA BALL_POS_X_ON_TILE
  CLC
  ADC #$20
  STA BALL_POS_X_ON_TILE
  INX 
  CPX BALL_POS_Y_ON_TILE
  BNE ComputeXYOnTile

....

PerformBallColWithBrickLeft:
  LDX BALL_POS_X_ON_TILE
  LDA $0400, x ( $400 is where the ram map begin )
  CMP #$2D
  BEQ PerformBallCollisionWithBrick

...
I know BALL_POS_X_ON_TILE is always between 0-255 because it's a value stored on a single location, but I can't understand how to store or use a tile that is greater than 255, with addressing it's not a problem, but in this case? How can I do that? Could you please give me an example to learn?

Thanks a lot, this is the last big "problem" to solve to finish my first demo! :P

User avatar
pubby
Posts: 549
Joined: Thu Mar 31, 2016 11:15 am

Re: Count over 255.

Post by pubby » Mon Jul 16, 2018 1:19 am

I don't fully understand what you're asking, but computing a nametable address would look something like this:

Code: Select all

lda #0
sta ADDR+1

lda BALL_POS_Y
and #%11111000
asl 
rol ADDR+1
asl
rol ADDR+1
sta ADDR+0

lda BALL_POS_X
lsr
lsr
lsr
clc
adc ADDR+0
sta ADDR+0
lda #$20 ; high byte of address 
adc ADDR+1
sta ADDR+1
(haven't tested but it should work)

If you wanted to test ram, just use indirect addressing with a Y of 0 after computing the address:

Code: Select all

ldy #0
lda (ADDR), y
So accessing RAM and VRAM is really done the same way.

User avatar
koitsu
Posts: 4216
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Count over 255.

Post by koitsu » Mon Jul 16, 2018 1:57 am

There are only 256 tiles available on the NES (values $00 to $FF) at any one time. That's all the pattern table provides space for, and all you can natively address in a single nametable. Period. If you think I'm kidding, I'm not (read: "The pattern table is divided into two 256-tile sections ...").

If you need more than that, then you need to look into using either:

a) a mapper with CHR-RAM (and thus write your own graphics to the pattern table (CHR) yourself using 6502 code), or,
b) a mapper with CHR-ROM (which lets you swap out all of, or portions of, the pattern table (CHR) immediately using 6502 code).

A good example of (a) is mapper 1 or UNROM. The wiki has a demonstration of how to do this.

A good example of (b) is mapper 3 or CNROM which lets you swap in/out the entire 8KByte CHR, or you can use something more complex like MMC1 (mapper 1) (swap 4KByte portions of CHR) or MMC3 (mapper 4) (swap 2KByte or 1KByte portions of CHR).

If you need help implementing these, or don't understand the difference between the two, read this.

If I've misunderstood what your problem is, then sorry, all of the above is wasted effort on my part.

User avatar
dougeff
Posts: 2633
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: Count over 255.

Post by dougeff » Mon Jul 16, 2018 4:53 am

It sounds like he has an array for collisions in the RAM that is larger than 256.

If that were the case, I would use (indirect), y and adjust the high byte of the indirect address if it rolls past 255.

The collision array I used for Jammin Honey is a bit bigger than 256. So, it's not uncommon.

However, you seem to be using a fairly slow method to calculate the address of the collision byte.

...if its a 16x8 sized breakable tile like Arkanoid. Then it would be 16 elements wide and (??) 18 elements high. Your array should fit in a 288 byte array. So this should work...

LDA #4 ;address 400
STA pointerHigh
LDA x position
LSR a
LSR a
LSR a
LSR a ;divide by 16
Sta pointerLow
LDA y position
;divide 8, then multiply 16 = multiply 2
ASL a ;times 2
BCC +
INC pointerHigh
+
AND #$f0
CLC
ADC pointerLow
STA pointerLow
LDY #0
LDA (pointerLow), y

;where pointerLow and pointerHigh are 2 consecutive zeropage addresses.

Edit.
AND #$f0
CLC
ADC pointerLow

Could have been

AND #$f0
ORA pointerLow
nesdoug.com -- blog/tutorial on programming for the NES

User avatar
kikutano
Posts: 102
Joined: Sat May 26, 2018 6:14 am
Location: Italy

Re: Count over 255.

Post by kikutano » Mon Jul 16, 2018 5:20 am

Yes, I've 960 tiles on RAM ( 32 * 30 ) and when I translate the x, y point on tile it will be greater than 255. I will read your answers and I will respond as soon as I can! Thanks! :)

User avatar
kikutano
Posts: 102
Joined: Sat May 26, 2018 6:14 am
Location: Italy

Re: Count over 255.

Post by kikutano » Tue Jul 17, 2018 12:21 am

dougeff wrote:
BCC +
INC pointerHigh
+
What's mean that "+" simbol? I can't compile it, it's just a label? Something like:

Code: Select all

  BCC label
  INC pointerHigh
label:
  ...
thanks! :)

User avatar
tokumaru
Posts: 11520
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Count over 255.

Post by tokumaru » Tue Jul 17, 2018 12:26 am

Yeah, it's an anonymous label, ASM6 style, and yes, you can rewrite it like you did.

User avatar
Banshaku
Posts: 2329
Joined: Tue Jun 24, 2008 8:38 pm
Location: Fukuoka, Japan
Contact:

Re: Count over 255.

Post by Banshaku » Tue Jul 17, 2018 12:27 am

Yes, those are unnamed labels. '+' one's are for jumping forward and '-' ones backward. Not all compiler support that paradigm. I know that ca65 uses them but don't know about other ones.

You can use any name in that case to make it work in your compiler.

edit:

Tokumaru pressed the send button faster than me :lol:

User avatar
koitsu
Posts: 4216
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Count over 255.

Post by koitsu » Tue Jul 17, 2018 12:29 am

It's a label that means "the next occurrence of label +", and only works forwards (i.e. "the label is somewhere past/later on/in front of the current line"). The opposite/reverse is -. However, these are re-usable labels, and can be nested (ex. +, ++, +++, etc.). This is an assembler-specific syntax, so it may not be available in the assembler you're using. You can use normal labels and accomplish the same thing.

User avatar
kikutano
Posts: 102
Joined: Sat May 26, 2018 6:14 am
Location: Italy

Re: Count over 255.

Post by kikutano » Tue Jul 17, 2018 9:42 am

dougeff wrote: ASL a ;times 2
BCC label
INC pointerHigh

label:
AND #$f0
ORA pointerLow
I really don't understand how the BCC is working in this code. I know that BCC is used to branch and compare like this:

Code: Select all

CMP  $20     ;Accumulator less than location $20?
        BCC  THERE
HERE                 ;No, continue execution here.
        .
        .
        .
THERE                ;Execute this if Accumulator is less than location $20.
        .
        .
        .
But in this case what BCC is comparing? The value in the accumulator? Could you please explain me? Why the #04 is stored on High Byte and not on Low Byte considering the fact that the collision map start at address $0400 on RAM?

Sorry for my dumps questions but I'm still learning ASM :oops: and everything is new for me. Thanks!

User avatar
rainwarrior
Posts: 7718
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Count over 255.

Post by rainwarrior » Tue Jul 17, 2018 10:00 am

There is a thing called "flags" which contain the last result of an operation.

CMP in particular updates the C (carry) flag, which is what BCC uses. (Branch if C is Clear)

Many instructions affect the flags, but they only change what is related to the operation. An instruction like LDA won't affect carry, but does update the Z (zero) flag, for instance, so a LDA can set the flags for a BEQ/BNE (branch if equal, branch if not equal) on whether the loaded value was zero.

Instruction reference will tell you which flags each instruction affects:
http://www.obelisk.me.uk/6502/reference.html

Info about registers and flags. Z (zero) and C (carry) are the most important ones.
http://www.obelisk.me.uk/6502/registers.html

User avatar
koitsu
Posts: 4216
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Count over 255.

Post by koitsu » Tue Jul 17, 2018 10:06 am

kikutano wrote: I really don't understand how the BCC is working in this code. I know that BCC is used to branch and compare like this:

Code: Select all

CMP  $20     ;Accumulator less than location $20?
        BCC  THERE
HERE                 ;No, continue execution here.
        .
THERE                ;Execute this if Accumulator is less than location $20.
        .
You may want cmp #$20, not cmp $20. Your comment says "than location $20", so I can't tell if you mean "the value in/at memory location $20", or "literal value $20".

cmp $20 would be comparing the accumulator against the value in memory location $20, while cmp #$20 would be comparing the accumulator against literal value $20.

As for branches: there are two commonly-used "aliases" for branch opcodes that might help you, depending on context:

BCC is sometimes written as BLT (branch if less than)
BCS is sometimes written as BGE (branch if greater than or equal to)

User avatar
dougeff
Posts: 2633
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: Count over 255.

Post by dougeff » Tue Jul 17, 2018 10:44 am

I'm not comparing. I'm indexing an array > 256.

ASL a ;times 2
BCC +
INC pointerHigh
+

the "ASL a" shifts all the bits left, and puts the high order bit in the Carry Flag.

If that bit was a zero, the Carry Flag will be zero (clear), and it will skip the next line.

If that bit was 1, the Carry Flag will be 1 (set), so it will increase the high byte of the array address (pointerHigh).

.

Your array is 960 bytes large, so this code won't work. Instead, you will need to shift the y value right until it is 0-3, then add that to #4 to get the high byte of the address.
nesdoug.com -- blog/tutorial on programming for the NES

User avatar
kikutano
Posts: 102
Joined: Sat May 26, 2018 6:14 am
Location: Italy

Re: Count over 255.

Post by kikutano » Wed Jul 18, 2018 12:26 am

Ok thanks! I will take my time to study and try your suggests :).

Post Reply