Forums

Sega Master System / Mark III / Game Gear
SG-1000 / SC-3000 / SF-7000 / OMV
Home - Forums - Games - Scans - Maps - Cheats - Credits
Music - Videos - Development - Hacks - Translations - Homebrew

View topic - devkitSMS - develop your homebrew in C

Reply to topic Goto page Previous  1, 2, 3 ... 15, 16, 17
Author Message
  • Joined: 06 Mar 2022
  • Posts: 678
  • Location: London, UK
Reply with quote
Post Posted: Fri Apr 05, 2024 9:09 am
sverx wrote
tibone wrote
In the wiki, it says all you need to do is access the unsign char array SMS_SRAM[], so.. i did this:
[...]
But it doesnt really work [...]


I should change the wording in the wiki, it's not very clear indeed.
What I meant is that SRAM is mapped as an array of chars - of course you can cast that to whatever you need.
Here is a simple example of how to map your own struct definition onto SRAM.

Another approach could be to have your struct/data in RAM and simply memcpy() that to SRAM when you want to save.
Or you could copy every single variable from RAM to SRAM using a separate write operation but it probably would get messy pretty quickly (and still you have to cast every variable that is not an unsigned char...)

Out of interest as maybe another example for you @tibone, here's how I just did this for Land on my Base: source.

As sverx suggests, I've taken the approach here of keeping the game config in working RAM (it's passed into these functions by reference), and then at the point of loading from / saving to SRAM, which is very infrequently, I do a memcpy operation of the entire structure. Because the level code is part of the structure and because it has an inherent checksum component, it's also possible to use this to effectively detect whether SRAM is present, since valid SRAM data must have a valid checksum. If SRAM is not present, the write operations will not modify the memory in slot 2, so the save will silently fail.

(N.B. I'm not sure why I hand wrote my own memcpys here instead of using the standard library - I really should have used the library, maybe I was just playing around with stuff and forgot to come back and tidy up)


void game_save_config(game_config_t *config)
{
  SMS_enableSRAM();
  // cast:
  game_config_t *save_config = (game_config_t *)SMS_SRAM;
  // memcpy:
  for (int i = 0; i < sizeof(game_config_t); i++)
    save_config[i] = config[i];
  SMS_disableSRAM();
}

bool game_load_config(game_config_t *config)
{
  // default settings (in case no SRAM data)
  for (int i = 0; i < sizeof(config->level_code); i++)
    config->level_code[i] = DEFAULT_START_LEVEL[i];
  config->difficulty = 1;
  config->invert_controls = false;

  SMS_enableSRAM();
  // cast
  game_config_t *save_config = (game_config_t *)SMS_SRAM;
  // check if SRAM data exists and has valid checksum
  bool loaded = random_deserialize_seed(save_config->level_code);
  if (loaded)
  {
    // memcpy
    for (int i = 0; i < sizeof(game_config_t); i++)
      config[i] = save_config[i];
  }
  SMS_disableSRAM();
  return loaded;
}
  View user's profile Send private message Visit poster's website
  • Joined: 18 Jul 2020
  • Posts: 386
Reply with quote
Post Posted: Mon Apr 08, 2024 2:46 am
Hey sverx, trying to get back into the swing of things. I think the meta sprite tool was the last thing I was working on. I'm getting around to outputting c code, but I may have missed a thing or two since coming back.

Below is sample output (Tall sprite) from the Konami sprite I have done previously:
// Your MetaSpriteBaseTile offset is 317
unsigned char const konami_star_00[] = { 0, 0, 0, 8, 0, 2, METASPRITE_END };
unsigned char const konami_star_01[] = { 0, 0, 4, 8, 0, 6, METASPRITE_END };
unsigned char const konami_star_02[] = { 0, 0, 8, 8, 0, 10, METASPRITE_END };
unsigned char const konami_star_03[] = { 0, 0, 12, 8, 0, 14, METASPRITE_END };
unsigned char const *konami_star_frames[] = { konami_star_00, konami_star_01, konami_star_02, konami_star_03 };


How is the tile id offset applied? I have the tiles for the sprite loaded at tile 317. Since that value is larger than 256, I would imagine it couldn't be simply added as the sprite base tile id. The tool does have the option to define your tile id offset.

Also, having potential negative values for the x and y. Would that not trigger a compiler warning? Thanks in advance.
  View user's profile Send private message
  • Joined: 05 Sep 2013
  • Posts: 3845
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Mon Apr 08, 2024 9:07 am
Sprite tile IDs are always 8 bit, as you can only have sprites in the first OR in the second half of VRAM - so your 317 becomes 317-256.
But you can use 317 as base and ignore the warning, as you would ignore them anyway if you use negative values for x and y - or you could used signed char const arrays, and have warnings each time your tile ID is 128 or more.
Really, it's quite hard to avoid warnings as you can't easily have an array in C where some are signed and some are unsigned, you should have structs for that but here it would complicate matters too much with no real gain.
  View user's profile Send private message Visit poster's website
  • Joined: 30 Mar 2009
  • Posts: 296
Reply with quote
Post Posted: Mon Apr 08, 2024 1:20 pm
Padding the rom to 64KB and casting the value of my hiscore variable to a char seemed to have worked. :)

