nesdev.com
http://forums.nesdev.com/

Basic nametable reading question (.incbin addressing)
http://forums.nesdev.com/viewtopic.php?f=21&t=16287
Page 1 of 1

Author:  nesrocks [ Tue Aug 01, 2017 4:55 pm ]
Post subject:  Basic nametable reading question (.incbin addressing)

Sorry for the newbie question, I've been searching for practical examples on this but so far not much luck...

So, when developing a nes game with the cc65 compiler and using Nes Screen Tool, if I include a full screen nametable (the whole screen tiles) binary like so:

Code:
nametable:
.incbin "level_01_bg.nam"


Is it possible to read all of its bytes to send data to the PPU if the included file is longer than $FF bytes? I can only access its first 256 bytes by using "LDA nametable,x", but the rest I have no idea how to access.

I got it to work (the full nametable loaded and displayed) by copy/paste the nametable as asm code from Nes Screen Tool and then setting labels dividing it in 4 areas, but workflow would be streamlined if I could export a file from Nes Screen Tool and compile the game as is, especially because of the nametable splitting and having to rename ".db" to ".byte" (is there a way to make NSS more cc65 compatible?).

minor edit: more descriptive title

Author:  tepples [ Tue Aug 01, 2017 5:09 pm ]
Post subject:  Re: Basic nametable reading question

Do you know what a pointer is?

You'll need to make a pointer in two bytes of zero page and use the (dd),Y addressing mode to step through all four 256-byte pages of nametable data.

EDIT: spelling

Author:  mikejmoffitt [ Tue Aug 01, 2017 5:15 pm ]
Post subject:  Re: Basic nametable reading question

You can use the Indirect Indexed mode, with Y, to load from a large table.
Assuming a ZP two-byte variable "addr_ptr":

Code:

; Put nametable source address in addr_ptr
lda #<nametable
sta addr_ptr
lda #>nametable
sta addr_ptr+1

; Copy one page of data ($100 bytes)
@copypage:
ldy #0
@copyloop:
lda (addr_ptr), y
sta PPUDATA
iny
bne @copyloop

; Move on to the next page, or leave if finished
lda nametable+1
clc
adc #1
sta nametable+1
cmp #(>nametable + 4)
bne @copypage


This code is really rough, so please forgive minor errors. The jist of it is a copy loop using Y from $00-$FF, and then incrementing the high byte of your pointer after that and doing it again until you are done. In this case, it is four iterations to cover a whole nametable.

This code assumes you have already loaded PPUDATA.

Author:  nesrocks [ Tue Aug 01, 2017 5:21 pm ]
Post subject:  Re: Basic nametable reading question

tepples wrote:
Do you know what a pointer is?

So you mean I can use that to retrieve the label's address at runtime and find the rest of the data relative to its position? I'll look further into zero page pointers and see if that's the case, thanks.

Pre-posting edit: It seems that's the case (sans my probably imprecise way of describing it), thanks mikejmoffitt!

edit: it works! The only typo in your code is that instead of reading and writing to/from "addr_ptr+1" you wrote "nametable+1" but that was an easy fix. Thanks! I'll study those operators (<, >, +1 etc), I kind of see what they do but I had never seen them.

Updated code for posterity:
Code:
; Put nametable source address in addr_ptr
lda #<nametable
sta addr_ptr
lda #>nametable
sta addr_ptr+1

; Copy one page of data ($100 bytes)
@copypage:
ldy #0
@copyloop:
lda (addr_ptr), y
sta PPUDATA
iny
bne @copyloop

; Move on to the next page, or leave if finished
lda addr_ptr+1
clc
adc #1
sta addr_ptr+1
cmp #(>nametable + 4)
bne @copypage

Author:  thefox [ Wed Aug 02, 2017 9:17 am ]
Post subject:  Re: Basic nametable reading question

nesrocks wrote:
Code:
nametable:
.incbin "level_01_bg.nam"

Indirect addressing with (dd),y is the way to go (smaller code size, not that much slower), but I'll just note that you could've also done this to avoid splitting the data manually to 4 parts:
Code:
nametable_part0:
nametable_part1 := nametable_part0+$100
nametable_part2 := nametable_part1+$100
nametable_part3 := nametable_part2+$100
.incbin "level_01_bg.nam"

