How to program a NINTENDO POWER Cartridge ?

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
nocash
Posts: 1405
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: How to program a NINTENDO POWER Cartridge ?

Post by nocash »

BennVenn wrote:Success! A big thanks to skaman!!
(must write 0x77 twice)
How did you do that exactly? And does it work stable?

I am assuming that "write 0x77" does mean a AA-55-77 sequence like this:

Code: Select all

       mov  a,0aah // mov  [far 0c0aaaah],a  ;\
       mov  a,055h // mov  [far 0c05554h],a  ; causes ALL bytes = C8h (sometimes FFh, or CAh)
       mov  a,077h // mov  [far 0c0aaaah],a  ;/
Right? That is, using SNES addressing, with the C00000h as base address for HIROM area, and with the 5555h/2AAAh values multiplied by two for the 16bit FLASH chips being used in SNES.

Whenever executing the above sequence (once, or twice, or several times), and then reading from [C0FFxxh], I am just receiving C8h bytes from the chip (occassionally with a few CAh or FFh bytes inserted on some reads).When reading from [C000xxh], I am getting C0h instead C8h. Anyways, that are just garbage or status values, not the hidden data.
Another odd thing is that, after sending the above sequence, the chip stops responding to any normal commands (eg. command AA-55-F0 doesn't return to normal FLASH data read mode anymore).

However, if I remove the whole write AA-55-77 stuff, and re-upload my test program to the SNES, then it does sometimes pop up with the hidden data - although I haven't issued the AA-55-77 stuff (nor the 38h,D0h stuff) in that situations at all.
So, it does look as if the 77h is starting to enter the hidden data mode on SNES, but it does still require whatever random bus traffic before completely reaching the hidden data read state.
I've tried to insert extra reads & writes & delays here and there, but haven't been able to reproduce that effect yet.

EDIT: Thinking about it. When I re-upload (and reboot) my test program, then MX15001 chip might automatically issue the 38h,D0h stuff (if it's doing so when receiving a /RESET from SNES side). So that might also explain where the hidden data is coming from even when NOT requesting it (ie. on the SNES, the AA-55-77 might be just causing the FLASH chip to fail to return to normal data mode after having received the 38h,D0h stuff from the MX15001).
nocash
Posts: 1405
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: How to program a NINTENDO POWER Cartridge ?

Post by nocash »

Btw, does the SNES-sytle method for reading hidden data work on gameboy, too?

On SNES, with 16bit FLASH chips, it works like this:

Code: Select all

  [0AAAAh]=AAh, [05554h]=55h, [0AAAAh]=F0h   ;FLASH read/reset command
  [00000h]=38h, [00000h]=D0h, [00000h]=71h   ;FLASH request chip info part 1
  dummy=[00004h]                             ;Read Ready-status (bit7=1=ready)
  [00000h]=72h, [00000h]=75h                 ;FLASH request chip info part 2
  read=[0FF00h+(0..FFh)]                     ;Read hidden data
  [0AAAAh]=AAh, [05554h]=55h, [0AAAAh]=F0h   ;FLASH read/reset command
For the gameboy's 8bit FLASH chips, one would probably need to divide the 0AAAAh, 05555h, and 00004h values by two, so it should work as so:

Code: Select all

  [05555h]=AAh, [02AAAh]=55h, [05555h]=F0h   ;FLASH read/reset command
  [00000h]=38h, [00000h]=D0h, [00000h]=71h   ;FLASH request chip info part 1
  dummy=[00002h]                             ;Read Ready-status (bit7=1=ready)
  [00000h]=72h, [00000h]=75h                 ;FLASH request chip info part 2
  read=[0FF00h+(0..FFh)]                     ;Read hidden data
  [05555h]=AAh, [02AAAh]=55h, [05555h]=F0h   ;FLASH read/reset command
Does that work?
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 »

I call these functions, then read 256 bytes from address 0x0000
main_JPN_F2()
main_JPN_F4()
main_JPN_F5(0x77)
main_JPN_F5(0x77)

Where F2() is the WE line enable, F4() is the WP disable. You don't need to do this on the SNES, it doesn't have the little brain inside the MBC.

F5(0x77) is a write to 0x5555<0xAA, 0x2AAA<0x55, 0x5555<0x77

And yes, after issuing that command I am unable to perform a chip erase, write byte etc without first issuing a F5(0xF0) command.

I'll try your 0x38,0xD0,0x71 sequence now and report back
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 »

And no, that command sequence enabled nothing. Also, reading from 0xFF00 on a GBcart is not valid, I bank switched to access 0xFF00 and still it was just ROM data being read out. Likewise from 0x0000. There was no status byte returned either so I don't think the flash IC recognises that command set as valid.
skaman
Posts: 88
Joined: Fri Oct 24, 2014 1:56 am

Re: How to program a NINTENDO POWER Cartridge ?

Post by skaman »

In a way, the SF magic "0x38" does show up in the GB sequence. The flash commands that allow overwriting of the GB NP Register is a sequence with 0x60 (sector unprotect/protect) and 0xE0 (sequential load to page buffer). Following the 0xE0 command, 0x3 and 0x8 are sent to 0x120. See the last section of BennVenn's post (viewtopic.php?f=12&t=11453&start=105#p158687).
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 »

In regards to the 256byte NP register write - it is unusual that the MBC allows a flash write through where every other command write to the flash needs to be done using command 0x0F... I might look into this, could make for faster cart flashing
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:In a way, the SF magic "0x38" does show up in the GB sequence.
I can't see a 38 in there. If you meant the 3 and 8 bytes, that are three different things: 3 and 8 isn't 38, the 3 and 8 are written to the mx15002 chip (not to the flash chip), and the 3 and 8 were used with the hidden-write sequence (not the hidden read sequence).
BennVenn wrote:write to 0x5555<0xAA, 0x2AAA<0x55, 0x5555<0x77
And yes, after issuing that command I am unable to perform a chip erase, write byte etc without first issuing a F5(0xF0) command.
That seems to be different on SNES. After command 70, I can't send any further commands, specifically: even F0 doesn't work anymore.
BennVenn wrote:Also, reading from 0xFF00 on a GBcart is not valid, I bank switched to access 0xFF00 and still it was just ROM data being read out. Likewise from 0x0000.
Yup, the gameboy would need some sort of bank switching for reading/writing FF00h. Maybe also for writing 0000h (assuming that writes to first 16K might be passed to the mx15002/mbc registers, instead of to flash).

I am still miles away from having an idea how the flash addressing would work on gameboy. For example, if you wanted to write a byte to flash address 8000h, then you would need writes to flash addresses 5555,2AAA,8000, which would be three different 16K banks. Assuming the gameboy address 0000-3FFF is reserved for mx/mbc I/O ports, then you would probably need to squeeze all three writes through gameboy address 4000-7FFF, each preceeded by a write to the mbc rom bank register (at 2180 or the like)?
Or wait, you mentioned something about special mx/mbc addresses for writing to 5555,2AAA, so that registers could be written at any time, regardless of the current bank for data access?

The purpose of the special write command (that with lo,hi,data parameters) isn't clear to me. If the flash chip connects directly to the gameboy databus, then it should be possible to do direct writes without needing that command... unless nintendo has totally screwed up the mx15002 chip design. Seeing the pinout of the mx15002 chip would be very interesting to figure out how the hardware works - and if there is any good (or bad) reason for using direct or indirect writes.
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 »

Flash addressing is a pain, and yes, it involves lots of writes to the flash, bank swapping, flash, bank swapping. And here lies the problem. If you write say 5555,AA, then bank swap, if the flash IC see's the bank swap write it will abort the instruction you are trying to pass to it.

This is why most flash carts use an unused pin on the edge connector to control the flash WE, so you are free to bank switch as you like and issue flash commands only to the flash IC.

Nintendo seem to have got around this by using the MBC IC to do all flash commands. The NP IC works like this:

You write the command instruction to the IC (0x0F), then load registers with the Address and data you wish to send to the flash IC, then write the execute command [0x013F]. Then the IC takes over, it waits 1 R/C constant as defined by the external RC circuit, by this stage it expects the gameboy bus to be high impedance. It then takes over the bus, sends the Address to the Flash Address bus, the data to the data bus, then triggers the flash WE pin for a few nS.

Using this technique, you can address the full 16bit ROM size, with the extra bits controlled via the bank controller.

I haven't looked into it yet, but command 0x03 and 0x08 must pass the Gameboy's WE signal straight through to the Flash IC, or else it wouldnt be able to send the NP data to the flash buffer... There must be complementary instructions to stop this.

Some older flash carts will respond to address 0x555 and 0x2AA which means no bank switching is required for the flash preamble. This is how the SharkMX cart works.

Looks like the SFC and GB flash chips are similar but very different. I'd day the NP structure would be the same though.

Looking forward to the dumps Skaman is working on!
skaman
Posts: 88
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: 88
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: 88
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: 88
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: 88
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.
Post Reply