News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu

SDCC thingies and warning

Started by pacomix, 22:20, 30 May 13

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

pacomix

Hi all!


   Actually in the project that we finally gave up (CPC-Bros) I found a problem that could aliviate some headaches if any of you is developing a multiload game.


   In the build pipeline I have built what I do, in order having an arbitrary number of sprites, songs, specific code and all of the variable things that a level has, is defining a data descriptor structure (containing tables of pointers to the level specific data) and then an unsigned char variable just after the structure. This MUST be defined as the last data in your code such as it is placed at the end of the data segment generated by the compiler. Then parsing the .map file (where it is "supposed" all the symbols and its memory addresses appear) I get that address and build a file containing all the level's data.
   I guess there is no other better way of having a reliable way for developing multiload games. If so I would like to hear other suggestions. (And no... I do not accept having a complete load of code+data... :D )


   So the thing is that, after trying fixing a bug of the project we gave up, it seems that SDCC doesn't include the static symbols defined in the code inside that .map file. This resulted in that some static variables were being defined after the last symbol that appears at the end of the data segment in the .map file. I do not know if this is a SDCC bug or not and if other compilers ignores this as well.


   So this post is to warn you all if you are loading data after the last address of the data section and getting weird behaviours or random crashes.

arnoldemu

It is sad you have stopped this project.

This is how I would do multiloads:

Have a structure, which is like this

struct
{
int num_enemies;
char *enemies,
int num_weapons;
char *weapons;
}

This is a descriptor structure. There is no instance of this in your code.

But, when you write the data you put this structure at the start of the level data, but where you have pointers you write offset values.

enemies and weapon pointers start as offsets from the start of the data. e.g. +30, or +600.

In your code you then load the data where you want to, "fix up" these pointers (by taking the offset, adding on the start and poking it back in).

Now you access all your data using pointers.

It's a common method used in games for a long time now.

So this, is not defined as a variable in your code, so the compiler doesn't need to allocate for it.


e.g.

LoadLevel(0x04000);

struct desc *level_desc = (struct desc)0x04000;

now you can use it like this:

level_desc->num_enemies etc.

With this the data is independent of the code, no need to use map files to resolve addresses.

There are times when you need to know addressess within the code, this is when the level contains code, and you need to access the main code.

Build your code to generate a file that has this kind of assembly listing:

move_player=0x08454 or
move_player equ 0x08454

Now have a seperate .c file for your level data and code. Include this listing to get the addresses for your code.
It will link against this and generate seperate data, do not link against the code.

Now you have code and level that can be loaded and which can have code in it.


My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

pacomix

Hi!


   Your suggestion of having offsets instead of pointers was the first one I thought of. It is easier and more comfortable. But if we can save bytes in the source code that is way better. Not much but a little bit in here, another little bit there and so and you end up wasting 1KB. An issue that might arise with your suggestion you need to define a fixed memory location for loading the data. global variables, arrays and structures are defined in the data segment area so you have to recalculate the last address every time you change the code. Or am I missing something here?
   That is precisely what I avoided by automatically calculating that last used address from the .map file avoiding also the fix of the offsets in runtime.
One thing I didn't fully understand is the way you use for including additional code... Could you explain it with a tiny example?


Regards!

arnoldemu

Quote from: pacomix on 22:20, 30 May 13

   So this post is to warn you all if you are loading data after the last address of the data section and getting weird behaviours or random crashes.
I had another idea.

Make your own crt file if you haven't done this already.

At the end put a label like this:


__totallyend:


at the top put:

.globl __totallyend

in your c file you should be able to reference it with

extern _totallyend;

this should give you the last address which is safe to use.


put it after all the _GSFINIAL and _DATAFINAL segments.

Or did you try this already???

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

sigh

Quote from: pacomix on 22:20, 30 May 13
Actually in the project that we finally gave up (CPC-Bros)


:( :'(


AMSDOS

I don't have any experience in this at all  ;D But if I knew how large my Data Block was going to be wouldn't setting up an array tell your C Compiler how much area you want set aside, you could probably work out where your program finishes by doing what Kev is suggesting and point your array to that area which should reserve that area for your Data. Just a thought.  ;D


The other thought I had was if you were building something which changes, then perhaps it's better to write it in parts like Dynamic wrote their games, these days with everyone using Disc Drives (don't they  :o ) making some huge game in separate loads isn't an issue.  ;D
* Using the old Amstrad Languages :D   * with the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

arnoldemu

#6
Example is asm:

http://www.cpctech.org.uk/download/modasm.zip

I'll make a c version soon.

In this asm example I use pasmo because it makes .lst files that can be included in other asm files.
main.s is built, it has the main functions and the main code. lst is generated that has it's labels.
Now I build level.s and include the labels from main. One label defines where level.s should be located, others are used so we can call functions in main.

main.s loads level.s and executes it, so we can see how we can have code and data in the levels.
So to load next level, we only need to call a function in main to load the level and execute it.

This shows how easy it is to do with pasmo and asm.

In the next example, I will make something similar, but in c.

With C, I wrote a program that reads the .noi file that sdcc can write. This program reads the file and gives me the values of labels from that file. Not as simple as #including an output listing like in the asm example.

In Windows C programming, we would like against a lib. The lib uses GetProcAddress to find the address of a function in a DLL and connect it for us so we can call it. There are other things Windows can do.
Perhaps we can learn from this for our C programs...?
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

A few months late (been busy at work):

And here is the "module" or multi-load example for C.

http://www.cpctech.org.uk/download/modc.zip

It relies on my tools to build it.

"sh make.sh" to generate the module.dsk with the 3 files on it (one is main, the others are the levels).
Main loads to 0x0100, initialises the roms so it can then load.
It uses the firmware and contains the main functions that the levels use.

Each level loads to 0x04000 and returns control back to the main program with a ret.

Note the command-line for building sdcc for the levels.

Example shows:

1. making asm code that you can link with your c program (example in cpc_ShowString.s).
2. how you compile the main program and the levels
3. how to extract the labels from the main program of the functions you want to use then to generate an asm file that you can link against with your levels in order to use these functions.

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

The level location is fixed in main.c.

I didn't have a lot of success with the linker forcing a particular segment to be at the end.
If I could do that, then I could define the real "end" of main (after data etc) and use this as the address to load to.

I did attempt it in the main_crt0.s but at the time I tried it, it just wasn't reliable enough.

So perhaps CPC Snow Bros can continue ??? ;)
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Powered by SMFPacks Menu Editor Mod