Author:  tokumaru [ Wed Aug 02, 2017 10:03 am ]
Post subject:  Re: Basic nametable reading question

thefox wrote:
Code:
nametable_part0:
nametable_part1 := nametable_part0+$100
nametable_part2 := nametable_part1+$100
nametable_part3 := nametable_part2+$100
.incbin "level_01_bg.nam"

I sometimes need to do this (usually to label the individual arrays/fields of structures of arrays), so I created a ca65 macro for this (IIRC, you need to supply the names of all the labels and the macro calculates how far apart they are based on the length of the data and the number of labels - so it won't work if the arrays aren't all the same length). I can post it if anyone is interested, I just don't have it with me right now.

For something constant-sized like a name table I probably wouldn't bother creating separate labels though, I'd just adjust the base address directly in the 4 loops that copy the data:

Code:
lda nametable+$000, x
;(...)
lda nametable+$100, x
;(...)
lda nametable+$200, x
;(...)
lda nametable+$300, x

Author:  thefox [ Wed Aug 02, 2017 11:57 am ]
Post subject:  Re: Basic nametable reading question

For completeness, here's one more option (ca65 syntax):
Code:
nametable_part0:
.incbin "level_01_bg.nam", 0*256, 256
nametable_part1:
.incbin "level_01_bg.nam", 1*256, 256
nametable_part2:
.incbin "level_01_bg.nam", 2*256, 256
nametable_part3:
.incbin "level_01_bg.nam", 3*256, 256

Author:  rainwarrior [ Wed Aug 02, 2017 12:00 pm ]
Post subject:  Re: Basic nametable reading question

!!! How did I not know that ca65 has way to trim an .incbin like that???
Thanks for making me aware of this.

Author:  mikejmoffitt [ Wed Aug 02, 2017 12:09 pm ]
Post subject:  Re: Basic nametable reading question

nesrocks wrote:
tepples wrote:
Do you know what a pointer is?

So you mean I can use that to retrieve the label's address at runtime and find the rest of the data relative to its position? I'll look further into zero page pointers and see if that's the case, thanks.

Pre-posting edit: It seems that's the case (sans my probably imprecise way of describing it), thanks mikejmoffitt!

edit: it works! The only typo in your code is that instead of reading and writing to/from "addr_ptr+1" you wrote "nametable+1" but that was an easy fix. Thanks! I'll study those operators (<, >, +1 etc), I kind of see what they do but I had never seen them.


Glad it mostly worked! The < and > operators retrieve the low and high addresses of the provided symbol, respectively. <nametable gets the lower byte, and >nametable gets the higher byte of nametable. Putting those into a pointer in order gets you a pointer to the nametable.

addr_ptr+1 simply means "the high byte of addr_ptr", which is one byte after the symbol. That's because addr_ptr uses two bytes to represent a memory address. We're checking the high byte (in this little-endian system) because it effectively indexes the page, which we've already iterated through.

rainwarrior wrote:
!!! How did I not know that ca65 has way to trim an .incbin like that???
Thanks for making me aware of this.

Agreed, that's fantastic. This makes a yy-chr palette file directly usable as well.

Author:  tokumaru [ Wed Aug 02, 2017 12:12 pm ]
Post subject:  Re: Basic nametable reading question

rainwarrior wrote:
!!! How did I not know that ca65 has way to trim an .incbin like that???

I didn't know either! That may come in handy sometime!

Author:  FrankenGraphics [ Wed Aug 02, 2017 12:38 pm ]
Post subject:  Re: Basic nametable reading question

Incbin management like this is super useful for a beginner like me, too. Tip of the month at the very least!

Author:  nesrocks [ Wed Aug 02, 2017 3:19 pm ]
Post subject:  Re: Basic nametable reading question (.incbin addressing)

Amazing stuff that this information could be spread! And here I was wondering if writing "+1" was correct... :lol: Now I know a decimal number doesn't need a preceding character. Coming from a hacking background where I mostly worked with hex numbers typing byte code directly into the hex it looked weird to see in asm code.

And yeah, being able to .incbin only a section of a file seems very powerful for the workflow, one could include parts of other ROMs without splitting it into different files or clogging your own ROM with useless bytes. The uses are endless.

Page 1 of 1 All times are UTC - 7 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/