Thanks sverx and willbritton

I did something a lot simpler than your examples, but it seems it worked correctly, on my first test.

I'll check everything and probably update my rom today or tomorrow.

Thanks for the help!
  View user's profile Send private message Visit poster's website
  • Joined: 19 Oct 2023
  • Posts: 150
Reply with quote
Post Posted: Yesterday at 9:27 pm
A couple of questions about banking code if anyone can help please.

In the assets2banks it reads:

Quote
In case you need the banks count to start from a different number (default is 2) for instance when you need to allocate other code banks before the data banks, you can do that using:

assets2banks assets --firstbank=6


Does this mean code has to go before assets or is the above just for preference?

Another question: what's the easiest way for me to get the size of my code bank? Similar to how assets2banks outputs the size of each bank in it's summary. I mean I might not hit 16Kb but it would be good to know. EDIT: Nevermind I can see it tells me this in the output.map.

Also sorry a final question, the only code I'm putting on a separate bank is large constant arrays (enemy paths, events etc) but no functions. Is this the best way for me to store this data or should I be doing it another way?
  View user's profile Send private message Visit poster's website
  • Joined: 27 Apr 2021
  • Posts: 38
Reply with quote
Post Posted: Today at 5:51 am
For Stygian Quest, my static arrays of data are put in .bin binary files and threated as data. Much more easy to use on my opinion.

For order of banks I dont know.
  View user's profile Send private message
  • Joined: 06 Mar 2022
  • Posts: 678
  • Location: London, UK
Reply with quote
Post Posted: Today at 7:42 am
Constant arrays are not "code" in this sense, they can be banked as assets like any other without needing to use the code banking mechanism - the output of assets2banks can produce constant arrays as a comparison.

Note that there's a compiler directive you can put in a C file to indicate what bank it targets. Afk right now but I think it's #pragma bank n. I use this one rather than specifying on the command line.
  View user's profile Send private message Visit poster's website
  • Joined: 19 Oct 2023
  • Posts: 150
Reply with quote
Post Posted: Today at 7:59 am
I suppose my only thought is how to get my constant array data (mostly unsigned chars) into binary so assets2banks can bank it for me, or is there another way?

Regarding the order of banks, I've seen open source examples using code banks at the end of a list of asset banks, so I don't think the order matters.
  View user's profile Send private message Visit poster's website
  • Joined: 06 Mar 2022
  • Posts: 678
  • Location: London, UK
Reply with quote
Post Posted: Today at 8:23 am
badcomputer wrote
I suppose my only thought is how to get my constant array data (mostly unsigned chars) into binary so assets2banks can bank it for me, or is there another way?

I assume your constant array data is already in C?
If so, what I'm saying is that you don't need to use assets2banks at all for those, just put it straight in a C or H file and use the #pragma to say which bank it should go into.

