How to program a NINTENDO POWER Cartridge ?

Discussion of hardware and software development for Super NES and Super Famicom.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
skaman
Posts: 87
Joined: Fri Oct 24, 2014 1:56 am

Re: How to program a NINTENDO POWER Cartridge ?

Post by skaman »

I hooked up a logic analyzer to my GB cart interface that sits between the GB cart and the GB XChanger.

Here's the command sequences used when loading a new NP register:

Code: Select all

120, 09 (WR LOW)
121, AA (WR LOW)
122, 55 (WR LOW)
13F, A5 (WR LOW)

120, CF (WR LOW)
13F, A5 (WR LOW)

120, 08 (WR LOW)
13F, A5 (WR LOW)

120, 09 (WR LOW)
121, AA (WR LOW)
122, 55 (WR LOW)
13F, A5 (WR LOW)

120, C0 (WR LOW)
13F, A5 (WR LOW)

120, 08 (WR LOW)
13F, A5 (WR LOW)

120, 09 (WR LOW)
121, AA (WR LOW)
122, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0A (WR LOW)
125, 62 (WR LOW)
126, 04 (WR LOW)
13F, A5 (WR LOW)

120, 01 (WR LOW)
13F, A5 (WR LOW)

120, 02 (WR LOW)
13F, A5 (WR LOW)

