CPCWiki forum

General Category => Programming => Topic started by: ervin on 16:16, 11 July 15

Title: SDCC question
Post by: ervin on 16:16, 11 July 15
Hi everyone.

I've got a little problem that's had me banging my head against a brick wall for the last 2 hours.
I've google'd it again and again, but no matter what I can't seem to make it work.
:'(

In main.c, at the top (right after my #include statements), I've got this:

typedef struct obj3d{
    i8 x;
    u8 z;
    u8 colour;
    u8 active;
} Obj3D;

Obj3D ground={0,115,0,1};


Until now I've set x, z, colour and active in code, so I could get my screen routines working without distractions.
But now I want to move away from that and use data instead to initialise ground.
Hence the initialiser list in the ground declaration.

Now, it compiles.
However, when the program runs, it appears that the initialisation didn't work, as ground appears to contain {0,0,0,0}.

Can anyone see what I'm doing wrong?

Thanks.
Title: Re: SDCC question
Post by: Carnivius on 16:23, 11 July 15
I confused.  I thought this was going to be about the San Diego Comic-Con that's currently happening.
Title: Re: SDCC question
Post by: ervin on 16:57, 11 July 15
Quote from: Carnivac on 16:23, 11 July 15
I confused.  I thought this was going to be about the San Diego Comic-Con that's currently happening.

:)
Actually the San Diego Comic Con keeps coming up in searches for SDCC, which is very annoying when I'm trying to solve a programming problem!
Title: Re: SDCC question
Post by: gerald on 17:43, 11 July 15
Quote from: ervin on 16:16, 11 July 15
Hi everyone.

I've got a little problem that's had me banging my head against a brick wall for the last 2 hours.
I've google'd it again and again, but no matter what I can't seem to make it work.
:'(

