Re: [hatari-devel] Hatari state save/restore for Falcon emulation

[ Thread Index | Date Index | More lists.tuxfamily.org/hatari-devel Archives ]


Le 22/09/2014 23:49, Eero Tamminen a écrit :

And if the version is same, but content turns out to be incompatible
(e.g. wrong lenght) after loading, should emulation be able to
revert the state change?

(Reverting could be done by writing current state to a temporary
file before trying to restore user given state file.)

If you consider that each component is saved with a structure that contains :
 - a component ID
 - a version ID
 - size of the structure in bytes
 - data for this component

Then you can easily walk through the savestate, parse only the component where the ID is recognized and adapt the parsing depending on the version ID of the saved component.

This requires that you can't have same version ID for a component if the data has a different meaning between 2 Hatari versions, so the risk of loading incompatible data is lowered (it could still happen if savestate gets corrupted)

The size of the structure in bytes has 2 meaning :

- if you encounter a block with an unknown component ID, then you can skip it by reading as many bytes as in "size of the structure", and you will point to the next block to parse (so for example some winuae's specific component (MMU for example) could be ignored when trying to load a snapshot made with Hatari "new winuae core" into Hataro "old uae core"

- if you encounter a known block, then you can check that the size matches the expected size for given version of the component (for example, you expect the YM2149 part version 1.8.0 to be 60 bytes,else there's an error in the saved component you're tryring to restore).



This way, we could also keep previous snapshots and use them with more
recent version of Hatari, which can be useful if you use snapshot to
save some games' progress (this is something that is possible with
WinUAE or Steem since years for example, and I think it's a good
feature).

What do you think ?

Sounds good.  It would require either saving all of them to
separate files (instead of filename, user could select state save
directory), or completely rewriting how state saving is currently
done in Hatari.


I think we could save everything to the same file as we do today, then compressing the result.

The components' version could be similar to the Hatari's version. So we would start with "1.8.0" for example. Then when Hatari 1.8.1 is released, all component that were not modified would keep their 1.8.0 version, only updated component would have a version's change to indicate a difference (eg a new fdc.c component could have version 1.8.1)

Now what would be good is that "fdc 1.8.1" be able to load an older snapshot made with "fdc 1.8.0", but this can become quite hard to do the transition between this old state and the new one, as we're only dealing with bytes, sometimes a component is just a whole structure written to the savestate, and nothing more, with no indication of what is in the structure. This means for example fdc.c 1.8.1 would need to know how to parse 1.8.1, but also all previous state versions to be able to add the missing default values.

In the end, to achieve this, I wonder if a savestate file should not be stored as text and not as byte, this way you can easily store each data as a "key=value" pair. This way, it's easier when loading a savestate to look for key "videomode" for example. If it's found, you use the value, else you use a default value.

Using "key=value" pairs make sense only for structures used to emulate each component (video, fdc, sound, acia, cpu, ...) but to save the content of the RAM for example, we would still store it as byte, not as text.

So, code wise we could have sthg like :

structure component {
 int component_id,
 char version[8],
 int size,
 void *data
}

then data would point to another structure made of several "key" = "value" with a type (indicating if value

structure {
  int size,	/* size of this structure */
  char *key,	/* '\0' terminated */
  void *value,	/* as many bytes as "size - strlen( key ) */
}

Then we would have an API such as MemorySnapShot_Store to save each "key=value" (eg State_Store ( "ram" , pRamStart , RamSize ) )

We would also need some functions to start and close a components block.

In the end, this looks a lot like a config file, where we have sections between [], then values for each section are stored with key=value. Difference with a config file is that this would not necessarily be stored as plain text (but plain text could be an option, this way a memory file could even be loaded in a text editor)

Well, that's just some random thoughts I had since some times about the savestate format, feel free to add your own idea.


Nicolas









Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/