2100, 01 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, AA (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 2A (WR LOW)
126, AA (WR LOW)
127, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, 60 (WR LOW)
13F, A5 (WR LOW)

2100, 01 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, AA (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 2A (WR LOW)
126, AA (WR LOW)
127, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, 40 (WR LOW)
13F, A5 (WR LOW)

REPEAT 242X
0000, 02 (RD LOW)
0000, 03 (WR LOW)

0000, 80 (RD LOW)
0000, 03 (WR LOW)

2100, 01 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, AA (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 2A (WR LOW)
126, AA (WR LOW)
127, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, 60 (WR LOW)
13F, A5 (WR LOW)

2100, 01 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, AA (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 2A (WR LOW)
126, AA (WR LOW)
127, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, 04 (WR LOW)
13F, A5 (WR LOW)

REPEAT 256X
0000, 00 (RD LOW)
0000, 03 (WR LOW)

0000, 80 (RD LOW)
0000, 03 (WR LOW)

120, 08 (WR LOW)
13F, A5 (WR LOW)

120, 09 (WR LOW)
121, AA (WR LOW)
122, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0A (WR LOW)
125, 62 (WR LOW)
126, 04 (WR LOW)
13F, A5 (WR LOW)

120, 01 (WR LOW)
13F, A5 (WR LOW)

120, 02 (WR LOW)
13F, A5 (WR LOW)

2100, 01 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, AA (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 2A (WR LOW)
126, AA (WR LOW)
127, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, A0 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 00 (WR LOW)
126, 00 (WR LOW)
127, FF (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 00 (WR LOW)
126, 00 (WR LOW)
127, FF (WR LOW)
13F, A5 (WR LOW)

2100, 01 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, AA (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 2A (WR LOW)
126, AA (WR LOW)
127, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, 60 (WR LOW)
13F, A5 (WR LOW)

2100, 01 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, AA (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 2A (WR LOW)
126, AA (WR LOW)
127, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, E0 (WR LOW)
13F, A5 (WR LOW)

2100, 00 (WR LOW)

120, 10 (WR LOW)
13F, A5 (WR LOW)

120, 08 (WR LOW)
13F, A5 (WR LOW)

0000, B4 (WR LOW) (NEW REGISTER FILE BEGINS)
0001, 00 (WR LOW)
0002, 00 (WR LOW)
0003, FF (WR LOW)
This sequence loads the first 0x80 bytes of the new NP register.
Last edited by skaman on Sat Dec 12, 2015 4:18 am, edited 4 times in total.
skaman
Posts: 87
Joined: Fri Oct 24, 2014 1:56 am

Re: How to program a NINTENDO POWER Cartridge ?

Post by skaman »

Now to the end of the 1st half of the new register file:

Code: Select all

007D, FF (WR LOW)
007E, 00 (WR LOW)
007F, 00 (WR LOW) (LAST BYTE OF FIRST HALF OF REGISTER)
007F, FF (WR LOW)

REPEAT 90X
0000, 00 (RD LOW)
0000, 03 (WR LOW)

0000, 80 (RD LOW)
0000, 03 (WR LOW)

120, 09 (WR LOW)
121, AA (WR LOW)
122, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0A (WR LOW)
125, 62 (WR LOW)
126, 04 (WR LOW)
13F, A5 (WR LOW)

120, 01 (WR LOW)
13F, A5 (WR LOW)

120, 02 (WR LOW)
13F, A5 (WR LOW)

2100, 01 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, AA (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 2A (WR LOW)
126, AA (WR LOW)
127, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, A0 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 00 (WR LOW)
126, 00 (WR LOW)
127, FF (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 00 (WR LOW)
126, 00 (WR LOW)
127, FF (WR LOW)
13F, A5 (WR LOW)

2100, 01 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, AA (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 2A (WR LOW)
126, AA (WR LOW)
127, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, 60 (WR LOW)
13F, A5 (WR LOW)

2100, 01 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, AA (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 2A (WR LOW)
126, AA (WR LOW)
127, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, E0 (WR LOW)
13F, A5 (WR LOW)

2100, 00 (WR LOW)

120, 10 (WR LOW)
13F, A5 (WR LOW)

120, 08 (WR LOW)
13F, A5 (WR LOW)

0080, FF (WR LOW) (START OF SECOND HALF OF NEW REGISTER FILE)
0081, FF (WR LOW)
0082, FF (WR LOW)
0083, FF (WR LOW)
Last edited by skaman on Sat Dec 12, 2015 4:20 am, edited 5 times in total.
skaman
Posts: 87
Joined: Fri Oct 24, 2014 1:56 am

Re: How to program a NINTENDO POWER Cartridge ?

Post by skaman »

Here's the end of the "Load NP Register" sequence. This code section starts with writing the end of the 2nd half of the new register file (all FFs). The subsequent commands read the entire new register file back (uses the 0x77 command).

Code: Select all

00FC, FF (WR LOW)
00FD, FF (WR LOW)
00FE, FF (WR LOW)
00FF, FF (WR LOW) (LAST BYTE OF SECOND HALF OF REGISTER)
00FF, FF (WR LOW)

0000, 00 (RD LOW)
0000, 03 (WR LOW)

0000, 80 (RD LOW)
0000, 03 (WR LOW)

120, 09 (WR LOW)
121, AA (WR LOW)
122, 55 (WR LOW)
13F, A5 (WR LOW)

2100, 01 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, AA (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 2A (WR LOW)
126, AA (WR LOW)
127, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, 77 (WR LOW)
13F, A5 (WR LOW)

2100, 01 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, AA (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 2A (WR LOW)
126, AA (WR LOW)
127, 55 (WR LOW)
13F, A5 (WR LOW)

120, 0F (WR LOW)
125, 55 (WR LOW)
126, 55 (WR LOW)
127, 77 (WR LOW)
13F, A5 (WR LOW)

120, 08 (WR LOW)
13F, A5 (WR LOW)

3000, 00 (WR LOW)

2100, 00 (WR LOW)

0000, B4 (RD LOW) (READ BACK THE NEW REGISTER FILE)
0001, 00 (RD LOW)
0002, 00 (RD LOW)
0003, FF (RD LOW)
..
00FC, FF (RD LOW)
00FD, FF (RD LOW)
00FE, FF (RD LOW)
00FF, FF (RD LOW) (LAST BYTE OF THE NEW REGISTER FILE)

0000, C0 (WR LOW)

120, 09 (WR LOW)
121, AA (WR LOW)
122, 55 (WR LOW)
13F, A5 (WR LOW)

120, C0 (WR LOW)
13F, A5 (WR LOW)

120, 08 (WR LOW)
13F, A5 (WR LOW)
Last edited by skaman on Sat Dec 12, 2015 4:23 am, edited 3 times in total.
skaman
Posts: 87
Joined: Fri Oct 24, 2014 1:56 am

Re: How to program a NINTENDO POWER Cartridge ?

Post by skaman »

Using the commands that I posted previously, I was able to write a new mapping sequence to the GB Memory cart. In the summary below, F# is BennVenn's function numbering as posted earlier in the thread.

Here's a summary:

Code: Select all

First section erases the register to FFs:
F2
F4
0x2100, 0x01
F1: 5555, AA
F1: 2AAA, 55
F1: 5555, 60
0x2100, 0x01
F1: 5555, AA
F1: 2AAA, 55
F1: 5555, 40
Loop (0x100 times):  
Read 0x0000, Write 0x03 to 0x0000 until 0x0000 reads 0x80 then write 0x03 one last time
0x2100, 0x01
F1: 5555, AA
F1: 2AAA, 55
F1: 5555, 60
0x2100, 0x01
F1: 5555, AA
F1: 2AAA, 55
F1: 5555, 04
Loop (0x100 times):  
Read 0x0000, Write 0x03 to 0x0000 until 0x0000 reads 0x80 then write 0x03 one last time
F3
----------------------
Second section writes the new mapping:
F2
F4
0x2100, 0x01
F1: 5555, AA
F1: 2AAA, 55
F1: 5555, A0
F1: 0000, FF
F1: 0000, FF
0x2100, 0x01
F1: 5555, AA
F1: 2AAA, 55
F1: 5555, 60
0x2100, 0x01
F1: 5555, AA
F1: 2AAA, 55
F1: 5555, E0
0x2100, 0x00
F5
F3
Write the 1st 0x80 bytes of the new mapping (0x00-0x7F)
0x007F, 0xFF (Write to 0x7F for a 2nd time)
Loop (0x100 times):  
Read 0x0000, Write 0x03 to 0x0000 until 0x0000 reads 0x80 then write 0x03 one last time
F2
F4
0x2100, 0x01
F1: 5555, AA
F1: 2AAA, 55
F1: 5555, A0
F1: 0000, FF
F1: 0000, FF
0x2100, 0x01
F1: 5555, AA
F1: 2AAA, 55
F1: 5555, 60
0x2100, 0x01
F1: 5555, AA
F1: 2AAA, 55
F1: 5555, E0
0x2100, 0x00
F5
F3
Write the 2nd 0x80 bytes of the new mapping (0x80-0xFF)
0x00FF, 0xFF (Write to 0xFF for a 2nd time)
Loop (0x100 times):  
Read 0x0000, Write 0x03 to 0x0000 until 0x0000 reads 0x80 then write 0x03 one last time
----------------------
Third section reads back the new register (not mandatory):
F2
0x2100, 0x01
F1: 5555, AA
F1: 2AAA, 55
F1: 5555, 77
0x2100, 0x01
F1: 5555, AA
F1: 2AAA, 55
F1: 5555, 77
F3
0x3000, 0x00
0x2100, 0x00
Read back the register from 0x0000
F2
0x120, 0xC0
0x13F, 0xA5
F3
Some other stuff I learned working with the code:

Code: Select all

The standard flash command 0x90 can retrieve the flash ID C2/89:
F2
F1: 5555, AA
F1: 2AAA, 55
F1: 5555, 90

To return the cart to the normal (menu) mode:
F2
0x120, 0xC0
0x13F, 0xA5
F3

Addressing an individual game in multigame mode is done:
F2
0x120, 0xC#
0x13F, 0xA5
F3

Where # is the slot (0..7).   C0 is the menu or the game in single game mode (no menu).  The cart also uses 0xCF which I assume addresses the entire flash (more testing needed).
I'm going to look into fully decoding the mapping. I think I've figured out most of it except for the 8-byte sequence at 0x70.

Now let's hope that some of this applies to the SF Memory carts.
nocash
Posts: 1405
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: How to program a NINTENDO POWER Cartridge ?

Post by nocash »

Cool, congrats on getting that working!

I am trying to figure out the memory map of the gameboy cart - just guessing - but it seems to look like so:

Code: Select all

For Reading:
  0000h..3FFFh --> FLASH Chip address 000000h..003FFFh
  4000h..7FFFh --> FLASH Chip address 000000h..003FFFh+RomBank*4000h
For Writing:
  0000h..00FFh --> FLASH Chip address 000000h..0000FFh
  0120h..013Fh --> Special Nintendo Power registers (among others used to access FLASH Chip address 2AAAh,5555h)
  2100h        --> MBC-like RomBank LSBs
  3000h        --> MBC-like RomBank MSB or so
  xxxxh        --> MBC-like other stuff, like RAM bank etc.
  4000h..7FFFh --> FLASH Chip address 000000h..003FFFh+RomBank*4000h
Observe that some MBC-chips do also have write-able registers at 4000h..7FFFh, if the Nintendo Power cart is
supporting that kind of MBC mapping too, then it might conflict with FLASH writes via 4000h..7FFFh, unless
there's some way to switch the 4000h..7FFFh write-behaviour via some command/register at 0120h..013Fh.
If that's right, then you would need to write to 2100h and 3000h only when accessing the memory window at 4000h..7FFFh. The code that you've posted isn't doing that at all - so I guess you could completely remove the 2100h/3000h stuff from it, right?

The hidden erase function consists of two (almost) identical steps: The first with [5555h]=40h, the second with [5555h]=04h. What's that about? One erasing the first 80h bytes of the 100h-byte hidden data, and the other one erasing the remaining 80h bytes?

The hidden write function is using not less than three writes to 5555h-2AAAh-5555h, that's a bit more than usually. Looking closer at it, the first write with data "AA-55-A0-FF-FF" isn't a hidden command at all! It's just the standard write command (writing two FFh bytes to addresss 0000h, which means it's just a dummy write; since writing FFh won't change any bits from "1-to-0").
The next two commands, with data "AA-55-60" and "AA-55-E0" seem to be invoking the actual hidden write.
What happens if you remove the "AA-55-A0-FF-FF" part? It looks like a useless dummy thing... unless it's some secret prefix needed to unlock the following secret hidden write command.

For both the dummy command (writing one dummy byte to 0000h), and the hidden write command (writing 80h bytes to 0000h), your code is having that "write-last-byte-twice" effect in it. That's unexpected because, as far as I remember, BennVenn said that the gameboy cart wouldn't need that effect (and wouldn't work at all when trying to do so).
If you are writing normal flash sectors (not the hidden sectors), are you getting that working with and/or without "last-byte-twice"?
EDIT: Sorry, I've misunderstood what you were saying. The extra write to last address is needed, but the data must be other than F0h, so, for the gameboy version, it would be "write-a-value-other-than-F0h-to-last-address" instead "write-last-byte-twice".

Oh, and about the actual mapping: Currently you can only map the menu, or alternately map a selected game (which works only for memory regions that ARE defined in the hidden sector).
But there's no way to map the WHOLE memory yet (like the HIROM:ALL feature in SNES version)? Having such a feature could be useful in several cases.
Last edited by nocash on Sat Jan 23, 2016 4:24 am, edited 1 time in total.
skaman
Posts: 87
Joined: Fri Oct 24, 2014 1:56 am

Re: How to program a NINTENDO POWER Cartridge ?

Post by skaman »

nocash wrote:Cool, congrats on getting that working!

I am trying to figure out the memory map of the gameboy cart - just guessing - but it seems to look like so:

Code: Select all

For Reading:
  0000h..3FFFh --> FLASH Chip address 000000h..003FFFh
  4000h..7FFFh --> FLASH Chip address 000000h..003FFFh+RomBank*4000h
For Writing:
  0000h..00FFh --> FLASH Chip address 000000h..0000FFh
  0120h..013Fh --> Special Nintendo Power registers (among others used to access FLASH Chip address 2AAAh,5555h)
  2100h        --> MBC-like RomBank LSBs
  3000h        --> MBC-like RomBank MSB or so
  xxxxh        --> MBC-like other stuff, like RAM bank etc.
  4000h..7FFFh --> FLASH Chip address 000000h..003FFFh+RomBank*4000h
Observe that some MBC-chips do also have write-able registers at 4000h..7FFFh, if the Nintendo Power cart is
supporting that kind of MBC mapping too, then it might conflict with FLASH writes via 4000h..7FFFh, unless
there's some way to switch the 4000h..7FFFh write-behaviour via some command/register at 0120h..013Fh.
If that's right, then you would need to write to 2100h and 3000h only when accessing the memory window at 4000h..7FFFh. The code that you've posted isn't doing that at all - so I guess you could completely remove the 2100h/3000h stuff from it, right?
I removed the 2100/3000 stuff and the code still works.
The hidden erase function consists of two (almost) identical steps: The first with [5555h]=40h, the second with [5555h]=04h. What's that about? One erasing the first 80h bytes of the 100h-byte hidden data, and the other one erasing the remaining 80h bytes?
I thought that too but the functions appear to do different things. If I use only 0x40, then the contents of the register becomes the result of merging the two register files (original and new) like using a bitwise AND. If I use only 0x04, then the register get erased to FFs but only 0x80-0xFF is written the first time. I have to add another 0x04, then 0x0-0x7F is written. It looks like the 0x40 function can be replaced by a 2nd 0x04 function.
The hidden write function is using not less than three writes to 5555h-2AAAh-5555h, that's a bit more than usually. Looking closer at it, the first write with data "AA-55-A0-FF-FF" isn't a hidden command at all! It's just the standard write command (writing two FFh bytes to addresss 0000h, which means it's just a dummy write; since writing FFh won't change any bits from "1-to-0").
The next two commands, with data "AA-55-60" and "AA-55-E0" seem to be invoking the actual hidden write.
What happens if you remove the "AA-55-A0-FF-FF" part? It looks like a useless dummy thing... unless it's some secret prefix needed to unlock the following secret hidden write command.
I removed the 0xA0 flash command sequence and the code still works.
For both the dummy command (writing one dummy byte to 0000h), and the hidden write command (writing 80h bytes to 0000h), your code is having that "write-last-byte-twice" effect in it. That's unexpected because, as far as I remember, BennVenn said that the gameboy cart wouldn't need that effect (and wouldn't work at all when trying to do so).
If you are writing normal flash sectors (not the hidden sectors), are you getting that working with and/or without "last-byte-twice"?
I haven't written to the regular flash yet. I'm still working on getting the reader code working for normal carts. I've got a good base for the normal mappers so I'll build off it to work with the NP cart.
Oh, and about the actual mapping: Currently you can only map the menu, or alternately map a selected game (which works only for memory regions that ARE defined in the hidden sector).
But there's no way to map the WHOLE memory yet (like the HIROM:ALL feature in SNES version)? Having such a feature could be useful in several cases.
The program appears to use 0xCF (1st command sequence in the original list) so that might address the entire flash. I haven't tested it yet.

More testing to do.
BennVenn
Posts: 107
Joined: Sat Mar 29, 2014 10:01 pm
Location: Australia
Contact:

Re: How to program a NINTENDO POWER Cartridge ?

Post by BennVenn »

Great work!

Just something to keep in mind when re-flashing the flash. Unlock sector 0 first.

main_JPN_F1(0x5555,0xAA)
main_JPN_F1(0x2AAA,0x55)
main_JPN_F1(0x5555,0x60)
main_JPN_F1(0x5555,0xAA)
main_JPN_F1(0x2AAA,0x55)
main_JPN_F1(0x0000,0x40)
nocash
Posts: 1405
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: How to program a NINTENDO POWER Cartridge ?

Post by nocash »

skaman wrote:If I use only 0x40, then the contents of the register becomes the result of merging the two register files (original and new) like using a bitwise AND.
Okay, the bitwise ANDing would be the normal case when erase didn't occur.
On a normal flash chip, that six-byte sequence (AA-55-60 plus AA-55-40) would be the sector unprotect command. The sixth byte (40h) should be normally written to the desired sector address (not to AAAAh) though, but I guess the chip might accept any address in range 0..1FFFFh for unprotecting the first 128Kbyte-page.
Maybe the command is just doing the same thing on the chip in the gameboy cart, too. Maybe that command (or some other command) does also allow to protect/unprotect the hidden sector. But either way, if you have the /WP pin switched high (did you?) then the whole chip should be always write-able (going by the datasheet, the protect flags are used only when /WP=LOW).
skaman wrote:If I use only 0x04, then the register get erased to FFs but only 0x80-0xFF is written the first time. I have to add another 0x04, then 0x0-0x7F is written. It looks like the 0x40 function can be replaced by a 2nd 0x04 function.
Odd. The first write to 00h..7Fh is ignored, and only the second write to 80h..FFh is taken?
Sounds a bit as if the erase wasn't finished yet, so the chip refused the first write command when erase was still busy.

How are you handling the Write/Erase busy stuff? Ie. those "Loop (0x100 times) ... until 0x0000 reads 0x80" parts?
Correct should be reading until Bit7 of the returned data becomes 1=Ready. You may also add a timeout so that the program won't hang if something gets wrong, but make sure that the timeout is big enough (like one second, or at least several milliseconds). Doing the timeout after looping "0x100 times" sounds a bit short (depends on how much time your program needs to execute one of those loop cycles, of course).

Btw. also in the Write/Erase busy stuff: Is that "Write 0x03" really needed for anything? Normally it should be enough to READ the status byte several times (until it indicates ready), but without needing to write anything during (or after) that period.
BennVenn wrote:Just something to keep in mind when re-flashing the flash. Unlock sector 0 first.
Yes, just mentioned that sector protect stuff too, while you've sent your post. I think it's needed only when /WP=LOW though.
nocash
Posts: 1405
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: How to program a NINTENDO POWER Cartridge ?

Post by nocash »

skaman wrote:The standard flash command 0x90 can retrieve the flash ID C2/89
BennVenn wrote:ID's are $C2 and $83.
That are different chips with different IDs?
skaman wrote:I hooked up a logic analyzer to my GB cart interface that sits between the GB cart and the GB XChanger.
If you have spare time to do more soldering... How about wiring it up directly to the GB cart - and then logging what happens when running the cart on a real gameboy?
Theoretically it should read the hidden data on power-up, and also after selecting a game in the menu. Going by mootan's code, that would be done by sending AA-55-77 twice, but as far as I understand, mootan has found that command by trial-and-error - which is great - but it would be also interesting if Nintendo is really using the exact same sequence.
skaman
Posts: 87
Joined: Fri Oct 24, 2014 1:56 am

Re: How to program a NINTENDO POWER Cartridge ?

Post by skaman »

All of the carts that I have on hand report C2/89 which matches what Nitro found.

I did some logging with the cart interface sitting between the cart and Gameboy. I'll look and see what is there.
skaman
Posts: 87
Joined: Fri Oct 24, 2014 1:56 am

Re: How to program a NINTENDO POWER Cartridge ?

Post by skaman »

Here's what I've got so far on the GB NP mapping:

Code: Select all

GB Mapping Info
Entries start at 0x0 divided into 3 Byte segments

For example, let's look at the start of the mapping for a multi-game cart:  
A8 00 00 71 04 00 48 94 04 separates into
A8 00 00 MENU
71 04 00 GAME 1
48 94 04 GAME 2

Byte 00 of each entry contains the MBC Type, ROM Size, and SRAM Size (start).  
SRAM Size is 3 bits across Byte 00 and Byte 01.
     MBC SZE SRAM 
A8 = 101 010 00  0 MBC5, size 2 = 128KB
71 = 011 100 01  0 MBC3, size 4 = 512KB, SRAM 8KB
48 = 010 010 00  1 MBC2, size 2 = 128KB, SRAM MBC2

Byte 00: 1st 3 Bits = MBC Type
        000 = MBC0
        001 = MBC1
        010 = MBC2
        011 = MBC3
        101 = MBC5
 
Byte 00: 2nd 3 Bits = ROM Size (minimum size is 128KB due to block size)
        010 = Size 2 - 128KB
        011 = Size 3 - 256KB
        100 = Size 4 - 512KB
        101 = Size 5 - 1MB

Byte 00: Last 2 Bits (bit1..bit0) + Byte 01: 1st Bit (bit7) = SRAM Size
        00 0 = NONE
        00 1 = SRAM MBC2
        01 0 = SRAM 8KB
        01 1 = SRAM 32KB

Byte 01 contains the SRAM Size (end) and ROM Block in the Flash.
ROM Blocks are 128KB (8 total)
Byte 01: Last 7 Bits (bit6..bit0) = ROM Block
			00 = ROM Block 0  start offset 0KB
			04 = ROM Block 1  start offset 128KB
			08 = ROM Block 2  start offset 256KB
			0C = ROM Block 3  start offset 384KB
			10 = ROM Block 4  start offset 512KB
			14 = ROM Block 5  start offset 640KB
			18 = ROM Block 6  start offset 768KB
			1C = ROM Block 7  start offset 896KB

Byte 02 contains the RAM Block in the SRAM.
RAM Blocks are 8KB (16 total)
Byte 02: RAM Block:
			00 = RAM Block 0  start offset 0KB
			04 = RAM Block 1  start offset 8KB
			08 = RAM Block 2  start offset 16KB
			0C = RAM Block 3  start offset 24KB			
			and so on until RAM Block 15.

Going back to our example cart:
A8 00 00 MENU:  MBC5, size 2 = 128KB, ROM Block 0, RAM Block 0 (Ignored since SRAM is 000)
71 04 00 GAME 1:  MBC3, size 4 = 512KB, SRAM 8KB, ROM Block 1, RAM Block 0
48 94 04 GAME 2:  MBC2, size 2 = 128KB, SRAM MBC2, ROM Block 5, RAM Block 1
EDIT: Fixed the SRAM Size. Uses 3 bits spread across Byte 00 and 01.
Last edited by skaman on Sun Jan 24, 2016 6:20 am, edited 5 times in total.
nocash
Posts: 1405
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: How to program a NINTENDO POWER Cartridge ?

Post by nocash »

Looks good! And looks as if you've already found out everything. Or do you still have some games that have non-zero bits in unexpected locations (like bit5-6 of byte1, for example)?

One thing that is missing is the RAM size. Common would be None, 2K, 8K, 32K (maybe also 128K in some newer titles), maybe that's somehow encoded in the 2bit "SRAM Flag" entry... do you have games with different size in your collection? The size can be seen in the gameboy cart ROM header (entry 0149h).

MBC1, MBC2, MBC3 and MBC5 should cover the most common mappers, do you have NP games of all those types in your collection, for confirming that they are all supported?

There are few more mappers like Huc1 or MBC4, but they are rarely used, so Nintendo might have considered as not worth being implemented in NP cartridges.

What is MBC0? Does that mean small games with only 32Kbyte ROM (=without any ROM bank switching)? Don't know if Nintendo sold any such small games as NP titles - or did they sell only newer/bigger titles? Oh, and did they sold both classic monochrome games and gameboy color games, or only color ones?
skaman
Posts: 87
Joined: Fri Oct 24, 2014 1:56 am

Re: How to program a NINTENDO POWER Cartridge ?

Post by skaman »

nocash wrote:Looks good! And looks as if you've already found out everything. Or do you still have some games that have non-zero bits in unexpected locations (like bit5-6 of byte1, for example)?

One thing that is missing is the RAM size. Common would be None, 2K, 8K, 32K (maybe also 128K in some newer titles), maybe that's somehow encoded in the 2bit "SRAM Flag" entry... do you have games with different size in your collection? The size can be seen in the gameboy cart ROM header (entry 0149h).

MBC1, MBC2, MBC3 and MBC5 should cover the most common mappers, do you have NP games of all those types in your collection, for confirming that they are all supported?

There are few more mappers like Huc1 or MBC4, but they are rarely used, so Nintendo might have considered as not worth being implemented in NP cartridges.

What is MBC0? Does that mean small games with only 32Kbyte ROM (=without any ROM bank switching)? Don't know if Nintendo sold any such small games as NP titles - or did they sell only newer/bigger titles? Oh, and did they sold both classic monochrome games and gameboy color games, or only color ones?
The SRAM Flag could be the RAM Size. I only have games that use 8KB saves. So those 2 bits could be used to encode something larger. The minimum RAM size would be 8KB (like the minimum ROM size is 128KB) due to the block size.

Code: Select all

Byte 0: Last 2 Bits = RAM Size
        00 = NONE
        01 = SRAM 8KB
//      10 = SRAM ? (No Example)
//      11 = SRAM ? (No Example)
I have carts with MBC 0, 1, 2, 3 and 5. Entries for MBC 4, 6, and 7 are possible but I'm not sure if they're actually supported. I'll have to give those mappers a try when I find some time.

Yes, MBC0 = No Mapper. Sorry, went with the MBC# theme when typing it out. In my multi-game carts, I have NO_MBC games: Alleyway, Tennis and Yakuman.
skaman
Posts: 87
Joined: Fri Oct 24, 2014 1:56 am

Re: How to program a NINTENDO POWER Cartridge ?

Post by skaman »

nocash wrote:Theoretically it should read the hidden data on power-up, and also after selecting a game in the menu. Going by mootan's code, that would be done by sending AA-55-77 twice, but as far as I understand, mootan has found that command by trial-and-error - which is great - but it would be also interesting if Nintendo is really using the exact same sequence.
I looked at the startup sequence and also when the cart switches between games.

The cart does use the AA-55-77 sequence.

Code: Select all

STARTUP:  MENU MAPPING: A8 00 00
0x8000, 0xFF (RD LOW) (RESET LOW)
0x8000, 0xF0 (RD LOW) (RESET LOW)
0x8000, 0xAA (RD LOW) (RESET LOW)
0x8000, 0x55 (RD LOW) (RESET LOW)
0x8000, 0x77 (RD LOW) (RESET LOW)
0x8000, 0xAA (RD LOW) (RESET LOW)
0x8000, 0x55 (RD LOW) (RESET LOW)
0x8000, 0x77 (RD LOW) (RESET LOW)
0x8000, 0xFF (RD LOW) (RESET LOW)
0x8000, 0x00 (RD LOW) (RESET LOW)
0x8000, 0xA8 (RD LOW) (RESET LOW)  (MAPPING BYTE 00)
0x8000, 0x00 (RD LOW) (RESET LOW)  (MAPPING BYTE 01 & 02 - DURATION IS 2X)
0x8000, 0xF0 (RD LOW) (RESET LOW)
0x8000, 0xFF (RD LOW) (RESET LOW)

SWITCHING TO GAME 1 MAPPING:  31 04 00
0x8000, 0xFF (RD LOW) (RESET LOW)
0x8000, 0xF0 (RD LOW) (RESET LOW)
0x8000, 0xAA (RD LOW) (RESET LOW)
0x8000, 0x55 (RD LOW) (RESET LOW)
0x8000, 0x77 (RD LOW) (RESET LOW)
0x8000, 0xAA (RD LOW) (RESET LOW)
0x8000, 0x55 (RD LOW) (RESET LOW)
0x8000, 0x77 (RD LOW) (RESET LOW)
0x8000, 0xFF (RD LOW) (RESET LOW)
0x8000, 0x00 (RD LOW) (RESET LOW)
0x8000, 0x31 (RD LOW) (RESET LOW)  (MAPPING BYTE 00)
0x8000, 0x04 (RD LOW) (RESET LOW)  (MAPPING BYTE 01)
0x8000, 0x00 (RD LOW) (RESET LOW)  (MAPPING BYTE 02)
0x8000, 0xF0 (RD LOW) (RESET LOW)
RESET GOES HIGH
0x8000, 0xFF (RD LOW)

SWITCHING TO GAME 2 MAPPING:  2D 14 04
0x8000, 0xFF (RD LOW) (RESET LOW)
0x8000, 0xF0 (RD LOW) (RESET LOW)
0x8000, 0xAA (RD LOW) (RESET LOW)
0x8000, 0x55 (RD LOW) (RESET LOW)
0x8000, 0x77 (RD LOW) (RESET LOW)
0x8000, 0xAA (RD LOW) (RESET LOW)
0x8000, 0x55 (RD LOW) (RESET LOW)
0x8000, 0x77 (RD LOW) (RESET LOW)
0x8000, 0xFF (RD LOW) (RESET LOW)
0x8000, 0x00 (RD LOW) (RESET LOW)
0x8000, 0x2D (RD LOW) (RESET LOW)  (MAPPING BYTE 00)
0x8000, 0x14 (RD LOW) (RESET LOW)  (MAPPING BYTE 01)
0x8000, 0x04 (RD LOW) (RESET LOW)  (MAPPING BYTE 02)
0x8000, 0xF0 (RD LOW) (RESET LOW)
RESET GOES HIGH
0x8000, 0xFF (RD LOW)
Post Reply