Hello World

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

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

Post by tepples »

FinalZero wrote:
2) Do not depend on the flags at the time of reset. You'll usually end up clearing X, S, and half of P in the first six instructions anyway. All you can be sure of is that PC points where $FFFC-$FFFD says.
What do you mean "where $FFFC-$FFFD says."? How do I set where?
That's one of the "vectors". How you set up the vectors depends on your assembler. I remember how only for ca65, not asm6 or nesasm.
Why are you setting the interrupt flag in your code?
To prevent IRQs from happening during the init code. True, the CPU already sets the interrupt priority bit to 1 (NMIs only) when coming out of reset, but having an explicit SEI makes the game more compatible with badly coded multicart menus that start the game with a JMP ($FFFC) but put the interrupt priority at 0 (CLI).
Okay, so that's the overlay thing again. I don't understand which segments overlay what. Is it by bank/memory-area? Basically, I still don't understand how my linker file is supposed to be set up.
Which assembler are you using again? If ca65, I have a project template that sets most of this up for you.
User avatar
FinalZero
Posts: 152
Joined: Thu Dec 03, 2009 7:27 am
Contact:

Post by FinalZero »

Which assembler are you using again? If ca65, I have a project template that sets most of this up for you.
ca65, yes. Also, I'm trying to use MMC1.
To prevent IRQs from happening during the init code. True, the CPU already sets the interrupt priority bit to 1 (NMIs only) when coming out of reset, but having an explicit SEI makes the game more compatible with badly coded multicart menus that start the game with a JMP ($FFFC) but put the interrupt priority at 0 (CLI).
But why would one expect an interrupt? Anyways, do you clear the flag at the end of the init code then?

* * *

Here's my linker code at the moment.

Code: Select all

MEMORY {
	# Header
	HEADER:   start = $0000, size = $0010;
	
	# Ram
#	ZEROPAGE: start = $0000, size = $0100;
#	STACK:    start = $0100, size = $0100;
	RAM:      start = $0200, size = $0600, fill = yes;
	
	# Rom
	LOWER_PROG_ROM: start = $8000, size = $2000, fill = yes;
	LOWER_CHAR_ROM: start = $A000, size = $1000, fill = yes;
	UPPER_CHAR_ROM: start = $B000, size = $1000, fill = yes;
	UPPER_PROG_ROM: start = $C000, size = $4000, fill = yes;
}
#-------------------------------------------------------------------------------

SEGMENTS {
	# Header
	HEADER:   load = HEADER,   type = ro;
	
	# Ram
#	ZEROPAGE: load = ZEROPAGE, type = zp;
#	STACK:    load = STACK,    type = rw;
	RAM:      load = RAM,      type = rw;
	
	# Rom
	CODE:      load = LOWER_PROG_ROM, type = ro;
	FONT:      load = LOWER_CHAR_ROM, type = ro;
	TILES:     load = UPPER_CHAR_ROM, type = ro;
	
	MORE_CODE: load = UPPER_PROG_ROM, type = ro;
	VECTORS:   load = UPPER_PROG_ROM, type = ro, start = $FFFA;
}
#-------------------------------------------------------------------------------
Do I need to include the zeropage and stack segments even if nothing gets initialized there? Also, when I open it in FCEUX, I don't see any code at $8000 in the debugger, even though there should be.

And my header:

Code: Select all

.byte $4E, $45, $53, $1A ; "NES", eof
.byte 1 ; Number of 16 kB prog ROM Segments
.byte 1 ; Number of 8 kB char ROM Segments
.byte %00010001 ; Byte 6 (Mirroring (0xx0: Horizontal, 0xx1: Vertical), Ignored if the mapper controls mirroring.)
.byte %00000000 ; Byte 7
.byte 0 ; Number of 8 kB prog RAM Segments
.byte 0 ; Byte 9 (0: NTSC, 1: PAL)
.byte 0 ; Byte 10 (Sporadically Supported)
.byte 0, 0, 0, 0, 0 ; Filler
;-------------------------------------------------------------------------------
Does MMC1 even use 8kb PROG RAM?
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

