Portable Game Console Project - Storage System Implemented!

May 27, 2018, 6:52 a.m. Behind the Scenes Electronics Portable Game Console Programming WIP

Hey guys! The storage system of my portable game console is implemented!

Storage System Design

Why is the game save content located right inside the ROM?

It seems to be dumb to save the save content right inside the ROM file. I don't really have a choice because of the limitation of the FAT library. :(

My original idea was to have two files. One is the ROM file. Another is the save file. The save file is dynamically created by the game by using the API Calls.

However, when I tried to create the file by using the function pf_write() of the FAT library, it didn't work. Then I looked into the documentation and found out this restriction:

Alright. Then I had come up with three ideas. They're:

Using another FAT library takes a lot of work. Pre-creating a save file on the SD card would bring quite a bit of nuisance to the player because the player would have to manually paste the save file to the SD card in addition of the ROM file. So it's apparently to me that storing the save file content right inside the ROM would be the solution to go.

Resource Alignment

Since the restriction of the file-writing function is "Cannot create file. Only existing file can be written", everything should be working after saving the content right inside the ROM, right?

It turned out that I was mistaken. When I tried writing something on the SD card, the offset of the content being written was wrong! And some of the content were corrupted by zeros. Why?

After reading the documentation again, I've found out why. The library has a function for reading from file, and another function for writing to file. The function for reading works with any file offset. However, the function for writing only works properly if the seek offset of the file is aligned to 512 bytes. Otherwise, the offset would be rounded down to the closest 512-bytes. In addition of that, the number of bytes written are padded with zeros to 512 bytes.

The solution? Simple! Just align the offset of each resources to 512 bytes and pad them.

ROM File Format

Here's the file format of the ROM of the game console.

Offset      Size    Description
0           3       Magic number
3           1       ROM file format version
4           32      Name of the game. NULL-terminated.
36          32      Author of the game. NULL-terminated.
68          256     Game Description. NULL-terminated.
324         700     Reserved
1024+8*N    4       Resource offset in file. N is from 0~255.
1024+8*N+4  4       Resource length. N is from 0~255. Can be zero.
3072        varies  The content of the resources. Each resources are aligned to 512 bytes.

ROM-packing Python Script

The python script takes a CSV input file and generate the ROM. The CSV file looks like this:

NAME,Name of the game goes here
AUTHOR,Sadale.net
DESCRIPTION,Description of the game goes here
0,assets/game.bin
1,assets/level1.map
2,assets/level2.map
128,assets/titleScreen.graphic
254,[1024]

It's rather obvious what does the CSV do except the last line. For the resource #254, it allocates a resource that contains 1024 bytes of zero. It's useful for allocating space for save file of the game.

API Calls

It's simple. There're only three functions.

It's rather intuitive. I guess I don't need to explain it here. :P

Sample program

To demonstrate that the storage system is working, I've developed a test program. The program is capable for playing three kind of sound with configurable duty cycle. The function of the buttons are shown below:

Click here and see how does the code of the program looks like. Please notice that this isn't a complete project and it's not buildable without extif.h, which I'm not releasing until the completion of the software.

After saving the content of the file, here's how does the content of the ROM looks like:

Content of ROM showing the bytes 0x55, 0x01 and 0x01

As you can see above, the first byte 0x55 is the magic number. It's used for informing the program that the save data is valid.

The second one is the sound ID. The value of 0x01 refers to the second sound.

The third one is duty cycle. A value of 0x01 refers to 50% duty cycle.

After relaunching the program, the sound and the duty cycle will be loaded. I've tested it. The sound was played correctly after I pressed the Button A. :)

What's next?

I'll be working on the following stuffs:

That's it for now. I'll update you guys for any progress! :)


Comments