hey neil, i want to make a nintendo program that has a sav file, are there any good tutorials or resources online that you can point me to that will help me figure this out?
hey neil, i want to make a nintendo program that has a sav file, are there any good tutorials or resources online that you can point me to that will help me figure this out?
It's fairly straightforward - you need to change your ROM configuration to use MMC1 mapper (I think that's the minimum you need mapper-wise) and you'll need to change the ROM header. After that, NVRAM (battery-backed RAM) is mapped at $6000-$7FFF and you can just read and write to it like normal RAM.
I'll send you some code.
nickmaynard wrote:hey neil, i want to make a nintendo program that has a sav file, are there any good tutorials or resources online that you can point me to that will help me figure this out?
It's fairly straightforward - you need to change your ROM configuration to use MMC1 mapper (I think that's the minimum you need mapper-wise) and you'll need to change the ROM header. After that, NVRAM (battery-backed RAM) is mapped at $6000-$7FFF and you can just read and write to it like normal RAM.
I'll send you some code.
wow, that would be really great neil. thanks!
Actually, turns out you don't even need MMC1 (in Nestopia at least). Here's some bare-bones code that will write 00-FF in the first 256 bytes of a .sav file. The key part is setting bit 1 of the 6th byte of the iNES header (http://wiki.nesdev.com/w/index.php/INES)
;NES Header
DB "NES",$1A
DB 2 ;number of PRG ROMs
DB 0 ;number of CHR ROMs
DB %00000010 ; BIT 1 = enable(1)/disable(0) battery RAM
DB %00000000
DB 0,0,0,0,0,0,0,0
WRAM EQU $6000
.ORG $8000
RESET sei
ldx #$FF
txs
ldx #$00
@a txa
sta WRAM,x
inx
bne @a
LOOP jmp LOOP
NMI RTI
IRQ RTI
ORG $FFFA
DW NMI,RESET,IRQ
Last edited by neilbaldwin (Jan 8, 2011 11:26 pm)
awesome, thanks for the code. some of this is still over my head but this is a great place to start learning.
I realised afterwards that some of that might be confusing (or that your code for the Chords program is set up a little differently) - I wanted to give you something that would compile and work in ASM6 (I guessed that was what you used?)
Really, the only parts you need that can be transplanted in your own code is setting bit 1 of the 6th header byte and then knowing you just read/write addresses $6000-$7FFF to access the battery RAM. The rest of my example is just reset code and the necessary layout to make a working ROM.
I realised afterwards that some of that might be confusing (or that your code for the Chords program is set up a little differently) - I wanted to give you something that would compile and work in ASM6 (I guessed that was what you used?)
Really, the only parts you need that can be transplanted in your own code is setting bit 1 of the 6th header byte and then knowing you just read/write addresses $6000-$7FFF to access the battery RAM. The rest of my example is just reset code and the necessary layout to make a working ROM.
yeah, i actually think i get it. i tried out your code and saw that it wrote that info to the sav file. i'm going to set up a little test program where you can set a variable, then save it, then see if the program can call that information back up when i reopen the program.
thanks a lot for the help!
LOL just spotted a schoolboy error - I'd wrote 'sta WRAM,y' instead of 'sta WRAM,x'
Fixed now
so, i've been messing with this a lot and i've got a quick question. can you tell me why THIS code seems to work...
.ORG $7ff0
Header:
.db "NES", $1a
.db $02
.db $01
.db %00000010
.db %00000000
.db $00
.db $00
.db $00
.db $00
.db $00
.db $00
.db $00
.db $00
WRAM EQU $6000
.org $8000
Reset:
SEI
ldx #$FF
txs
lda #$25
sta WRAM
LOOP: jmp LOOP
NMI: RTI
IRQ: RTI
.ORG $fffa
.dw NMI
.dw Reset
.dw IRQ
...while this code does NOT work?
.ORG $7ff0
Header:
.db "NES", $1a
.db $02
.db $01
.db %00000010
.db %00000000
.db $00
.db $00
.db $00
.db $00
.db $00
.db $00
.db $00
.db $00
WRAM EQU $6000
.org $8000
Reset:
SEI
ldx #$FF
txs
LOOP: jmp LOOP
NMI:
lda #$25
sta WRAM
RTI
IRQ: RTI
.ORG $fffa
.dw NMI
.dw Reset
.dw IRQ
the code looks kind of wonky when i paste it in here, but it's not all weirdly tabbed in my .asm file. #$25 is just a totally random value, by the way.
Last edited by nickmaynard (Jan 10, 2011 5:46 am)
It's because the NMI never gets triggered. You need to enable NMIs through the PPU Control Register 1 ($2000). To enable the NMI you just set bit 7. Put this somewhere before the LOOP;
lda #$80
sta $2000
The PPU control registers do a lot more so you should be familiar with the various functions they provide;
http://nesdev.parodius.com/NinTech.txt
(near the bottom of the page is a table listing what each bit of PPU 1/2 Control and PPU Status does)
It's also common practice to 'acknowledge' the NMI in your NMI code by 'reading' the PPU Status Register ($2002)
bit $2002
at the start of the NMI.
Something else you should do in the NMI is save the contexts of the A, X and Y registers - this is because the NMI can occur at any point in your background loop and once the NMI has finished, the register contents could have been changed. You use the stack instructions PHA and PLA.
NMI:
pha ;push A onto stack
txa ;transfer X to A
pha ;push A onto stack
tya ;transfer Y to A
pha ;push A onto stack
bit $2000 ;acknowledge interrupt
;do other stuff
pla ;pull top of stack to A
tay ;transfer A to Y
pla ;pull next by off stack to A
tax ;transfer A to X
pla ;pull A off stack
rti
The stack is a LIFO buffer (last in, first out) so you restore the registers in the reverse order to what you saved them. Because you can only push (PHA) and pull (PLA) a value to/from the A register, in order to save the content of X and Y you transfer them to the accumulaor (A) first when saving, and then reverse the procedure for restoring.
Edited to add:
In fact, most people clear the two PPU Control registers at the start of the reset code too:
PPU0 EQU $2000
PPU1 EQU $2001
RESET:
sei
lda #$00
sta PPU0
sta PPU1
ldx #$FF
txs
etc.
Last edited by neilbaldwin (Jan 10, 2011 9:11 am)
Sorry, that happens a lot to stuff I get involved with. It's a constant burden.
I was thinking about this today. This kind of topic is not really music-releated and so if a moderator wants to move it I don't mind. Maybe it's worth having a coding/programming section? I know it's slightly off-topic for the whole board but it has a tangential connection. Nick's chord program and also probably things like Litewall could be moved there.
I think its more than on topic, and interesting to read, even if barely understand anything.
I think its more than on topic, and interesting to read, even if barely understand anything.
Ah cool. I'm more than happy to answer general programming questions like this in the forum then if everyone else is.
awesome! it works perfectly now neil. thanks for the lesson.
there's so much about this i don't know yet and most of the documentation i've been able to find assumes a certain level of coding experience that i just don't have. so it's really helpful for you to go through some of this with me.