FinalZero wrote:ca65, yes. Also, I'm trying to use MMC1.
If you have only 16 or 32 KiB of PRG ROM and only 8 KiB of CHR, why are you using MMC1 and not just NROM? Is it just for the switchable nametable mirroring?
But why would one expect an interrupt?
Sources of IRQs on the NES other than mappers include the APU frame IRQ and the DMC completion IRQ. A few games on simple mappers without their own scanline or CPU cycle counter circuits (ab)use the DMC completion IRQ as a crude scanline counter.
Anyways, do you clear the flag at the end of the init code then?
A lot of games appear to just leave the ignore IRQs flag turned on (SEI) because they never use any IRQs.
HEADER: start = $0000, size = $0010;
For this, you may want to specify "fill=yes, fillval=$00", which means you won't need the "; Filler" line at the end of the header.

Code: Select all

   LOWER_PROG_ROM: start = $8000, size = $2000, fill = yes;
   LOWER_CHAR_ROM: start = $A000, size = $1000, fill = yes;
   UPPER_CHAR_ROM: start = $B000, size = $1000, fill = yes;
   UPPER_PROG_ROM: start = $C000, size = $4000, fill = yes;
[...]
I don't see any code at $8000 in the debugger
That's because with one 16 KiB bank, you need the following in order: UPPER_PROG_ROM, then LOWER_CHAR_ROM, then UPPER_CHAR_ROM. The only time CHR ROM ever comes before PRG ROM is in certain CHR RAM setups, and there is no LOWER_PROG_ROM in a 16 KiB PRG ROM. And your PRG ROM is in fact 16 KiB, as seen next:

Code: Select all

.byte 1 ; Number of 16 kB prog ROM Segments
.byte 1 ; Number of 8 kB char ROM Segments
Some MMC1 boards have PRG RAM; others don't. In fact, the possibility of PRG RAM doesn't depend much on the mapper; even one board in the NROM class (mapper 0) has PRG RAM.

If you don't want to spend a lot of time fixing your linker script, I recommend just using the NROM project template that I linked, which has a known working linker script.
User avatar
FinalZero
Posts: 152
Joined: Thu Dec 03, 2009 7:27 am
Contact:

Post by FinalZero »

If you don't want to spend a lot of time fixing your linker script, I recommend just using the NROM project template that I linked, which has a known working linker script.
I want to know why though. I don't want to just be cargo-cult programming.
And your PRG ROM is in fact 16 KiB, as seen next:
Can't I just switch it to 2 then? (That doesn't seem to do anything. The debugger still shows nothing.)
Some MMC1 boards have PRG RAM; others don't. In fact, the possibility of PRG RAM doesn't depend much on the mapper; even one board in the NROM class (mapper 0) has PRG RAM.
What is PRG RAM used for anyways? It's not any faster than PRG ROM, is it?
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

FinalZero wrote:What is PRG RAM used for anyways?
It's used for whatever programmers dissatisfied with the stock 2KB of RAM want. Many games put things like decompressed level maps there. It's just RAM, usually 8KB of it, to complement the 2KB that are built in the console.
It's not any faster than PRG ROM, is it?
No.
3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

PRG-RAM is the extra RAM at $6000-$7FFF. It's in the cart, sometimes battery backed up. SMB3 has it to decompress level to. Metroid also has it. So does Kid Icarus, although none of them back it up, it's just 8KB more RAM for stuff. Other games like zelda also use it for probably more space, but also saving information on the cart to continue later, which is very important in RPGs and why most have PRG-RAM with a battery like Zelda 1+2, Crystalis, Startropics, etc. MMC5 has even bankswitchable PRG-RAM, so you can have 16KB, maybe more, although nobody has ever used that much in the day so more isn't supported by any mappers but that one.
User avatar
FinalZero
Posts: 152
Joined: Thu Dec 03, 2009 7:27 am
Contact:

