I am writing a c program for a uController and I managed to fill 32kb with code.
The program is full with the following 'print' function:
void print(char *x)
{
while(*x) {
SerialWrite(*x++);}
}
SerialWrite looks like:
void SerialWrite(unsigned char c)
{
while(tx_buffer_size>250);
ES=0;
tx_buffer_size++;
if (tx_buffer_empty == 0){
txBuffer[tx_in++] = c;}
else {
tx_buffer_empty = 0;
SBUF = c;}
ES=1;
}
I call the print function with a string text as arguement like:
print("Hello World");
I only used 2.2kb of my 32kb external memory so my conclusion is too move "Hello World" to the external memory instead of having it hardcoded in the main program.
Unfortunately my attempts actually made it worse, I did the following:
char xdata *msg1 = "Hello World"; // <-- this made it worse, and the external memory space was not used at all
print(msg1);
Than I tried:
char xdata msg1[] = "Hello World";
print(msg1);
This did increase the external memory size by 12 which is correct as the string contains 11 chars + the null. But the program memory also increased by 3. I tried different string lengths but the program memory keeps increasing by 3 bytes.
How can I solve this problem?
Addition: I am using Keil's C compiler and I compile with favor for program size. The uController is an FPGA chip which has an emulated 80C51 chip. For this virtual 80c51 I am writing the code. I have 32kb memory for the main program and 32kb for variables
EDIT: *msg[] was a typo, it had to be *msg
char xdata *msg1 = "Hello World";
char xdata msg1[] = "Hello World";
I don't think you can ever shorten your program this way, because even if the message will be accessed from xdata, it will be first copied there by the C runtime, fetching it from code (initialized data).
If you really have a lot of "print()", then you can squeeze some bytes by declaring a correct pointer type for its parameter. I explain: due to the strange architecture of the 8051, a "high level" C "generic" pointer takes three bytes - two bytes as offset, and a third byte to specify whether it points in XDATA or in CODE. Then every call to print() has to construct such a pointer.
If, for example, you declare:
void print(char xdata *x)
now print() only accepts pointers into xdata, and only two bytes long pointers are required. Every call to print() will be simpler.
It seems that most of your texts will be constant, so they will be in code; and so the pointer type you need is not XDATA but CODE (or what else keyword is correct).
Once you have declared print() like above, you will NO MORE be able to print() data which is not in the code segment; perhaps you will need another function, like
printx(char* what)
which will accept char* from any segments, like before, but you will call this costly printx() only when needed.
Hope this helps; the 8051 is very peculiar and compilers for it are complicated (but Keil is superb). I would suggest to take a look at the generated (low level) code, may be you can spot some other memory waste. Good luck!
Addendum:______________
It happened once to me to have little room for texts. I solved nicely by applying some text compression. Given that all the texts were plain ASCII, I used characters over 127 to point to common, repeated words in the texts. For example "Hello world" can be replaced with 0x80 " world"
, if the string "Hello" is repeated a few times. Of course, the print routine must detect those special markers and manage the decompression - but this is very easy.