.bank .org question

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
NeverCameBack
Posts: 31
Joined: Mon Feb 24, 2020 12:22 am

.bank .org question

Post by NeverCameBack » Sat May 09, 2020 12:26 pm

I'm missing some knowledge on "banks", ".org" directives.

If we have:
.bank 0
.org $8000
"code goes here"

.bank 1
.org $A000
"code goes here"

.bank 2
org $C000
"more code here"


From what I understand, the .bank 0 defines an 8 kb chunk of memory, and then we're telling it to select the chunk starting at CPU address $8000, and write all the following code starting at that CPU address.
But what is the point of .bank 0, if we're going to just tell the CPU where to start putting the code that follows with the .org directive anyway?


I see in a lot of the sample programs where they're putting the .chr graphics file at:
org 0000.PNG
org 0000.PNG (2.88 KiB) Viewed 897 times
Wouldn't this end up writing graphics data to the Internal CPU RAM at $0000 to $0800 ?
NES CPU memory layout.PNG
NES CPU memory layout.PNG (5.12 KiB) Viewed 897 times
When the CHR data shouldn't even be put on the CPU anywhere right? Doesn't it go directly from the cart's CHR ROM chip directly to the NES PPU chip?
NES and Cart hardware layout.PNG

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

Re: .bank .org question

Post by tokumaru » Sat May 09, 2020 12:50 pm

Please remember state the assembler you're using. The behavior of assembler directives varies from assembler to assembler. From the code I assume you're using NESASM, correct?
NeverCameBack wrote:
Sat May 09, 2020 12:26 pm
From what I understand, the .bank 0 defines an 8 kb chunk of memory
Yes.
and then we're telling it to select the chunk starting at CPU address $8000
You're not "selecting" anything. That .org statement is there to let the assembler know where in memory that code will be mapped. If you change the $8000 to, say, $94B7 the code will still be mapped to $8000, but then the assembler will create labels with the wrong values, most likely causing the program to crash when run.
But what is the point of .bank 0, if we're going to just tell the CPU where to start putting the code that follows with the .org directive anyway?
It's a dumb requirement of NESASM. Not all assemblers need that.
I see in a lot of the sample programs where they're putting the .chr graphics file at:
org 0000.PNG
Wouldn't this end up writing graphics data to the Internal CPU RAM at $0000 to $0800 ?
The NES has 2 memory buses, one for the CPU and one for the PPU, and they're completely independent from each other. CHR graphics are part of the PPU memory, which starts at $0000. It's normally not necessary to use .org on CHR banks though, unless you're creating labels there and using them to reference the tiles, but most programmers don't do that.

User avatar
Quietust
Posts: 1555
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: .bank .org question

Post by Quietust » Sat May 09, 2020 1:03 pm

NeverCameBack wrote:
Sat May 09, 2020 12:26 pm
From what I understand, the .bank 0 defines an 8 kb chunk of memory, and then we're telling it to select the chunk starting at CPU address $8000, and write all the following code starting at that CPU address.
But what is the point of .bank 0, if we're going to just tell the CPU where to start putting the code that follows with the .org directive anyway?
Because .bank and .org control two completely different things - .bank controls the location of the data in your output file (i.e. your ROM image), and .org specifies the address range in which the 6502 is actually going to see that data.

If you're using a mapper which supports bank switching, then you will have multiple banks which logically exist in the same memory region, though only one at a time. In order to reference any code or data in a given bank, the assembler needs to assign the correct absolute addresses to all of the labels inside (since the 6502 doesn't do relative addressing aside from conditional jumps), and for that reason you need to tell the assembler the base address of everything inside that bank.

To make things even more interesting, some mappers have multiple "windows" into which banks can be mapped. For example, the MMC3 has one window at $8000-$9FFF* and another at $A000-$BFFF, so in that case each bank would either have .org $8000 or .org $A000 at the beginning to denote where it's going to be mapped. In practice, each bank will only have one place where it'll get mapped - it's possible to map the same bank in multiple different places, but there's almost never a good reason to do it.

(* - technically, the window at $8000-$9FFF can also be relocated to $C000-$DFFF, leaving the original location to contain a fixed bank, but that's not important right now)

As Tokumaru explained, whatever value you specify for .org needs to be at the beginning of an actual bank - if you specify something else, then things won't work. If you're using a mapper which doesn't do bank switching (e.g. mapper 0), then banks 0/1/2/3 must begin with .org $8000 / .org $A000 / .org $C000 / .org $E000 (unless you have only two banks, in which case you'll just want $C000 and $E000).
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.

User avatar
NeverCameBack
Posts: 31
Joined: Mon Feb 24, 2020 12:22 am

Re: .bank .org question

Post by NeverCameBack » Sat May 09, 2020 2:13 pm

