Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Accessing to the save/load game data
#1
Hi everyone,

I'm triying to develop a game for ngpc with the framework 4 and at the moment works fine. I think that it would be good save/load data of the game for give it the possibility of save data and continue in other moment in the same point, somethink like any Memory Card.

I', not find methods in the framework to store or retrive data from this memory address and Chris say to me "maybe Flavor or Loic know something about that"

So, anyone can hel me?

Regards,
Reply
#2
(11-14-2018, 11:38 PM)KeiDash Wrote: Hi everyone,

I'm triying to develop a game for ngpc with the framework 4 and at the moment works fine. I think that it would be good save/load data of the game for give it the possibility of save data and continue in other moment in the same point, somethink like any Memory Card.

I', not find methods in the framework to store or retrive data from this memory address and Chris say to me "maybe Flavor or Loic know something about that"

So, anyone can hel me?

Regards,

Hi K',
The reading part is the easiest, as it's a direct acces to memory offset where the data are saved.
The writting part is a little trickiest.
If you want to be able to run your program on bung or flashmasta, you need to consider that your game will be 16/32mbits.

The process of data saving requires the use of bios call.
You first need to call an erase function. This function is based on the memory bloc number you want to erase.
The next part is to call the bios write function.

As I've never used C on Neogeo Pocket, I can only give you the assembly way of doing this operation.

You can find some informations in this thread : https://forum.freeplaytech.com/showthrea...88#pid5388

Bascally,
here's the way to clear a bloc :

Code:
using this definitions :
; rWDCR            equ     6fh      ; Watch Dog Control Register
; WD_CLR            equ     4eh     ;  Value required to be written to rWDT
; VECT_FLASHERS    equ     8        ; Flash memory - erase specified blocks
; VECT_FLASHWRITE    equ     6        ; Flash memory - data write
    
    
ld    ra3,0                    : load 0 to ra3 register
ld    rb3,0x21                : load rb3 with the required bloc number (0x21 here)
ld    rw3, VECT_FLASHERS    : load rw3 with the bios bloc erase function number
ld    (rWDCR),WD_CLR        : required so the unit won't shut down
swi    1                    : call bios function

for the wirting part :

Code:
ld    ra3,0                            ; load ra3 register with 0
ld    rbc3,1                        ; 1x256 bytes

ld    xhl3, <ram_writing data address>    ; data to write
ld    xde3, 1FA000h                    ; SAVEOFFSET
ld    rw3,VECT_FLASHWRITE            ; load rw3 with the bios write function number
ld    (rWDCR),WD_CLR
swi    1


Load_Game:

You only need to read data starting from 0200000h+SAVEOFFSET (ie 3FA000h)
Code:
;To read data : acces memory at 0200000h+SAVEOFFSET
ld     bc, 01
ld    xhl, 3FA000h            ; offset where the data are stored
ld    xde, <ram_destination>    ;
ldirw    (xde+),(xhl+)            ;