Post by FinalZero »

If you have only 16 or 32 KiB of PRG ROM and only 8 KiB of CHR, why are you using MMC1 and not just NROM? Is it just for the switchable nametable mirroring?
I want to practice/try mirroring, yes.
It's used for whatever programmers dissatisfied with the stock 2KB of RAM want. Many games put things like decompressed level maps there. It's just RAM, usually 8KB of it, to complement the 2KB that are built in the console.
Okay.
Other games like zelda also use it for probably more space, but also saving information on the cart to continue later, which is very important in RPGs and why most have PRG-RAM with a battery like Zelda 1+2, Crystalis, Startropics, etc. MMC5 has even bankswitchable PRG-RAM, so you can have 16KB, maybe more, although nobody has ever used that much in the day so more isn't supported by any mappers but that one.
It's only that ram that's battery-backed-up though, right? What else must one do to use battery-backed-up saves?
3gengames
Formerly 65024U
Posts: 2281
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

Yeah, the 8KB is the only stuff that's backed up. And to use the back up function what you have to do is program your game/program to boot up and not clear the memory, but format it if need be and put someting in there to know it's been formatted and then use all the other data in the RAM as the state of your game and program your game to load from it.
User avatar
FinalZero
Posts: 152
Joined: Thu Dec 03, 2009 7:27 am
Contact:

Post by FinalZero »

Yeah, the 8KB is the only stuff that's backed up. And to use the back up function what you have to do is program your game/program to boot up and not clear the memory, but format it if need be and put someting in there to know it's been formatted and then use all the other data in the RAM as the state of your game and program your game to load from it.
Okay.

Also, can someone explain exactly what's wrong with my linker file?
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

The first thing that's wrong is that the CHR ROM data isn't last in the file, as it MUST be. Can you paste your revised linker script that fixes this problem?
User avatar
FinalZero
Posts: 152
Joined: Thu Dec 03, 2009 7:27 am
Contact:

Post by FinalZero »

The first thing that's wrong is that the CHR ROM data isn't last in the file, as it MUST be. Can you paste your revised linker script that fixes this problem?
I am confused. Why must it be last? Looking at http://wiki.nesdev.com/w/index.php/MMC1 , it isn't listed last there.

Edit: Okay, wait. I'm not even sure why I put the char rom at the locations I did. It doesn't match the documentation. Where does the char rom go in MMC1?
Last edited by FinalZero on Fri Dec 02, 2011 5:03 pm, edited 1 time in total.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

The relevant wiki article is iNES. In all mappers that use CHR ROM, the CHR data comes last in the file. First the header, then the PRG ROM, then the CHR ROM.
User avatar
FinalZero
Posts: 152
Joined: Thu Dec 03, 2009 7:27 am
Contact:

Post by FinalZero »

Linker File:

Code: Select all

MEMORY {
	# Header
	HEADER: start = $0000, size = $0010, fill = yes, fillval = $00;
	
	# General Ram
#	ZEROPAGE:  start = $0000, size = $0100;
#	STACK:     start = $0100, size = $0100;
	RAM:       start = $0200, size = $0600, fill = yes;
	EXTRA_RAM: start = $6000, size = $2000, fill = yes;
	
	# Prog Rom
	LOWER_PROG_ROM: start = $8000, size = $4000, fill = yes;
	UPPER_PROG_ROM: start = $C000, size = $4000, fill = yes;
	
	# Char Rom
	LOWER_CHAR_ROM: start = $0000, size = $1000, fill = yes;
	UPPER_CHAR_ROM: start = $1000, size = $1000, fill = yes;
}
#-------------------------------------------------------------------------------