In main.c, at the top (right after my #include statements), I've got this:

typedef struct obj3d{
    i8 x;
    u8 z;
    u8 colour;
    u8 active;
} Obj3D;

Obj3D ground={0,115,0,1};


Until now I've set x, z, colour and active in code, so I could get my screen routines working without distractions.
But now I want to move away from that and use data instead to initialise ground.
Hence the initialiser list in the ground declaration.

Now, it compiles.
However, when the program runs, it appears that the initialisation didn't work, as ground appears to contain {0,0,0,0}.

Can anyone see what I'm doing wrong?

Thanks.
It look like your crt0 is not initialising the initialised global variable.
Have a look at the crt0.s that cpcitor have provided in cpc-dev-tool-chain: a portable toolchain for C/ASM development targetting CPC. (http://www.cpcwiki.eu/forum/programming/cpc-dev-tool-chain-a-portable-toolchain-for-casm-development-targetting-cpc/msg70053/#msg70053)

Look for the gsinit label part, which handle the global initialised variables initialisation
Title: Re: SDCC question
Post by: ronaldo on 18:35, 11 July 15
@ervin (http://www.cpcwiki.eu/forum/index.php?action=profile;u=82): The problem is, as @gerald (http://www.cpcwiki.eu/forum/index.php?action=profile;u=250) suggests, an initialization problem. SDCC is a compiler designed for embeded environemts, and it generally assumes that you are producing a ROM. Inside a ROM, an asignment is impossible to perform, so the initial value for a global variable must be:
This is useful if you are actually producing a ROM, but quite perjudicial if you are producing a RAM-based program. In this second case (your case and mine) the initial value would be included in the binary stored at some place, then copied to the location of the global variable, effectively occuping 2 locations in RAM, taking double space and also taking time and code for the copy.
This is the reason why CPCtelera (http://lronaldo.github.io/cpctelera) is using an standard crt0.s file, which does not take care of global variable initialization. To save space and time in RAM-based programs. In future versions I hope to include tools for producing ROMS (i.e. .cpr files), but now it is RAM-based.
The solution is simple: do not declare it as a variable, but as a constant:

typedef struct obj3d{
    i8 x;
    u8 z;
    u8 colour;
    u8 active;
} Obj3D;

const Obj3D ground={0,115,0,1};


Then, SDCC will include it directly in your binary, as constants don't need to be copied to RAM prior to be used, because they are not expected to change. If you need to modify it, you can do the pointer trick:

const Obj3D ground={0,115,0,1};

void main(void) {
   // Pointer is not constant, so you can modify values
   Obj3D* pGround = &ground;

   // Accessing the structure using the pointer, compiler complains with a Warning, but it lets you modify values
   pGround->x = -2;
}


Several CPCtelera (http://lronaldo.github.io/cpctelera) examples use this trick, and you can see that all globals are either const, or have no default initializer.

If you dont like this trick, or have special requirements, you always can assign a default value using code:

Obj3D ground;

void initialize() {
   ground.x = 0;
   ground.z = 115;
   ground.colour = 0;
   ground.active = 1;
}

void main(void) {
   initialize();
   //...
}


I think I should write a help page describing this problem in the documentation. I add it to the task list :) .
Title: Re: SDCC question
Post by: FloppySoftware on 19:35, 11 July 15
I'm very surprised regarding this SDCC behaviour.

It should have an option for ram based programs, because the trick const/pointer should not have too much sense in the ANSI C world (but it works in SDCC, of course).

IMHO
Title: Re: SDCC question
Post by: ronaldo on 19:54, 11 July 15
@FloppySoftware (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1162): I was as surprised as you the first time I understood this behaviour. However, SDCC is not fully ANSI C compliant (it might be 90-95% more or less).

Indeed, this is a quite reasonable from the point of view of SDCC developers, as SDCC is not only for Z80 but for a great variety of processors and most of them are used in embedded systems where the program is stored in ROM. It is a little bit inconvenient when you are creating RAM-based programs, but not a hard problem actually.

There are other alternatives, like using assembler to enter initial values, but I think constants are clearer. This would be an assembler alternative:

typedef struct obj3d{
    i8 x;
    u8 z;
    u8 colour;
    u8 active;
} Obj3D;

extern Obj3D ground;

// SDCC only accepts assembly code inside a function. Remember that, in assembly,
// a function is just code (called using its address), so there is no problem in adding a dummy function
// because it would add no code to the binary. It acts as a "box" for placing code in the binary.
void dummy_function() {
__asm
_ground:: .db 0, 115, 0, 1
__endasm;
}


Title: Re: SDCC question
Post by: Optimus on 21:49, 11 July 15
Wow, thanks for that! I infact had the same problem with a global array of static variables, but never thought to use the const at the time. I was hitting my head, and then decided to initialize one after another with an init function, which takes much more memory. Even the pointer trick is nice to know, some of my global variables will be changed.
Title: Re: SDCC question
Post by: TFM on 23:10, 11 July 15
When looking at all the problem which came up here, then ... I leave my fingers off the C and stick with the Z80 assembler.  ;) :)
Title: BDS C question
Post by: AMSDOS on 23:39, 11 July 15
Quote from: FloppySoftware on 19:35, 11 July 15
I'm very surprised regarding this SDCC behaviour.

It should have an option for ram based programs, because the trick const/pointer should not have too much sense in the ANSI C world (but it works in SDCC, of course).

IMHO


I was wondering, after reading about your PCW & CP/M interests, if you've used BDS C?
Title: Re: BDS C question
Post by: FloppySoftware on 23:56, 11 July 15
Quote from: AMSDOS on 23:39, 11 July 15

I was wondering, after reading about your PCW & CP/M interests, if you've used BDS C?

No. All my CP/M & PCW projects I have written in the C language are done with MESCC (Mike's Enhanced Small C Compiler).
Title: Re: SDCC question
Post by: FloppySoftware on 23:58, 11 July 15
Quote from: TFM on 23:10, 11 July 15
When looking at all the problem which came up here, then ... I leave my fingers off the C and stick with the Z80 assembler.  ;) :)

Both, C & Z80 assembler, are nice languages. I like them very much.
Title: Re: SDCC question
Post by: ervin on 01:44, 12 July 15
Wow, thanks for all the information and discussion everyone!
This has become a very helpful thread.
My game will depend very heavily on data tables, so knowing how to do this is vital.

@gerald (http://www.cpcwiki.eu/forum/index.php?action=profile;u=250) - thanks for the info about that file. I'm still learning my way around SDCC, so that sort of info is very useful.
@ronaldo (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1227) - thanks for the detailed explanation (as usual!). Sounds like a pretty good solution.

I'll give both approaches a try tonight and see which works better.
(Or maybe they can be used together?)

Title: Re: SDCC question
Post by: ronaldo on 10:34, 12 July 15
Quote from: ervin on 01:44, 12 July 15
I'll give both approaches a try tonight and see which works better.
(Or maybe they can be used together?)
Both of them will have near to equal results. Depending on the way SDCC manages optimizations, it might be better the assembly option, but that's just speculation: just considering that specific optimizations for constants may lead to problems. However, as the compiler detects that the constant may be modified, I think it discards constant optimizations, making it equal to the assembly option.
Title: Re: SDCC question
Post by: mr_lou on 13:48, 12 July 15
I'm taking the liberty to ask another SDCC question then:

When I do this:
extern u8 myVariable = 4;
- outside all functions, then it seems to be defined but not set. I.e. the value of myVariable is not 4 but rather 0.

When I do this:
extern const u8 myVariable = 4;
- also outside all functions, then it does get defined and has the value 4.

I thought the whole "extern" keyword was supposed to work regardless of whether the variable is a constant or not?
Title: Re: SDCC question
Post by: ervin on 13:58, 12 July 15
Quote from: ronaldo on 10:34, 12 July 15
Both of them will have near to equal results. Depending on the way SDCC manages optimizations, it might be better the assembly option, but that's just speculation: just considering that specific optimizations for constants may lead to problems. However, as the compiler detects that the constant may be modified, I think it discards constant optimizations, making it equal to the assembly option.

I've decided to go with the 1st option (pGround pointing to ground).
At first this produced a compilation warning (I can't remember the wording - something to do with losing the properties of a const), but the program worked.
But after a "make clean && make" the warning went away.
;D
Title: Re: SDCC question
Post by: ronaldo on 14:01, 12 July 15
@mr_lou (http://www.cpcwiki.eu/forum/index.php?action=profile;u=96): extern keyword is normally used to signal that a variable or function is defined elsewhere (in another file of the same program). This lets your code use and access a variable or function which is defined and allocated in another part of your program. extern has nothing to do with initializing global variables to their default values. That works same way as we explained in previous posts.

More on extern keyword (http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/).
Title: Re: SDCC question
Post by: ronaldo on 14:10, 12 July 15
@ervin (http://www.cpcwiki.eu/forum/index.php?action=profile;u=82): The compilation warning will continue. It warns you that pointing to a constant with a normal pointer can lead to a change in the value of the constant (as you actually can change the value with the pointer). When you declare something constant, it's supposed to be constant (i.e. not changing), hence the warning :).

However, SDCC does some bizarre things with precompiled objects and code generation. Remember your problem with function duplication once you updated CPCtelera? I reproduced the bug and it is because of this way SDCC works. "make clean" removes the obj directory, forcing the compiler to compile all objects again, but maintains the final binary (.lib in the case of CPCtelera). You need to use "make cleanall" to ask make to delete final binary also and force SDCC to rebuild everything.

Anyway, if you know what you are doing, you can ignore the Warning, as you know that you are doing it on purpose and not by mistake.
Title: Re: SDCC question
Post by: ervin on 14:27, 12 July 15
Thanks again ronaldo.
8)

I have one more question I'm afraid.
:-[

I'm hoping this will be the last question like this I must ask, and that I will then have everything I need afterwards to continue with my game.

Based on the pointer to "ground" discussed above, I have changed my "obstacle" array to something similar.


const Obj3D obstacle[4]={
    {-8,123,3,1},
    {-8,155,5,1},
    {8,187,3,1},
    {8,219,5,1},
};

Obj3D* pObstacle=&obstacle[0];


However, it doesn't seem to work.
To be honest, I don't know what it is doing, or what I now have in (for example) pObstacle[0].x.

Can anyone help?
Title: Re: SDCC question
Post by: andycadley on 14:38, 12 July 15
Personally I'd avoid the "const trick" as it's making big assumptions about what the compiler might decide to do. For example it may decide that since two pointers are supposed to the "const" value 5, it'll coalesce them into the same value. Or it might make inline assumptions that the value will never change, for example replacing a loop counter with code unrolled a fixed number of times.

That warning is there for exactly this reason. Even if SDCC doesn't make these optimizations right now, the next version just might do....
Title: Re: SDCC question
Post by: ervin on 14:41, 12 July 15
Thanks Andy.
I'll give the ASM trick a try and see how I go...

[EDIT] It seems to work!
(And the obstacle table as well!)
:D :D :D

Thanks everyone for your help - now the development path is clear!
(Well, at least until the next thing I get stuck on).  :-[

Title: Re: SDCC question
Post by: TFM on 15:45, 12 July 15
Quote from: FloppySoftware on 23:58, 11 July 15
Both, C & Z80 assembler, are nice languages. I like them very much.


That's right. But Z80 is clearly defined, and it's easy to know the exact function of every command down to the bit.
That's what I miss for C. I would love to do more with Small-C on Z80 computers, but it's very hard to get complete docs. So if something doesn't work, I don't even know if I don't know how to use the compiler or if the program has an error.


That SDCC is surely a nice thing, but it doesn't run on a CPC.  :(
Title: Re: SDCC question
Post by: arnoldemu on 17:13, 12 July 15
Quote from: TFM on 15:45, 12 July 15
That SDCC is surely a nice thing, but it doesn't run on a CPC.  :(
Use Hisoft-c?

With modern C compilers it is not uncommon to find things that do not work the same between compilers. It depends on the language specification used (e.g. c++11) and what has been implemented by the compiler (e.g. compare gcc to visual studio's c compiler). Each compiler has a list of which language features are supported by each compiler version.

It is also not uncommon to crash the compiler trying to build a program, but mostly the functionality is stable and this is not often seen.

True Z80 is clearly defined. But then so is C. Small-c is different to c in many ways. SDCC is a C compiler, z88dk is a small-c compiler.

SDCC will either support C89 or C99.
ANSI C - Wikipedia, the free encyclopedia (https://en.wikipedia.org/wiki/ANSI_C#C89)
Modern PC compiles support c++11 or c++14.

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf)



C99 - Wikipedia, the free encyclopedia (https://en.wikipedia.org/wiki/C99)
Title: Re: SDCC question
Post by: TFM on 17:44, 12 July 15
Quote from: arnoldemu on 17:13, 12 July 15
Use Hisoft-c?


Ah no, Small-C for CP/M Plus is way better (best I know, which runs on CPC, but always open to learn something new). Thanks for your detailed answer.


Title: Re: SDCC question
Post by: ronaldo on 18:36, 12 July 15
@ervin (http://www.cpcwiki.eu/forum/index.php?action=profile;u=82): You have again the same problem. Your pObstacle variable is a global variable and you are trying to use an initializer with it (&obstacle[0]). Obviously, it has the same problem as before (ROM vs RAM etc etc).

The correct way to initialize it using const values is this:

const Obj3D obstacle[4]={
    {-8,123,3,1},
    {-8,155,5,1},
    {8,187,3,1},
    {8,219,5,1}
};

Obj3D* const pObstacle=&obstacle[0];

Now pObstacle is a constant pointer to a non-constant value. So, pObstacle variable requires a initializer that will be placed in a single location.

@andycadley (http://www.cpcwiki.eu/forum/index.php?action=profile;u=327): I partially agree with you. In fact, the const trick has dangers with respect to the way compiler may treat constants. However, if you know what you are doing, that shouldn't be an issue. I explain myself: if you use the pointer and the constant in your code (pObstacle and obstacle, in this example) you may have problems. The compiler can (and, in fact, should) apply optimizations to obstacle (the constant) but won't apply constant optimizations to *pObstacle as it is declared non-constant. So, if you use the constant only for initialization and you always access the value through the pointer, there is no way for the compiler to apply constant optimizations, and you are safe from trouble.

Of course, you can use other alternatives such use code-initialization (assuming that you lose space and time) or assembly definition (which has it's own different set of advantages and disadvantages). If no other solution is available, I think const trick is the easiest to apply and maintain under control, under the present circumstances. However, that's just my opinion. Anyone should code according to their opinion, not mine :) .

@ervin (http://www.cpcwiki.eu/forum/index.php?action=profile;u=82): When using assembly for structure initialization, take into account that you should perfectly define each byte from the structure in memory. Right now, you are using 4 consecutive bytes (1 signed and 3 unsigned) which is easy to track. However, a more complex structure may easily lead to problems if you forget a single byte. Take, for instance, this structure:

typedef struct {
   u8 name[10];
   f32 time;
   u16 seed;
} TLevel;

If you wanted to use assembly for initiating values for this structure, you need to allocate exactly 10 bytes for name, 4 bytes for time and 2 bytes for seed. Moreover, you need to know how SDCC encodes floats, as you should provide bytes for time. This is an example of how this could be managed:

extern TLevel myLevels[2];

void dummy_levels() {
__asm
_myLevels::
   ;; LEVEL 0
   ;;==================================================================
   .ascii /Level 0/     ;; Level 0 name (7 bytes)
   .db 0                ;; \0 character to end the string (1 byte)
   .db 0, 0             ;; 2 more bytes to complete the 10 bytes of name[10]
   .dw #0x0000, #0x3FC0 ;; f32 time = 1.5 in IEEE 754 format (little endian, 4 bytes)
   .dw #0x0023          ;; u16 seed = 35 (initial seed for the level, 2 bytes)
   ;; LEVEL 1
   ;;==================================================================
   .ascii /2nd level/   ;; Level 1 name (9 bytes)
   .db 0                ;; \0 character to end the string (1 byte)
   .dw #0x0000, #0x41A4 ;; f32 time = 20.5 in IEEE 754 format (little endian, 4 bytes)
   .dw #0x033A          ;; u16 seed = 826 (initial seed for the level, 2 bytes)
__endasm;
}

As you see, this is not so easy and it's quite error prone. If you change the name of a level and make a mistake in the number of total bytes (say you write 'Level 13' and forget to remove a zero from the posterior 2 padding bytes) then all the values are mixed and the results are undefined. Moreover, this kind of mistake could be quite difficult to track and fix.

This is why, in general, I prefer the const trick (taking care, of course). Using it, you make normal assignments and the compiler takes care of this low-level details with no harm to performance or size.
Title: Re: SDCC question
Post by: FloppySoftware on 22:14, 12 July 15
Quote from: TFM on 15:45, 12 July 15

That's right. But Z80 is clearly defined, and it's easy to know the exact function of every command down to the bit.
That's what I miss for C. I would love to do more with Small-C on Z80 computers, but it's very hard to get complete docs. So if something doesn't work, I don't even know if I don't know how to use the compiler or if the program has an error.

Have you tried MESCC (my Small-C version)?
It runs on CP/M, has some nice libraries and it's licensed under the GNU license.
FloppySoftware: MESCC / Mike's Enhanced Small C Compiler (http://www.floppysoftware.vacau.com/mescc.html)
Title: Re: SDCC question
Post by: ervin on 00:14, 13 July 15
@ronaldo (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1227) - thanks once again.
That's a lot of very useful information.
8)

I can see merit in both techniques... for me there is no danger in using the ASM approach, as my tables will indeed only contain consecutive  byte values (with perhaps the odd 16-bit word value).

Nonetheless, the pros/cons of each method are very interesting, and certainly something to keep in mind.
Title: Re: SDCC question
Post by: ervin on 02:49, 13 July 15
Wow, SDCC can be really frustrating at times!
:'(

I've spent over 4 hours(!) trying to figure out how to have an array of a struct, where the struct contains an array of a struct.
It's making my brain melt!

Anyway, I finally got it working.
I was getting "duplicate initializer" errors, and "needs curly braces" errors.
Much Googling ensued.

It makes sense now, but it hasn't been intuitive at all (and still feels like there are unnecessary extra curly braces, but compilation fails without them all).

I've got this:


typedef struct obj3d{
    i8 x;
    u8 z;
    u8 colour;
    u8 active;
} sObj3d;

const struct section{
    sObj3d obs[8];
} sSection[2]={
    {
        {
            {-8,8,3,0},
            {-8,40,3,0},
            {-8,72,3,0},
            {-8,104,3,0},
            {0,0,0,0},
            {0,0,0,0},
            {0,0,0,0},
            {0,20,0,0}
        }
    },
    {
        {
            {8,8,4,0},
            {8,40,4,0},
            {8,72,4,0},
            {8,104,4,0},
            {0,0,0,0},
            {0,0,0,0},
            {0,0,0,0},
            {0,20,0,0}
        }
    }
};


And in main.c I can access an element with something like this:


u8 myZ;
myZ=sSection[0].obs[0].z;


Finally, I have a working database structure!
In use, the benefits are obvious, as I don't need to calculate array offsets to get to a particular element, but it was very difficult getting here!

At last I can start designing the section layouts for my runner game, and make it all run from easily accessible data tables.
No doubt I'll run into more errors soon, but for now I'm pretty happy.
8)
Title: Re: SDCC question
Post by: AMSDOS on 07:30, 13 July 15
Quote from: arnoldemu on 17:13, 12 July 15
True Z80 is clearly defined. But then so is C. Small-c is different to c in many ways. SDCC is a C compiler, z88dk is a small-c compiler.


Not sure how you come to that reasoning regarding Small-C, it's limited in the sense it's a scaled down version of C, does it differ so much from the Circa 1970 language used to build Unix? I haven't used SDCC to comment on it, though I was under the impression (and correct me if I'm wrong) SDCC is a further adaption of Small-C, in the same manner Small-C was adapted Jim Hendrix?
Title: Re: SDCC question
Post by: arnoldemu on 09:28, 13 July 15
Quote from: AMSDOS on 07:30, 13 July 15

Not sure how you come to that reasoning regarding Small-C, it's limited in the sense it's a scaled down version of C, does it differ so much from the Circa 1970 language used to build Unix? I haven't used SDCC to comment on it, though I was under the impression (and correct me if I'm wrong) SDCC is a further adaption of Small-C, in the same manner Small-C was adapted Jim Hendrix?
Modern c differs from the original C in the way the functions are defined.

In very early c you did this:

main() int argc; char *argv

in modern c it's:

main(int argc, char *argv)

Yes small-c is a cut down implementation of C, specifically so to make it easier to implement and smaller in terms of compiler size I believe.
I don't know if there is a small-c definition, I think it started as a language in Dr.Dobbs journal?

Both are fine, there are some syntax differences but generally minor (small-c may be lacking "switch"??).
Title: Re: SDCC question
Post by: FloppySoftware on 11:35, 13 July 15
Quote from: arnoldemu on 09:28, 13 July 15
Modern c differs from the original C in the way the functions are defined.

In very early c you did this:

main() int argc; char *argv

in modern c it's:

main(int argc, char *argv)

Yes small-c is a cut down implementation of C, specifically so to make it easier to implement and smaller in terms of compiler size I believe.
I don't know if there is a small-c definition, I think it started as a language in Dr.Dobbs journal?

Both are fine, there are some syntax differences but generally minor (small-c may be lacking "switch"??).

No, an older function definition is like this:




int strlen(string)
char *string;
{
   ...
}


There are a lot of Small-C versions, all descendant from the Ron Cain's original.

The main problem with the Small-C versions around, is that they are only related between them in their ancestor, but they don't follow a linear evolution.

That caused that some versions have structures, even floats, while other lack switch, etc.

I'm absolutely sure that Small-C is the compiler most ported to any machine / environment / cpu: there are versions for CP/M, DOS, Unix / Linux, Mac, etc., each one with its own functionalities and peculiarities.

For example, my own Small-C versiĆ³n (MESCC), lacks structures, but has switch, nexted #includes, #if, #asm, redirection, malloc, etc., and, of course, can compile itself.

My Unix-like shell for CP/M (SamaruX) was written in MESCC.

Well, I do nearly all my projects in MESCC, actually.

I like Small-C.  8)

Title: Re: SDCC question
Post by: AMSDOS on 11:40, 13 July 15
Quote from: arnoldemu on 09:28, 13 July 15
Modern c differs from the original C in the way the functions are defined.

In very early c you did this:

main() int argc; char *argv

in modern c it's:

main(int argc, char *argv)


That would suggest in the earlier versions of C, variables could not be passed between functions, only declared locally.

QuoteYes small-c is a cut down implementation of C, specifically so to make it easier to implement and smaller in terms of compiler size I believe.


Wikipedia describes Small-C as a Subset of the C Programming Language, designed for the Low-Powered Microcomputers.


QuoteI don't know if there is a small-c definition, I think it started as a language in Dr.Dobbs journal?


Ron Cain wrote it for an Intel 8080 and was published in the May 1980 Dr. Dobbs Journal.

QuoteBoth are fine, there are some syntax differences but generally minor (small-c may be lacking "switch"??).



The Wikipedia site  (http://en.wikipedia.org/wiki/Small-C) mentions Z88DK as a Compiler derived from Small-C, so I'm getting my compilers muddled up.
Title: Re: SDCC question
Post by: FloppySoftware on 13:10, 13 July 15
This is part of the documentation from the Small-C compiler I bought from a PD library on 3" for my Amstrad PCW:
Quote
A SUMMARY OF THE SMALL C LANGUAGE (for Version 1.7 Oct. 1985)

Introduction
Small C is a subset of the standard C language.  It was written by Ron
Cain and originally published in Dr.Dobbs Journal of Computer Calisthenics and
Orthodontia,  No.45.   The version described has been modified to generate Z80
mnemonics instead of the original 8080 ones.  A number of bug fixes,  most  of
them  sent  in  by readers of DDJ, have also been incorporated.  Several extra
features have also been  added,  many  based  on  other  enhancements  of  the
original.  This version has been developed under CP/M 2.2.  Unlike the earlier
version  in Vol 15, no attempt has been made to keep the code 8080 compatible.
The libraries have been modified in various ways since the earlier release but
since most of them will only run in RAM, there has been no  particular  effort
to optimise their length by using shorter (but often slower) Z80 instructions.
The  compiler  inputs  a  program  written  in Small C from a file and
produces a version of the program in Z80 assembler  language  mnemonics  which
can  be  assembled and run on a Z80 system.  The original run time library has
been supplemented by some additional routines which use CP/M  I/O  facilities.
The  library  is divided into modules so that routines that are not needed for
particular applications can be omitted.

...

References.
Dr. Dobbs Journal of Computer Calisthenics and Orthodontia, Box E, Menlo Park,
      CA 94025
  No. 45  (May 1980)   "A Small C Compiler for the 8080's"  by Ron Cain
    A listing in C of the 8080 compiler + notes on implementation.
    This issue also contains other articles about C.
  No. 48  (Sept. 1980) "A Runtime Library for the Small  C  Compiler" 
   by  Ron Cain -   Run time library + useful notes.
   (See also Nos. 52, 57 and 62 for bug notes by P.L.Woods, K.Bailey,
     M.Gore & B.Roehl, J.E.Hendrix)
  Nos. 81 and 82 (July, Aug. 1983) "RED - A better Screen Editor" by E.K.Ream
    A screen editor written in Small C with a number of library
    routines.
     
  There is  a later version of Small C by J.E.Hendrix in DDJ Nos.74 and 75
   but this is copyright and so presumably not in the public domain.
 
"The Small C Handbook" J.E.Hendrix  This is mainly devoted to an update
   of Hendrix's development of Small C.  No support routines given, though
   they are given in the DDJ version.
C Users Group Vol 9. This contains Mike Bernson's Small C. This is an
   8080 version and uses a special assembler which is provided. The
   original was got going via BDS C.
SIG/M Vol 149  This includes C86 adapted by Glen Fisher
SIG/M Vol 224  This contains a floating point, Z80 version of Small C.
  There is also a Z80 assembler and linker. There are some formatted
  I/O facilities. The programming constructs are those in the original
  compiler. Modifications by J.R.Van Zandt.
"A book on C" by R.E.Berry and B.A.E.Meekings. (Macmillan 1984)
   This includes a listing of 'Rat.C' which is very similar to Ron Cain's
   version but has useful cross-referrence  listings  etc.  This  reference is
   also worth examining if you want to adapt the compiler to other CPU's. It's
   also quite a good introductory low priced text on C in general.

"The C Programming Language" by B.W.Kernighan and D.M.Ritchie (Prentice-Hall)
   The standard text on C.
"The  UNIX System" by S.R Bourne. (Addison-Wesley). A superb book on UNIX with
  a chapter on C  and an appendix which defines most of the important standard
  C functions.
The C/80 compiler from Software Toolworks is an 8080 code compiler which seems
to be based on Small C but is considerably enhanced.

        John  Hill  (Nov.1983/Mar.1984/Oct 1985)
Title: Re: SDCC question
Post by: arnoldemu on 13:13, 13 July 15
I wasn't saying small-c or c is better.

But they are different.

small-c doesn't have some constructs compared to c, and as said, it depends on the implementation of small-c.

SDCC is meant to be full c. z88dk is small-c with some extras.

I've used both and both are good.
Title: Re: SDCC question
Post by: Alcoholics Anonymous on 00:40, 16 July 15
Quote from: arnoldemu on 13:13, 13 July 15
I wasn't saying small-c or c is better.

But they are different.

small-c doesn't have some constructs compared to c, and as said, it depends on the implementation of small-c.

SDCC is meant to be full c. z88dk is small-c with some extras.

I've used both and both are good.

z88dk's small-c has evolved quite a bit.  Almost all the limitations of the original small-c are gone and things like float & longs are present as well as ansi-style functions.  If sdcc is 95% compliant, z88dk is probably 85% compliant in terms of the C89 language itself.  There are a few notable drawbacks (no function prototyping and no multi-dimensional arrays) but other than that it will consume most of the same C source.  The other main difference is in the libraries:  sdcc's are minimal and written in C whereas z88dk's are much more complete and written in assembly language.

If you would like to try it, z88dk is getting ready for another release soon (<1 month, 2 months? idk).  Quite a bit has changed.  There is now a second C library aiming for a subset of C11 compliance and made compatible with sdcc.  It's also directly supporting compilation with sdcc using this library.  It's a better sdcc for the z80 as it supplies a much more complete library written in asm, takes full advantage of sdcc's new fastcall and callee linkages and supplies more peephole rules to help reduce code size.  The crts automatically take care of bss and data initialization and can generate binaries destined for execution in RAM or ROM.  (A ROM binary needs to store initialized data with the rom image and copy that into ram at startup).  Some of these gotchas are mentioned specifically in this thread.  sdcc is being used purely to translate C to asm source and then that asm source is processed to be (more) standard zilog before being consumed by z88dk's backend assembler/linker.

Documentation is being prepared now and you can read little bit about it:
http://www.z88dk.org/wiki/doku.php?id=temp:front (http://www.z88dk.org/wiki/doku.php?id=temp:front)

The cpc target is not a completely smooth port.  z88dk's libraries take full advantage of the exx set and index registers which is a problem for the cpc's interrupt routine.  To make a cpc target, on interrupt, register state would have to be set to what is expected by the rom, the rom called and on return, register state restored. Likewise for firmware calls.  In the past cpc users have complained about stability but as it turned out, it came down to use of the exx set and incompatibility with the firmware, something that was not known to the z88dk devs as they (we) are not experts on the cpc.  If that's not done you can run with interrupts disabled as long as no firmware is called.
Title: Re: SDCC question
Post by: Alcoholics Anonymous on 00:55, 16 July 15
Quote from: arnoldemu on 13:13, 13 July 15
I wasn't saying small-c or c is better.
But they are different.

sdcc is modern C compliant (it can do C89, C99 and some C11) but beyond that it is an optimizing compiler.  It's performing code analysis that small c is not doing and the result is almost always faster code.  It also comes with a peephole optimizer that can perform simple code analysis (it can determine if a memory location is volatile or if a register's value is dead or live, eg).

Small-C is much simpler in those two compartments.  It only makes local optimization decisions and the peephole optimizers that are typically supplied can't do any code analysis and are limited to text substitution.  That means substitutions necessarily have to be more conservative but it's not as limiting as you might think since, because the compiler only performs local code generation, you can know that registers are dead if enough of the surrounding asm text is captured in the peephole rules.

There are two great things about small-C :- one is it's possible to run on the original hw and the other is that it tends to generate small code.  If you treat the C code as glue and supply a large body of asm library routines, you can approach the speed of asm programs and still keep the binary size relatively small.  The small code generation comes from implementing many compiler actions with calls to primitives functions.  It does mean slower code however.

sdcc's optimizer still has a ways to go for the z80.  I think Philip wrote a thesis on it and implemented it in sdcc but his thesis was on 8-bit register allocation, which sdcc does very well with no question, but what I see is sdcc screwing up 16-bit code and sometimes opting for 8-bit code where 16-bit code would work better.  We try to correct some of that with peephole rules.  While sdcc can still improve further in the optimization area, it still does fairly well and is able to improve in the future, unlike small-C derived compilers.

Anyway from the experience I've had over the last 6 months, it looks like sccz80 (small-C derivative) will usually generate smaller code whereas sdcc will typically generate faster code if they have access to the same libraries.  On the z80 the best results are always had by using statics where reasonable and those are the sorts of programs I was testing with.  Things swing the other way if you write C code with lots of local variables and long parameter lists.
Title: Re: SDCC question
Post by: AMSDOS on 11:24, 16 July 15
Quote from: Alcoholics Anonymous on 00:40, 16 July 15
z88dk's small-c has evolved quite a bit.  Almost all the limitations of the original small-c are gone and things like float & longs are present as well as ansi-style functions.  If sdcc is 95% compliant, z88dk is probably 85% compliant in terms of the C89 language itself.  There are a few notable drawbacks (no function prototyping and no multi-dimensional arrays) but other than that it will consume most of the same C source.  The other main difference is in the libraries:  sdcc's are minimal and written in C whereas z88dk's are much more complete and written in assembly language.


It's also possible to generate Z88DK code from CPC BASIC 3 files, so some degree of implementing code from Locomotive BASIC into Z88DK by just selecting the relevant output.
Title: Re: SDCC question
Post by: ervin on 14:22, 16 July 15
Quote from: AMSDOS on 11:24, 16 July 15

It's also possible to generate Z88DK code from CPC BASIC 3 files, so some degree of implementing code from Locomotive BASIC into Z88DK by just selecting the relevant output.

Oh, doesn't it produce ccz80 code?
(Or am I getting mixed up?)
Title: Re: SDCC question
Post by: AMSDOS on 09:28, 17 July 15
Quote from: ervin on 14:22, 16 July 15
Oh, doesn't it produce ccz80 code?
(Or am I getting mixed up?)


Yes, you're actually correct.


But perhaps someone could write it for Z88DK.  :laugh:
Title: Re: SDCC question
Post by: Alcoholics Anonymous on 04:13, 19 July 15
Quote from: AMSDOS on 09:28, 17 July 15
But perhaps someone could write it for Z88DK.  :laugh:

lol it would certainly help to clear up the confusion.  sccz80, ccz80 it's pretty close :D

Stefano was doing some interesting things a while back:

http://www.z88dk.org/wiki/doku.php?id=advanced:cpmlink:programs (http://www.z88dk.org/wiki/doku.php?id=advanced:cpmlink:programs)

He found a way to export rel files from cpm and link those within z88dk.  What that means is you could use cpm compilers (basic, fortran, c) to generate a rel file and then use z88dk to compile for any z80 target.  On that page he compiled a basic program.  I think there was still some work to do on it.
Title: Re: SDCC question
Post by: AMSDOS on 11:21, 20 July 15
Quote from: Alcoholics Anonymous on 04:13, 19 July 15
lol it would certainly help to clear up the confusion.  sccz80, ccz80 it's pretty close :D


Not to mention my Sprite Opcode Blues, and &CC/&88/&80 is more dilemma for me, when's the 0C compiler arriving?
Powered by SMFPacks Menu Editor Mod