First off, I think calima's post is important
and should not get lost in this mess. SNESGSS is intended to produce game audio. An SPC is not game audio; it is a dump of game audio for playback on PCs.
rchoudhary wrote:So, if I'm getting this correct, using an 8-bit address directly is super fast since the bus is 8 bits wide.
There's a caveat. If the direct page offset is not a multiple of 256 (that is, the bottom byte is nonzero), the CPU has to spend a cycle adding it to the 8-bit address and you don't get any speed benefit over 16-bit addressing. The code is still smaller, and there are use cases where the direct page register can be used almost as a third index register, so there may still be benefits to using non-page-aligned DP. Also, in some cases indexing can add a cycle to 8-bit but not 16-bit addressing, with much the same result. Exact instruction timing is probably out of scope for the moment, so let's leave that topic...
Now since you're confined to [$00, $FF], something like the following is impossible?
Code: Select all
.byte001: .byte $00
.byte002: .byte $00
.byte256: .byte $00
.byte257: .byte $00 ; Overflow of the zero page!
.byte258: .byte $00
.byte259: .byte $00
Yes. Zero page is 256 bytes long. If you want to access $0100 on a 6502, you need to use 16-bit addressing. On a SNES, you could either use 16-bit addressing or change DP so that $0100 is within scope. (Or use 24-bit addressing, because direct page is always in bank zero and if your data bank is nonzero you could end up with 8-bit and 16-bit addressing pointed at different banks. Fortunately the SNES has the exact same identical RAM mirror and system registers in fully half of all the banks in the memory space, which mitigates this issue somewhat.)
Furthermore, with the 65816, the bank register is used in tandem with any 8-bit addresses so that instead of being confined to [$00, $FF], you can access [X+$00, X+$FF] for any 16-bit X.
It's not a "bank" register. The term "bank" in the context of S-CPU addressing is reserved for the top byte of a 24-bit address. The program and data bank registers are 8-bit registers that are used to 'complete' 16-bit addresses. The direct page register is a 16-bit register that does what you describe. And it's not X, it's D (or DP). X is one of the index registers.
So, I guess that's a yes.
However, you're saying that this movable zero page is not possible with ca65.
No, you can still do it, because ca65 allows you to use the instructions that move direct page around at runtime. But the assembler was designed for the 6502 and its automatic organization functionality doesn't recognize the possibility of doing this. I haven't used ca65, so I'm not totally sure how far you'd have to go to work around it, but I'm pretty sure you can.
93143 wrote:You will only ever get one ROM bank to one SNES bank, but some SNES banks have other stuff in them besides ROM, which gets in the way a little and makes the remapping necessary.
This part confuses me a bit. Are you saying that a single bank in the SNES could have a bank from the ROM and
something else? A ROM bank can either be 32KB or 64KB, but a SNES bank is always
Right. Take a look at the image you posted. In the first and third quarters of the map, there's a bunch of stuff between $0000 and $7FFF in each bank, and it's not ROM. Then you have ROM from $8000 to $FFFF.
This means you can write code that accesses ROM, RAM, the PPU bus and the CPU's internal MMIO registers, all without using 24-bit addressing for anything.
Does this mean that:
Code: Select all
ROM addresses | is in | SNES Bank | SNES Addresses
$000000 - $007FFF | | $00 | $8000-$FFFF
$008000 - $00FFFF | | $01 | $8000-$FFFF
$010000 - $017FFF | | $02 | $8000-$FFFF
... | | ... | ...
$3D8000 - $3DFFFF | | $7B | $8000-$FFFF
$3E0000 - $3E7FFF | | $7C | $8000-$FFFF
$3E8000 - $3EFFFF | | $7D | $8000-$FFFF
It looks like by shifting the SNES bank left by 15 gets you the high 12 bits of the ROM address. Does that mean anything...?
Not really, other than the fact that each ROM bank is a 15-bit address space, and they're contiguous in the actual ROM chip. My understanding is that the cartridge just connects pins 16+ of the A bus address to pins 15+ of the ROM address, and pin 15 of the A bus address either does nothing or helps trigger SRAM select in a small logic chip, but not every cartridge was wired the same and there may be differences in how they handled things.
Also, the bank byte is 8 bits, so I'm not sure how you got 12 just by shifting it...
If so, this implies that in LoROM mode, you can access up to $3F0000 locations right?
How do you figure? The bank byte being bits 15-22 of the address would give you 8 MB of addressable space. Banks $7E and $7F are taken up by WRAM, so you can't actually access a full 8 MB in pure LoROM mode, but if you do the usual trick of mirroring banks $00-$7F of the ROM in banks $80-$FF on the S-CPU bus (ie: the cartridge ignores pin 23 of the A bus address for ROM accesses), you can do 4 MB pretty easily because the ROM that's blocked by WRAM in $7E and $7F appears unobstructed in $FE and $FF.
Also where do ROM banks fit in all of this?
Well, there's not necessarily such a thing, except in so far as certain areas of ROM are mapped to specific SNES banks. So the first 32 KB of a ROM could be considered the first "bank" if you're using a LoROM-type map, and the assembler would need to know this in order to put things where they should go and translate labels and such. But technically the ROM is contiguous. Or for big games it could be multiple chips - a 4 MB game might have been four 1 MB ROMs. The ROM bank structure of 32 or 64 KB chunks is purely conceptual, necessary only to allow the assembler to put together a working SNES program.
93143 wrote:a 32 KB LoROM bank appears in its entirety in the top half of a 64 KB SNES bank, so any address in the ROM is higher by $8000 when it appears on the SNES main bus.
So based on that table I made earlier, I think this is the process of turning a ROM address into a SNES address:
- 1. Take the ROM address and right shift by 15. This is the SNES bank number.
2. Take the low 15 bits of the ROM address. Then add $8000 to it. This is the SNES address.
3. SNES bank + SNES address = absolute SNES address?
- 1. Yes, but no. You can generally add $80 to the SNES bank number thus obtained (and/or possibly $40 or $C0 or whatever, depending on the cartridge) and still have the correct address, because of mirroring. It may even be better to do so, because if you access ROM in bank $80 or above, you can use FastROM mode...
3. Technically the term "absolute" means 16-bit addressing within a bank. (This is probably a holdover from the 6502, which had a 16-bit address space and no banks.) Full 24-bit addressing is called "long" addressing. Other than that, yes, assuming that by "+" you don't literally mean addition. (SNES bank << 16) + absolute SNES address = long SNES address.
Where does the code and ROM data live? I know it starts out on the cartridge, but does it stay there?
Yes, generally. Obviously you have to feed the PPU graphics data, and if you have compressed data you may want to decompress it into WRAM as needed (particularly since it is very advantageous to have graphics data in an uncompressed block that can be rapidly transferred via DMA during VBlank). And obviously any data generated by the program has to go in RAM. But code usually stays in ROM and is executed in place. Exceptions would include certain types of special chip games, where the CPU outright can't access the ROM if the coprocessor is using it, and self-modifying code, which doesn't work real well in read-only memory. In cases like those you'd have to explicitly transfer the code to RAM and jump to it, but since you aren't in a case like those you don't have to worry about it.
The audio module is different. It has no cartridge access, only a 64-byte boot ROM that defines a simple transfer protocol for the APU I/O ports. You have to follow this protocol to load a program and data (or, at minimum, your own data transfer code...) in order to play music and sound effects.
Specifically, when the processor enters the fetch state, where does it fetch from? Does the PC contain an address that gets translated into accessing the ROM as I detailed above?
The S-CPU does not really know the difference between ROM and any other part of its memory space. The address translation circuitry for the ROM is all in the cartridge. You can actually write to ROM just as easily as you can write to RAM, but of course the write won't do anything.
When you refer to an address in the code itself, e.g. lda $2000, that's a SNES address right? So if I want to access $3D8000 in the ROM, I need to set the SNES bank register to contain $7B with a tcd or pld instruction, and then I need to access $8000 with something like lda $8000.
No no. tcd
are for the direct page register, not either of the bank registers. You have to set the data bank with plb
- 1. How do I store stuff in the zero page with wla-dx?
2. (New one!) Is there a difference between .byte and .res in ca65? If so, which one does .db from wla-dx correspond to? And what's the equivalent of the other one?
3. How do I configure the SNES to have more banks and use a bigger ROM? I have a chip that supports up to 8Mbit, so I might as well set the limit to that.
- 1. WLA-DX doesn't care about any of that. You can define variables as 8-bit numbers, and if you use them as addresses it should default to using direct page. It might not; in that case it's best to use .b after the opcode, e.g. lda.b DPVAR, just to make sure it doesn't pad your address to 16 bits...
2. .db means define byte. It just plops a byte down into the ROM at the specified location (ie: if you use .db in the middle of a code section, you have to jump past it. Don't do that; it's silly.) You can .dw, meaning define 16-bit word, but since you can .db multiple comma-separated bytes you don't absolutely have to .dw; just remember that the SNES is little-endian. I haven't used ca65 so I don't know what its keywords mean.
3. Don't set the limit any higher than you need to. It will assemble a ROM that big and you will have to wait any time it needs to be written or loaded. That said, it should be as simple as changing .ROMBANKS to something higher than 4.
I kept .ROMBANKSIZE as is, set ROMSIZE $0A to correspond to 8 Mbit, did .ROMBANKS 8 so that I have 8 banks that're 1 Mbit each.
That's not how that works. Specifying .ROMBANKS 8
combined with .ROMBANKSIZE $8000
does not give you 8 banks of size $20000.
If you're using LoROM, ROM banks are always 32 KB ($8000 bytes). This is because the assembler has to make sure the ROM constitutes a working SNES program when mapped into the SNES address space, and if your cartridge is ignoring bit 15 of the address, using 32 KB banks is the only way to do that. Do not change .ROMBANKSIZE
doesn't do anything. It's part of the header, which is for bookkeeping purposes only (and to tell some emulators and flashcarts what they're supposed to pretend to be, although I'm sure Nintendo didn't plan for that when they designed it). The SNES doesn't read the header, and I'm pretty sure the assembler doesn't care what it says either, other than to include it in the ROM.
As for why what you did didn't work...
Code: Select all
.incbin SPC_FILE skip $10100 read $0080
adds up to the offset in the error message...
Are you sure everything is shipshape in your data includes? Correct filesizes and all?
WLA DX can be weird sometimes. This may not be your fault.
I have no idea, and I've kinda run out of time. Must go to bed...
I'm completely ignoring HiROM until I can actually grasp LoROM
Probably wise. I found memory mapping to be the hardest thing to understand about the SNES.