News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_Fessor

cpctelera/sdcc Problem w. Initialization of Variables and Arrays in headerfile

Started by Fessor, 00:30, 31 October 15

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Fessor

Im taking first steps at cpctelera and SDCC and got headaches because the initialization of this array in the headerfile won't work, or partly works as in the resulting .asm a pointerlist is created and also the calculated value stored. But at accessing the variables in subroutines they behave as if not initialised. n_choices returns 0, also the array-table is full of null-pointers.
CPCTelera is OOTB and nothing changed at configuration for my project. It should work as the assembly shows but it doesn't work and i don't have any idea why it doesn't work.


.h
char *menulist[]={"Journey Onwards ",
          " Continue Game  ",
          "Create Character",
          "    Options     "}; 

int n_choices=sizeof(menulist)/sizeof(char *);


.asm

___str_7:
    .ascii "Journey Onwards "
    .db 0x00
___str_8:
    .ascii " Continue Game  "
    .db 0x00
___str_9:
    .ascii "Create Character"
    .db 0x00
___str_10:
    .ascii "    Options     "
    .db 0x00
    .area _INITIALIZER
__xinit__n_choices:
    .dw #0x0004
__xinit__menulist:
    .dw ___str_7
    .dw ___str_8
    .dw ___str_9
    .dw ___str_10


.c
void print_menu(char startx, char starty, char highlight )  {

  int i,j;

  for (i = 0; i < 4; ++i)
    {
    j=i+1;
    if (highlight==j)
      {
    printf("\037%c%c\030> %s <\030",startx,starty+i,menulist[i]);
      }
    else
      {
      printf("\037%c%c> %s <",startx,starty+i,menulist[i]);
      }
     
    }
   
  }

arnoldemu

consider using const char *.

also initialisation is done in crt. @ronaldo, is this enabled for cpctelera?
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Fessor

Found this, googling around

Small Device C Compiler suite / Mailing Lists

QuoteYes - sdcc builds with the INITIALIZER section holding the data, but with all relocations for the INITIALIZED section. You simply take the INITIALIZER section of the sdcc output and move it to the INITIALZED section when creating the final binary, then you don't need to do anything in the start up code. See FUZIX/binman.c at master · EtchedPixels/FUZIX · GitHub This reads the map file and the makebin output of the ihx file sdcc generates. Note that the binman example there makes some assumptions about how the memory is laid out by the crt0.s and bits I use. There's not really a lot to it on Z80 beyond makebin and moving the block as the bugs in the sdcc ihx output don't affect anything under 64K long. Alan

ronaldo

@Fessor: We discussed this same issue months ago on the main thread about CPCtelera (don't know what page at this moment).

SDCC targets embedded devices, and it's binary code is mainly thought to run from ROM. That's the main problem when dealing with global variables and static initializers. All static initializer values have to be stored in the binary (in ROM), but variables cannot be in ROM: they have to be in RAM. Therefore, a piece of code is required to copy initializer values from ROM to RAM before the program starts, to ensure RAM variables have their initial values.

This is nice on an embedded environment with RAM and ROM, but is terrible when you are creating a game that runs entirely from RAM. This behaviour in RAM means:

       
  • Global variables take double space: space to store initializer values and space for variable storage.
  • Initializer code takes more space and CPU cycles at the start.
As current version of CPCtelera is designed to run from RAM, initializer code is not included. Then, global variables are not initialized at the start, to prevent having two copies of them. Proposed solutions to use global variables with initialization are:

       
  • Declare them as constants. Constant values are stored by SDCC only in ROM space, as they shouldn't change. However, as this space in a CPC game will effectively by RAM, you can change them. To change their values, access them through a non-const pointer.
  • Declare variables without an initializer. Then, initialize them using your own init functions.
Examples in CPCtelera use both of these approaches. In your example, you could do this:

#include <cpctelera.h>
#include <stdio.h>

char* const menulist[]={"Journey Onwards ",
          " Continue Game  ",
          "Create Character",
          "    Options     "};

const u8 n_choices=sizeof(menulist)/sizeof(char *);

void main(void) {
   u8 i;
   
   for(i=0; i < n_choices; i++)
      printf("%s\n\r", menulist[i]);

   // Loop forever
   while (1);
}
However, I wouldn't use a global constant/variable for the size of menulist. It's nice to have it automatically calculated, but a #define would be generally more efficient (with respect to generated code). Also, using a signed int to store a value which is always positive and smaller than 256 is an overkill (and will cost you space and CPU cycles). it's preferably to use a u8 (unsigned char).
Take into account that "const char*" and "char* const" are not the same. On first case you are telling the compiler that the character string are constant, but the 4 pointers stored in menulist[] are variables (and thus, they end-up uninitialized). In the second case, your code says that pointers are constant, but character strings may be changed.

Fessor

I must have looked at the wrong examples then... ;)
Wonderful, that works.

I took that approach with an array as i planned to write a generalized Menuselection-Routine where i can throw in a pointer to a list of Menupoints and get back the chosen selection so i have not to reinvent the wheel every time i want to use such a routine.
May be a bit overdressed for CPC and a simple printed menu with the key to press would have done also, but i wanted a "modern" UI-like browsing through Menu-Points with the Cursor-Keys as additional comfort so the fingers can reside at the cursor keys and have not to circle like an eagle around far in the sky on lookout for a prey.



ronaldo

Quote from: Fessor on 15:36, 01 November 15
I must have looked at the wrong examples then... ;)
This behaviour is quite far from being self-evident. I think all of us have had this problem at one point in our learning curve with SDCC.

May be I should review all examples to add more clarifying information on the topic. I also have one point in my task list about writting an article on this subject. I think it's quite important and gives lot of painful moments when you stomp into it without knowing (and even sometimes knowing it).

Are you implementing utility software? I'm curious about the interface you describe and what is it for :)


Fessor

This specific problem and its solution is wonderful explained and due to the keywords in the topic-title now also easy to find i hope.

No, not utility Software, only a game. For my current Project ( Mein Winterprojekt der letzten Jahre: U4 ) i am in need of a savegame with a characterrecord as actual (and further) ported subroutines are dependent on it. As generation is done in a seperate Boot/Intro/Startup-Program i can easily switch for that to c to speed up the development (i hope).
The last time i have programmed in c was on atari tt ~13 years ago so i am currently also experimenting with it to get back into that materia.

ronaldo

Oh, I see. Screenshots are really nice. Hope to see it working any time soon :)

Nice work! :D

Powered by SMFPacks Menu Editor Mod