Loïc
Reply
#3
I don't know this for sure, but I think that NGCollector may have save/reload in the source code.
See http://sebastianmihai.com/main.php?t=63
Card Fighters' Clash 2 English Translation ( http://cfc2english.blogspot.com/ )
Neo Geo Pocket Flash Cart and Linker Project ( http://www.flashmasta.com/ )
Avatar art thanks to Trev-Mun ( http://trevmun.deviantart.com/ )
Reply
#4
OMG assembler...I don't know it.

Well, I'm going to try to understand it and if I got it, implement a save/load data. In other case, I try to find another way to do it.

Many thanks Loic!
Reply
#5
(11-15-2018, 04:26 AM)KeiDash Wrote: OMG assembler...I don't know it.

Well, I'm going to try to understand it and if I got it, implement a save/load data. In other case, I try to find another way to do it.

Many thanks Loic!

I did take a quick look at the C sources mentioned by Ed...
So... it's inline assembly ^_^;

What you need is the SAVEOFFSET and the BLOCK_NB. You can find them in my previous post if you want to be able to test your code on flashmasta or bung.
Otherwise, you can use the data in my previous forum link to determine them, depending on the size of your game (from 4mbits to 32mbits).


Code:
void Flash(void *data) {
    __ASM("SAVEOFFSET    EQU    0x1e0000");                     // you need to set this offset depending on your game size
    __ASM("BLOCK_NB        EQU    30");                                // this offset should give you the bloc number (see link in previous post)

    __ASM("VECT_FLASHWRITE    EQU    6");
    __ASM("VECT_FLASHERS    EQU    8");
    __ASM("rWDCR        EQU    0x6f");
    __ASM("WD_CLR        EQU    0x4e");

    // Erase block first (mandatory) : 64kb for only 256 bytes
    __ASM("    ld    ra3,0");
    __ASM("    ld    rb3,BLOCK_NB");
    __ASM("    ld    rw3,VECT_FLASHERS");
    __ASM("    ld    (rWDCR),WD_CLR");
    __ASM("    swi    1");

    // Then write data
    __ASM("    ld    ra3,0");
    __ASM("    ld    rbc3,1");    // 256 bytes
    __ASM("    ld    xhl,(xsp+4)");
    __ASM("    ld    xhl3,xhl");
    __ASM("    ld    xde3,SAVEOFFSET");
    __ASM("    ld    rw3,VECT_FLASHWRITE");
    __ASM("    ld    (rWDCR),WD_CLR");
    __ASM("    swi    1");

    __ASM("    ld    (rWDCR),WD_CLR");
}

void GetSavedData(void *data) {                                  // should be rather easy, just a simple data copy from flash to ram
    u32 *ptr = (u32*)(0x200000+0x1e0000);
    u32 *ptrData = (u32*)data;
    u8 i;
    if (*ptr == MAGIC_NB) // Data saved
    {
        for (i=0;i<64;i++)
            ptrData[i] = ptr[i];
    }
    else // No data
    {
        ptrData[0] = MAGIC_NB;
        for (i=1;i<64;i++)
            ptrData[i] = 0;
    }
}
Edit : I think those C sources come from SOD/Thor's "Another day in hell" shooter (http://thor.pdroms.de/#ngpcdev)
Reply
#6
(11-15-2018, 03:56 AM)Flavor Wrote: I don't know this for sure, but I think that NGCollector may have save/reload in the source code.
See http://sebastianmihai.com/main.php?t=63

I check it and it doesn't has save/load on memory (or I can't see it).

Loic, respect at your post, I'll have a bit of time this weekend to try it. I have a few hours to read, understand and try it. I'll put someething here if I got it or have some problems.

Thank you very much to both of you.
Reply
#7
I'm reading the code of Thor in the game "Another Day in hell" and Thor was a file for this called flash.c. I understand that this file overwrite the methods flasha and GetSavedData right?

I think that this can help me but I have a big doubt. I'm never learn assembly and I don't understand any values or vars, etc.

Loic, you say me that I only want to know the SAVEOFFSET and the BLOCK_NB. The saveoffset it's an array? How can I determinate the size in my case and how to set the value?

This is the code of Thor to do it.

Code:
#include "ngpc.h"

u8 data[256];

#define    MAGIC_NB    0xcafebabe    // java rules !

void flash(void *data)
{
    __ASM("SAVEOFFSET    EQU    0x1e0000");

    __ASM("BLOCK_NB        EQU    30");
    __ASM("VECT_FLASHWRITE    EQU    6");
    __ASM("VECT_FLASHERS    EQU    8");
    __ASM("rWDCR        EQU    0x6f");
    __ASM("WD_CLR        EQU    0x4e");

    // Erase block first (mandatory) : 64kb for only 256 bytes
    __ASM("    ld    ra3,0");
    __ASM("    ld    rb3,BLOCK_NB");
    __ASM("    ld    rw3,VECT_FLASHERS");
    __ASM("    ld    (rWDCR),WD_CLR");
    __ASM("    swi    1");

    // Then write data
    __ASM("    ld    ra3,0");
    __ASM("    ld    rbc3,1");    // 256 bytes
    __ASM("    ld    xhl,(xsp+4)");
    __ASM("    ld    xhl3,xhl");
    __ASM("    ld    xde3,SAVEOFFSET");
    __ASM("    ld    rw3,VECT_FLASHWRITE");
    __ASM("    ld    (rWDCR),WD_CLR");
    __ASM("    swi    1");

    __ASM("    ld    (rWDCR),WD_CLR");
}

void getSavedData()
{
    u32 *ptr = (u32*)(0x200000+0x1e0000);
    u32 *ptrData = (u32*)data;
    u8 i;
    if (*ptr == MAGIC_NB) // Data saved
    {
        for (i=0;i<64;i++)
            ptrData[i] = ptr[i];
    }
    else // No data
    {
        ptrData[0] = MAGIC_NB;
        for (i=1;i<64;i++)
            ptrData[i] = 0;
    }
}
Reply
#8
Code:
__ASM("SAVEOFFSET    EQU    0x1e0000");

The SAVEOFFSET is where the save data will begin.  

You might want to look at a couple PDF documents named SysCall.pdf and FlashMem.pdf  
https://www.google.com/search?q=syscall....ashMem.zip

In FlashMem.pdf, you can see the block layout of the different chip/cart sizes.  Look at the table called "16Mbit Flash Memory Card."

Now, actually, in the code pasted, it's using the [font=Monaco, Consolas, Courier, monospace]block that starts at 0x1e0000 for savegame.  This would not be typical.  You would usually use blocks numbered 31, 32, and 33 for savegame stuff.  That's not necessary, but it's more typical.  [/font]

[font=Monaco, Consolas, Courier, monospace]Keep in mind that flash memory is a bit weird to work with.  For the sake of simplicity, let's just talk about the chips on NGPC carts.  You can do 2 things with them.  You can turn all the bits in a [font=Monaco, Consolas, Courier, monospace]block to 1 or you can turn a single bit from 1 to 0.  This means that you can write anything you want to a block, but you have to erase it first.  This can be tricky.  [/font][/font]

[font=Monaco, Consolas, Courier, monospace]Any time you want to write your savegame data, you COULD erase the whole [font=Monaco, Consolas, Courier, monospace]block and write your data.  That's slow and it can actually wear out the flash chip faster.  So, people come up with novel approaches to that will write multiple versions of the savegame data at different places and then have some sort of method to determine which is the latest version.  Then, if you ever fill it up, you erase the entire block and start over.[/font][/font]

[font=Monaco, Consolas, Courier, monospace]BUT, notice that Thor's code erases the block and writes the data.  This will work.  It's probably the easiest way, but it's not the "best" way to do it.[/font]

[font=Monaco, Consolas, Courier, monospace]I hope that makes a little sense.  [/font]

[font=Monaco, Consolas, Courier, monospace]If I were you, I would probably pick [font=Monaco, Consolas, Courier, monospace]block 32 and then change to[/font][/font]

Code:
__ASM("SAVEOFFSET    EQU    0x1f8000");
__ASM("BLOCK_NB        EQU    32");

[font=Monaco, Consolas, Courier, monospace]These 2 items much match up based on the table I mentioned.  If you used block 32, then [font=Monaco, Consolas, Courier, monospace]SAVEOFFSET must be between 0x1f8000 and 0x1f9fff (from the table).[/font][/font]

[font=Monaco, Consolas, Courier, monospace][font=Monaco, Consolas, Courier, monospace]Also look at SysCall.pdf.  In particular, look at VECT_FLASHWRITE and VECT_FLASHERS.  These are what Thor's code is calling.  The ASM is just setting up the parameters to call those SysCall functions.[/font][/font]

Also, notice that Loïc's ASM code is setting up writing to block "0x21" which is block 33. Then he uses 0x1fa000 as his SAVEOFFSET.
Card Fighters' Clash 2 English Translation ( http://cfc2english.blogspot.com/ )
Neo Geo Pocket Flash Cart and Linker Project ( http://www.flashmasta.com/ )
Avatar art thanks to Trev-Mun ( http://trevmun.deviantart.com/ )
Reply
#9
The offset and bloc number can be arbitrary set.

The easiest way is to uses the values I gave you in the fist post.
offset           : 0x1FA000
bloc number : 0x21

with these values, the data will be stored at 0x3FA000

Using this parameters, your data will be saved if you play from flashmasta card.

Technically, the NeoGeo Pocket see the "memory" as an array, starting from 0x000000 to 0x5FFFFF (on 32Mbit games like Metal Slug 2nd mission)
the memory part (or array range) from 0x000000 to 0x1FFFFF is used for storing displayed tiles, game RAM, color palettes, bios and other stuff.

the cartridge itself is logically subdivided in blocs. This layout depend on the cartridge size.

To write data on the cartridge, you first need to clear the bloc receiving your data (in this case, clearing 2000 bytes).
One this step is completed, you can write your data. I guess that the writing function only turns 0 to 1 and the erase function turns everything to 0.

I think that in the C code, you call flash(array to save)
the address of this array is then read by : __ASM("ld xhl, (xsp+4)" (xsp being the stack pointer. C language transmit functions args using the stack)




Better take a look at gears of fate sources, where the flash(data) is used.

Loïc
Reply
#10
(11-17-2018, 02:07 AM)Flavor Wrote: ...
[font=Monaco, Consolas, Courier, monospace]BUT, notice that Thor's code erases the block and writes the data.  This will work.  It's probably the easiest way, but it's not the "best" way to do it.[/font]
...

Ed, is it possible on neogeo pocket to change only the needed bits ?

All the commercial games I've disassembled uses clear/write process.

Loïc
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)