static vs. "normal" global variable
macca
Posts: 784
Hello All,
What is the difference (related to Propeller GCC not C) between a global variable declared as static and "normal" (non-static) ?
I'm working on a program that uses a library archive (ar) for common functions. The sources in the archive uses global variables, the problem is that if I declare one of these variables as static the program compiles but won't work anymore, or, better, doesn't work as expected. I tought that the static declaration worked like in standard C and the variables are visible in that source file only (which is my intention, these variables should not be visible by other modules), but I guess there is something else. The variables are used indirectly by others, like settings values, pointers to other data, etc. looks like something gets relocated in the wrong position.
The program is compiled with lmm model.
What is the difference (related to Propeller GCC not C) between a global variable declared as static and "normal" (non-static) ?
I'm working on a program that uses a library archive (ar) for common functions. The sources in the archive uses global variables, the problem is that if I declare one of these variables as static the program compiles but won't work anymore, or, better, doesn't work as expected. I tought that the static declaration worked like in standard C and the variables are visible in that source file only (which is my intention, these variables should not be visible by other modules), but I guess there is something else. The variables are used indirectly by others, like settings values, pointers to other data, etc. looks like something gets relocated in the wrong position.
The program is compiled with lmm model.
Comments
It is difficult to explain, I'll attach the source code, it is the C porting of my game engine project.
If you open the graphics_renderer.c file you'll see two TILEMAP declarations:
With that declaration it works. If you change these two variables to static the video doesn't display the correct image anymore. Looks like it picks the wrong pointers.
If you want to compile, compile the engine_c folder first, then the demo_c folder.
Why should accessing a static global from outside of it's file (or includes) produce a reliable result?
No mallocs and, as I said, there are very few local variables so the stack should not be an issue.
Overflow ? How ? It certainly doesn't use all hub memory. Are we using the same compiler version ? Mine is gcc version 4.6.1 (propellergcc_v0_3_4_1942) compiled from source.
The two tilemap arrays builds a double buffering scheme using for scrolling the background. The global tile_map variable points alternatively to tile_map_1 or tile_map_2, the switch is done by the flip function. The tile_map variable is used by external modules to have a reference to the off-screen map and be able to safely update it. The whole source is a work in progress and it is likely that it will be changed in the near future so there won't be any global pointer variable, but I would like to understand what's wrong. I don't remember to have had any problems with static variables like that with normal desktop programs, that's why I asked if there are differences in that specific gcc implementation.
Thanks for the overview of how your code works. As I said, I'll look at it later today.
This is a very a cool demo BTW.
As I said in my previous post, it might be a 32-bit alignment problem. It may be aligned when a global, but not when a static because of the order of the variables in memory.
Could these variables be getting optimized to something in the end?
I had two arrays of constants (look up tables) that were expected to be contiguous in memory. That is accesses off the end of the first one would reach into the second one which would happen to have the correct data in it. Bad practice really.
All was well in the Spin version and C version with no optimization.
BUT turning on optimization caused the compiler to reverse the order of the arrays in memory which broke everything.
I happen to notice that your problem here is with two consecutive arrays...
It should run on any platform with VGA on P16-P24. It expects a NES controller on P2-P4 but it isn't important to see the results.
Because the RENDER_PARAMS structure declares the tile_map member as uint32_t, declaring as TILEMAP * should fix the type match.
The TILEMAP structure is 16 bits but the array has always an even number of elements so it should always be 32-bit aligned, if that's what you mean. The pointer is used by the rendering COGs code so it must be 32 bit aligned. I guess this may be the problem. I don't know if there are structures or variables that may cause a misalignment, but anyway I'm surprised that this makes a difference when the variable is declared static.
Yes with volatile it works, so it appears to be an optimization issue.
No, the arrays are declared consecutively just for clarity but they could be declared in any order and with other variables between them.
Why?
I would expect it to be aligned yes. But I would expect an array of 16 bit items to be aligned to two byte boundries not four. Perhaps if TILEMAP is a struct of two bytes I would expect only byte alignment.
I think you are right, I assumed that the alignment was made by looking at the variable size but it should be made by looking at the type size, so the arrays may be not be aligned on 32 bit boundaries. The alignment issue may be confirmed, because if I change the order of the objects in the makefile the problem seems fixed. Maybe it is just a coincidence that it works without the static declaration.
Then I found two other things, first the array size is wrong, it should be [34 * (VRES / 8 + 2)] and not [34 * (VRES / 8) + 2] this alone seems to fix the problem, even if the missing elements are not that important in that specific case (the missing elements should not be read by the COG and are not written by the code). The other thing is that I found the nes_gamepad_ctrl.c source declares a 16 bit static variable, this could explain the different alignments when the arrays are declared static.
Is there a way to force the 32 bit alignment on a variable ?
Perhaps you could declare your TILEMAP as a union of a uint32_t and whatever structure it actually has. That should do it.
And access the tile data with :
static TILEMAP tmarray[10] __attribute__((aligned(4)));
In which case you don't need the union stuff.
No, I can't. It is 16 bits, or 2 bytes, one tile index and one palette index. Probably in future it will become 6 bits for palette index and 10 bits for tile index, but still 16 bits total.
As far as making tile_map_1 and tile_map_2 volatile -- that shouldn't make any difference as long as you always access them through the pointer. It might make a difference if you made the pointer volatile.
It certainly made a difference for me (on the default branch). Addresses must have gotten shuffled.
However, I don't think optimization is the problem since -O0 without volatile still had the same issues.
The thing is that without static, the display is "close" to being correct. If the arrays were totally lost, the screen would have garbage.