It is currently Mon Oct 23, 2017 1:16 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Mon Jan 23, 2017 8:38 pm 
Offline
User avatar

Joined: Mon Jan 23, 2017 8:08 pm
Posts: 6
Location: Boston, MA
I scoured this (and many other) pages for the past two hours so I apologize if this is already answered somewhere, but I'm at my wit's end. I'm trying to load more than 256 bytes to a memory blob (for collision detection). I load the high and low bytes of the collision data blob (728 bytes) and want to store accumulator values in that data using indirect addressing. The problem, however, is that I can't stick my data into it. I've tried several things (some below), but feel like I'm missing a fundamental syntax here...

Code:
collision_map .rs 768 ; gets assigned $0005
collision_low  .rs 1 
collision_high .rs 1
...
LoadData:
  LDA #low(collision_map)
  STA collision_low             ; confirmed puts $05 in collision_low
  LDA #high(collision_map)
  STA collision_high            ; confirmed puts $00 in collision_high
  LDX $00
  LDY $00
  LDA #$24                     ; for simplicity sake, lets say i just want to load the value '24'
LoadDataLoop:
  ; These are things I've tried
  STA (collision_low), Y ; this will store A at the address of collision_low and not collision_map
  STA [collision_low], Y ; Doesn't build: Incorrect zero page address!
  STA collision_low, Y ; this will store A at the address of collision_low and not collision_map
  STA $0005, Y ; works, but whole point is to avoid hard coding the address and trying to use vars bc this won't work for over 256 bytes
  ; End things i've tried (I also tried a combination of putting '#', '$', '<', '>' in front of collision_low in a desperate attempt to get lucky
  INY
  CPY #$00
  BNE LoadDataLoop
  LDA collision_high
  CLC
  ADC #$01
  STA collision_high
  LDA #$24                      ; reset back to value I want
  INX
  CPX #$03
  BNE LoadDataLoop


Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 8:43 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5734
Location: Canada
1. NESASM has nonstandard syntax for indirect addressing. Use square brackets instead:
Code:
sta [collision_low], Y


2. collision_low is not on the zero page. There are only 256 bytes of ZP and you've already reserved 768 bytes on it before trying to add collision_low. (The two bytes of an indirect address pointer must be on the ZP.)


Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 8:45 pm 
Offline
User avatar

Joined: Mon Jan 23, 2017 8:08 pm
Posts: 6
Location: Boston, MA
As stated above, when I try that (and just retried with copy pasting your code), it doesn't build with error: Incorrect zero page address!


Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 8:45 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10067
Location: Rio de Janeiro - Brazil
As a quick fix, try swapping the position of the pointer and the array in memory:
Code:
collision_low  .rs 1 
collision_high .rs 1
collision_map .rs 768

The problem seems to be that the 768-byte array is bumping the pointer to a memory position that's not in page 0, and indirect indexed addressing only works if the pointer is in ZP.

You will have to do something about that 768-byte array though, because starting it in ZP will make it occupy the rest of ZP, the entirity of pages 1 (the stack!) and 2 (normally the OAM buffer), and a bit of page 3. You should probably start this array on page 3 at least, and have it occupy 3 consecutive pages (3, 4 and 5).


Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 8:49 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5734
Location: Canada
mitch3a wrote:
As stated above, when I try that (and just retried with copy pasting your code), it doesn't build with error: Incorrect zero page address!

Sorry, I think you caught my post before I edited it with the second point. (I thought I could get it in there quick, but you were quicker!)


Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 8:51 pm 
Offline
User avatar

Joined: Mon Jan 23, 2017 8:08 pm
Posts: 6
Location: Boston, MA
Switching the order fixed it. TY TY TY TY. Totally misunderstood that the zero page was for the pointer itself and not for what it was pointing to, which was why I was trying for absolute indexing.

Also thanks for the pro-tip on moving that giant blob. Will do. Thanks for the ridiculously quick responses and not immediately hating on me for using Nesasm :D


Last edited by mitch3a on Mon Jan 23, 2017 8:51 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 8:51 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
There's a lot of wrong things here. Where to begin?

Subject says "absolute addressing", when that isn't what you're wanting to use at all. What you're wanting to use is indirect addressing, so that you have a way to handle ranges of >256 bytes.

Per the official nesasm documentation: http://www.nespowerpak.com/nesasm/usage.txt indirect addressing in nesasm uses brackets [] not parenthesis ().

You've omitted the relevant .rsset. I'm going to assume it defaults to $0000, but I would rather not assume anything.

Now, this code:

Code:
collision_map .rs 768 ; gets assigned $0005
collision_low  .rs 1 
collision_high .rs 1
...
LoadData:
  LDA #low(collision_map)
  STA collision_low             ; confirmed puts $05 in collision_low
  LDA #high(collision_map)
  STA collision_high            ; confirmed puts $00 in collision_high

Let's assume for a moment collision_map really does start at $0005.

The above code will stick the low byte of the address of the collision_map variable, i.e. value $05, into variable collision_low. It'll then put the high byte of the address of the collision_map variable, i.e. $00, into variable collision_high.

Using indirect addressing, you can then begin accessing data stored in collision_map like so:

Code:
ldy #0
lda [collision_low], y

This would access the first byte of what's contained at collision_map.

Now, let's talk about this, because it'll shed light on the situation:

Code:
  STA [collision_low], Y ; Doesn't build: Incorrect zero page address!


And here we have our answer: this assembler error is valid. It means that collision_low is not within zero page. For indirect addressing to work, the variables (for the low and high byte) need to be stored in zero page ($00 to $FF).

What this means is that collision_low and collision_high are outside of zero page. And that's certainly the case, because, again:

Code:
collision_map .rs 768 ; gets assigned $0005
collision_low  .rs 1 
collision_high .rs 1


If collision_map is $0005, that means $0005+768 will be the address of collision_low, which is $0305. That isn't in zero page, is it? :-)

Please refer to your assembler manual, looking at directives .zp and .bss for further details.

Edit: quintuple sniped.


Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 8:59 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10067
Location: Rio de Janeiro - Brazil
mitch3a wrote:
Switching the order fixed it.

Don't keep it that way though. Big arrays don't belong in zero page, which should be reserved for pointers and commonly used variables as much as possible, but way more importantly than that, the array is so big that it completely overlaps page 1, where the stack lies. This means that when the stack is used, the array will get corrupted, and when the array is written to, the stack might get corrupted, possibly crashing the program.

Quote:
Also thanks for the pro-tip on moving that giant blob. Will do.

:wink:


Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 9:29 pm 
Offline
User avatar

Joined: Mon Jan 23, 2017 8:08 pm
Posts: 6
Location: Boston, MA
Definitely heard you all on the problems with putting the blob in the zero page and of course once I loaded my blob, I saw the program crash. Still getting a handle on this so I appreciate your patience. Anyway, finally have it all loading as desired without crashing so I figured I'd post what finally worked for me. I'm sure it's still far from perfect, but figured it might be helpful for the next guy. Thanks again everyone for the quick/informative responses!

Code:
  .rsset $0000          ; Set the internal counter of the RS directive to start of zero-page
collision_low  .rs 1 
collision_high .rs 1
  .rsset $0300          ; Set the internal counter of the RS directive to a free blob after the stack, etc
collision_map .rs 768
...
LoadData:
  LDA #low(collision_map)
  STA collision_low             ; confirmed puts $05 in collision_low
  LDA #high(collision_map)
  STA collision_high            ; confirmed puts $00 in collision_high
  LDX #$00
  LDY #$00
  LDA #$24                     ; for simplicity sake, lets say i just want to load the value '24'
LoadDataLoop:
  STA [collision_low], Y      ; store the value
  INY
  CPY #$00
  BNE LoadDataLoop
  LDA collision_high           ; reached max y, so add one to high ptr to move it up 256 bytes and start y back at 0
  CLC
  ADC #$01
  STA collision_high
  LDA #$24                      ; reset A back to value I want
  INX
  CPX #$03
  BNE LoadDataLoop


Last edited by mitch3a on Mon Jan 23, 2017 9:51 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 9:45 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
mitch3a wrote:
Definitely heard you all on the problems with putting the blob in the zero page and of course once I loaded my blob, I saw the program crash. Still getting a handle on this so I appreciate your patience. Anyway, finally have it all loading as desired without crashing so I figured I'd post what finally worked for me. I'm sure it's still far from perfect, but figured it might be helpful for the next guy. Thanks again everyone for the quick/informative responses!

Code:
  LDX $00
  LDY $00


These are loading contents into X and Y, respectively, from zero page location $00, which is going to be the first byte of collision_map. You meant to use immediate addressing, ex.:

Code:
ldx #0
ldy #0

...or alternately, if you prefer:

ldx #$00
ldy #$00


Edit: P.S. -- You don't need to cpy #$00 after iny. iny modifies the both the CPU flags N and Z, so you don't need the comparison for comparing against zero here. You can just do iny, bne ....


Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 9:53 pm 
Offline
User avatar

Joined: Mon Jan 23, 2017 8:08 pm
Posts: 6
Location: Boston, MA
werps. Good catch with the $00 vs #$00. fixed it in place. As for the compare. will fix that in my code, but I'll leave it above. Guessing for anyone at my level that this'll help for, the extra logic is worth making it easier to understand.


Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 10:02 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
mitch3a wrote:
werps. Good catch with the $00 vs #$00. fixed it in place. As for the compare. will fix that in my code, but I'll leave it above. Guessing for anyone at my level that this'll help for, the extra logic is worth making it easier to understand.

Purely an optimisation thing; has nothing to do with fixing a bug. If the explicit compare is helpful for you, keep it. :-)


Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 10:11 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
As for the rest of the code: it should "function", but it probably won't work right once Y wraps from $FF to $00. Hint: think about collision_low. You're increasing the high byte of the address, but collision_low will still contain whatever address it did prior to the wrap. Think about the implications if, say, collision_map is at $03B4 (or any non-zero low byte of the address).


Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 10:18 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10067
Location: Rio de Janeiro - Brazil
koitsu wrote:
You're increasing the high byte of the address, but collision_low will still contain whatever address it did prior to the wrap. Think about the implications if, say, collision_map is at $03B4 (or any non-zero low byte of the address).

Actually, this kind of data transfer loop works just fine and is very common in 6502 ASM (you'd normally just use INC on the high byte of the pointer though, not LDA + CLC + ADC + STA). Look:
Code:
$03B4 + $FF = $04B3
$04B4 + $00 = $04B4 (which is indeed one byte after the previous)

There' will be more penalty cycles for crossing pages though, when compared to page-aligned data transfers, but that's hardly a concern in most cases.


Top
 Profile  
 
PostPosted: Mon Jan 23, 2017 10:26 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5734
Location: Canada
Also, while there is no convenient way to increment A, there is a convenient instruction for incrementing a byte of RAM directly (INC).
Code:
  LDA collision_high
  CLC
  ADC #$01
  STA collision_high

  ; the following does the same job:

  INC collision_high

Aside from being faster and shorter, the INC instruction does not modify A, and does not modify the carry bit (like ADC does), though it does still modify the zero bit. (However, an increment that should "carry" would have a result of zero anyway, so that flag is sufficient if you need it.)

Edit: sorry, was redundant to tokumaru's post, though maybe a little more explicit.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 7 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group