Would it be true then to say that:
.bank 0 = first 8 kb of memory in the actual rom (.nes file) = byte 0 to byte 7999 ?
.bank 1 = second 8 kb = byte 8,000 - byte 15,999 ?
.bank 2 = third 8 kb = byte 16,000 - byte 23,999 ?
.bank 3 = fourth 8 kb = byte 24,000 to 31,999?
- And these .bank directives are ONLY used for the compiler to actually build the .nes file?
- You can specify more banks, but only if you're using a mapper to swap them into the four with .orgs at $8000 - $E000, because the 6502 only has enough BUS "tentacles" to access a limited amount of memory locations.

Also,
.org $8000 => Hey CPU, run the code directly following this .org $8000 directive, with your $8000 address reading bus.

I'm not sure I totally understand about the .org needing to start at the beginning of a bank.
If we had:

.bank 0
.org $8001

Wouldn't this mean that the code following would be in the ROM address location of bytes 0 to 7,999, but the CPU would be directed to start reading the code from it's bus address at $8001, essentially leaving $8000 a dead pathway?

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

Re: .bank .org question

Post by tokumaru » Sat May 09, 2020 4:56 pm

NeverCameBack wrote:
Sat May 09, 2020 2:13 pm
.bank 0 = first 8 kb of memory in the actual rom (.nes file) = byte 0 to byte 7999 ?
It's actually byte 0 to byte 8191. One kilobyte is 1024 bytes.
.bank 1 = second 8 kb = byte 8,000 - byte 15,999 ?
8192 to 16383.
.bank 2 = third 8 kb = byte 16,000 - byte 23,999 ?
16384 to 24575.
.bank 3 = fourth 8 kb = byte 24,000 to 31,999?
24576 to 32767.
- And these .bank directives are ONLY used for the compiler to actually build the .nes file?
Yes, NESASM needs these directives in order to know how many 8KB banks your ROM has. You can also retrieve the bank number from labels for bankswitching purposes... For example, instead of doing lda #08 before switching to bank 8, you could do lda #BANK(SomeLabel) to select the bank where that label is defined, without having to manually keep track of where everything is, making code easier to maintain. If the mapper you're using doesn't work with 8KB banks, you may have to adjust the number returned by BANK() (e.g. lda #BANK(SomeLabel)/2 on a mapper that does 16KB bankswitching).
- You can specify more banks, but only if you're using a mapper to swap them into the four with .orgs at $8000 - $E000, because the 6502 only has enough BUS "tentacles" to access a limited amount of memory locations.
The addresses you have to use in .org statements vary depending on the mapper. Mappers are called "mappers" because they do just that - they map memory to the addressing space of the NES. Different mappers have different bank sizes and different configurations regarding fixed and switchable banks, and this affects the order in which the banks have to be ordered in the ROM file. Most of the time you have no control of what that order is, it's dictated by the mapper, and your only job is to communicate the assembler about where everything goes via the .org directive so it can generate proper references to the contents of your ROM banks.
.org $8000 => Hey CPU, run the code directly following this .org $8000 directive, with your $8000 address reading bus.
The CPU is completely unaware of banks and .org statements. As far as the CPU is concerned, there's only a straight sequence of 32768 bytes starting at $8000. All the trickery is handled by the mapper, which watches what addresses are being accessed and redirects those addresses to the appropriate parts of a memory chip larger than 32KB.
.bank 0
.org $8001
The bank would still be 8KB large and would still be visible between CPU addresses $8000-$9FFF. The assembler, however, would think it would be visible at $8001-$A000. Since this is not true, every reference to labels in this bank would be off by one byte. If you tried JSRing to a subroutine in this bank, it would actually jump to 1 byte ahead of the intended location, possibly skipping a instruction or even landing in the middle of one. This is the kind of thing that causes programs to crash (executing unintended code).

tepples
Posts: 21971
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: .bank .org question

Post by tepples » Sat May 09, 2020 7:18 pm

NeverCameBack wrote:
Sat May 09, 2020 2:13 pm
Would it be true then to say that:
.bank 0 = first 8 kb of memory in the actual rom (.nes file) = byte 0 to byte 7999 ?
.bank 1 = second 8 kb = byte 8,000 - byte 15,999 ?
.bank 2 = third 8 kb = byte 16,000 - byte 23,999 ?
.bank 3 = fourth 8 kb = byte 24,000 to 31,999?
Almost, except the banks are 8192 bytes (2^13 bytes), not 8000 bytes (8*10^3 bytes).
NeverCameBack wrote:
Sat May 09, 2020 2:13 pm
- You can specify more banks, but only if you're using a mapper to swap them into the four with .orgs at $8000 - $E000, because the 6502 only has enough BUS "tentacles" to access a limited amount of memory locations.
Pretty much. But in NROM-256, you can use .bank 4 for the CHR ROM data because that's assigned to a different set of tentacles.

As for the `.bank` followed by an unaligned `.org`, I'll let someone else more experienced in NESASM than I am answer as to whether padding is inserted. Because if it isn't, this means all jumps and other references to absolute addresses in that bank will be incorrect by 1 byte.

Post Reply