(NB it's e.g. #pragma constseg bank2)

I guess one issue is that assets2banks also tries to pack your banks efficiently. One way is to reserve a bank or so at the beginning for your const arrays, but maybe there's a better way that @sverx can suggest to reserve a specific number of bytes.
  View user's profile Send private message Visit poster's website
  • Joined: 19 Oct 2023
  • Posts: 150
Reply with quote
Post Posted: Today at 8:54 am
willbritton wrote
badcomputer wrote
I suppose my only thought is how to get my constant array data (mostly unsigned chars) into binary so assets2banks can bank it for me, or is there another way?

I assume your constant array data is already in C?
If so, what I'm saying is that you don't need to use assets2banks at all for those, just put it straight in a C or H file and use the #pragma to say which bank it should go into.

(NB it's e.g. #pragma constseg bank2)

I guess one issue is that assets2banks also tries to pack your banks efficiently. One way is to reserve a bank or so at the beginning for your const arrays, but maybe there's a better way that @sverx can suggest to reserve a specific number of bytes.


Sorry I should've explained, that's what I'm already doing. I have one bank for constant arrays. But I was thinking about Naarshakta's suggestion to put it in binary and let assets2banks convert to the arrays organise it. I'm assuming that Naarshakta has an external tool or something to arrange binary data though.

I don't have much problem doing what I'm doing now and adding arrays manually to my code bank source file but as it's the first time I'm banking "code" just wondering if it's the right way.
  View user's profile Send private message Visit poster's website
  • Joined: 27 Apr 2021
  • Posts: 38
Reply with quote
Post Posted: Today at 9:02 am
In fact, all my game data ( boards, strings, items, etcs.. ) are in a json file, easy to edit for me while I work on the game design itself.
So I have written a script In python that transform that json file into a brunch of binary files that are threated as any asset file :)
For types of data you Can use an assets2bank.cfg to tell assets2bank to generate arrays of int, or char or whatever struct you want...
  View user's profile Send private message
  • Joined: 05 Sep 2013
  • Posts: 3845
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Today at 11:44 am
As often happens, there are several ways to solve this.

One, as suggested, is to treat static data as binary asset, and put that into the assets folder and leave it for assets2banks to handle it. It's a very good suggestion, but sometimes your data is not just made of constants and needs to be compiled so another solution could be to have a data bank (or more than one if necessary) where you put all your static const arrays, then you compile that and link it as a data bank (address 0xn8000). Of course you then need to map that data bank before accessing the arrays defined there, just like you would do with 'regular' assets.

Another possible approach is to keep this data with the functions that uses that in a 'code' bank. As an example, one could have a few math functions (that uses data LUTs) and create a math.c file where these functions are declared as banked function. Upon invocation of these, the code and the data will be mapped at the same time, being them together, and the result will be returned. Of course if you just need to read a value from a LUT this solution's performance won't be great, but if your functions performs trigonometric operations that require some work and you call them just a few times per frame, it might be a handy solution.

Also, the order of banks doesn't really matter - I usually keep the code in the first banks because it's much easier to move the data further away (by changing assets2banks' --firstbank= parameter for my assets) in case I need one more banks for code. I don't usually use #pragmas in my sources because I prefer to handle everything from the makefile/build scripts but, once more, this is more about personal preferences - whatever floats your boat is a good approach ;)
  View user's profile Send private message Visit poster's website
  • Joined: 05 Sep 2013
  • Posts: 3845
  • Location: Stockholm, Sweden
Reply with quote
Post Posted: Today at 11:55 am
willbritton wrote
maybe there's a better way that @sverx can suggest to reserve a specific number of bytes


it's possible, if you really want to put your own static data together with the first bank allocated to the assets, to tell assets2banks that the first bank is smaller than the regular size using
--firstbank=n,size
but I would say this is needed only if one is desperate to save one bank because of a ROM availability limit.

Another option would be to allocate that static data at the end of the last bank by just telling the linker to put that at the same address as the last assets2banks' generated bank. If it fits, it should work - but I never tried it.
  View user's profile Send private message Visit poster's website
  • Joined: 06 Mar 2022
  • Posts: 678
  • Location: London, UK
Reply with quote
Post Posted: Today at 12:14 pm
sverx wrote
I don't usually use #pragmas in my sources because I prefer to handle everything from the makefile/build scripts but, once more, this is more about personal preferences - whatever floats your boat is a good approach ;)

Actually I take a somewhat strange hybrid approach - I get assets2banks to generate C files and then in my makefile I use the filename of the generated files to inject the #pragma at the top of each one, meaning I don't need to manually specify the bank names on the SDCC command line - in other words, assets2banks is deciding on the banks automatically for the most part, but I can also create manual asset files and specify the banks in the file, all without needing to change the command line too much.

sverx wrote
Another option would be to allocate that static data at the end of the last bank by just telling the linker to put that at the same address as the last assets2banks' generated bank. If it fits, it should work - but I never tried it.

Ah that's a good point - if it fits in the remainder it saves on a bank, if it doesn't we would need a new one anyway.
  View user's profile Send private message Visit poster's website
Reply to topic Goto page Previous  1, 2, 3 ... 15, 16, 17



Back to the top of this page

Back to SMS Power!