SEGMENTS {
	# Header
	HEADER:   load = HEADER,   type = ro;
	
	# Ram
#	ZEROPAGE:  load = ZEROPAGE,  type = zp;
#	STACK:     load = STACK,     type = rw;
	RAM:       load = RAM,       type = ro;
	DATA:      load = RAM,       type = rw;
	RODATA:    load = RAM,       type = ro;
	EXTRA_RAM: load = EXTRA_RAM, type = ro;
	
	# Prog Rom
	CODE:      load = LOWER_PROG_ROM, type = ro;
	MORE_CODE: load = UPPER_PROG_ROM, type = ro;
	VECTORS:   load = UPPER_PROG_ROM, type = ro, start = $FFFA;
	
	# Char Rom
	FONT:      load = LOWER_CHAR_ROM, type = ro;
	TILES:     load = UPPER_CHAR_ROM, type = ro;
}
#-------------------------------------------------------------------------------
Header File:

Code: Select all

.segment "HEADER"
;-------------------------------------------------------------------------------

.byte $4E, $45, $53, $1A ; "NES", eof
.byte 2 ; Number of 16 kB prog ROM Segments
.byte 1 ; Number of 8 kB char ROM Segments
.byte %00010001 ; Byte 6 (Mirroring (0xx0: H, 0xx1: V))
.byte %00000000 ; Byte 7
.byte 0 ; Number of 8 kB prog RAM Segments
;-------------------------------------------------------------------------------
It assembled, but doesn't show anything in the debugger.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

I see your LOWER_PROG_ROM and UPPER_PROG_ROM sum to 32 KiB. Are you making sure to specify two 16k pages in the iNES header? And are you making sure to replicate the vectors and the beginning of the init code in all 16k banks (the Barbie stub) so that no matter how the MMC1's registers are set at power on, the program still starts? If all this is Greek to you, I would recommend removing LOWER_PROG_ROM entirely from your linker script and putting all your code and data in UPPER_PROG_ROM for now.

In MEMORY, do not use fill=yes for any memory area that is RAM. This means remove it from RAM and EXTRA_RAM. If you use fill=yes, the linker will try to (uselessly) put initial values for the memory area into the ROM file. Only memory areas that represent ROM should have fill=yes.

In SEGMENTS, use type=bss instead of type=rw for any RAM segment. For segments of type bss, the linker won't try to (uselessly) put initial values for the segment into the ROM file.
User avatar
FinalZero
Posts: 152
Joined: Thu Dec 03, 2009 7:27 am
Contact:

Post by FinalZero »

I see your LOWER_PROG_ROM and UPPER_PROG_ROM sum to 32 KiB. Are you making sure to specify two 16k pages in the iNES header?
Yes.
And are you making sure to replicate the vectors and the beginning of the init code in all 16k banks (the Barbie stub) so that no matter how the MMC1's registers are set at power on, the program still starts?
I didn't know that I needed to.
If all this is Greek to you, I would recommend removing LOWER_PROG_ROM entirely from your linker script and putting all your code and data in UPPER_PROG_ROM for now.
Okay, I'll try that first.
In MEMORY, do not use fill=yes for any memory area that is RAM. This means remove it from RAM and EXTRA_RAM. If you use fill=yes, the linker will try to (uselessly) put initial values for the memory area into the ROM file. Only memory areas that represent ROM should have fill=yes.
Okay.
In SEGMENTS, use type=bss instead of type=rw for any RAM segment. For segments of type bss, the linker won't try to (uselessly) put initial values for the segment into the ROM file.
Why is it useless though? Isn't data stored there? I don't see why it should be any different from the CODE segment.

And... I see my code at $8000! There's stuff at $C000 too, but it's nothing I wrote, and appears to be random garbage. However, running the debugger, it seems to be alternating between $0002 and $FFFF. I don't know why.

Edit: I forgot to change the number of PRG banks in the header back to 1. Doing that, it runs code that I wrote. I think I made an error in the code though, because it isn't doing the addition that I wanted it to do.

Edit Edit: It seems to be interrupting every so often, and then returning to the wrong address. Ideas as to why?
Post Reply