SDCC Part 4 of 4 : Tips & Tricks when programming in C for the Amstrad CPC

In Part 3 of this series of tutorial, I covered how to use Maxam-style syntax in your own C programs using SDCC2Pasmo tool. You can now technically create C programs targeting the Amstrad CPC for real, congrats ! This article shares some tricks & tips I found while gaining knowledge on C programming for the Amstrad CPC.

How to debug your program

Of course, a program being developed for the Amstrad CPC has to be tested against a simulator (I use the real machine only after hours of work to ensure it's still compatible with the target). I personally use WinAPE, but any other modern emulators with debugging facilities should behave the same way.If you insert the following code in your C code, it will behave as a breakpoint for the debugger :

__asm db &ed, &ff__endasm;

Then you will be able to debug line by line your program while checking for registers and memory.

How to split your program at different memory locations

There are 2 methods to accomplish this. This first one is to use static binding : in your main_entryPoint.asm file (see Part 3) simply insert org &XXXX instructions at right locations in your source code. The second method is called dynamic binding and is tricky to implement : it's exactly the same pattern used in... Windows's DLLs !

I personally always split my programs in 2 distinct parts :

a core part, containing low-level routines shared through all the program such as WaitVBL, FlipScreen, SetColor, Unpack, PlayMusic, etc. This core part can also contain data (pointer to each screen scan-lines, music, etc).

a temporary part, being unpacked at a temporary location (a part for a demo, a level for a game, etc).

This split is mandatory because I don't want to bind the core part to the temporary one, it would not be efficient memory-side (in the context of having multiple temporary parts for a single core part).

We want the temporary part being able to give calls to the core part. The solution I found for this (as used in Pheelone demo, and extended one step further in Phreaks demo) is to use a separate table at an absolute location in memory containing function pointers.

This function is called at your program's startup and will initialize the table's content with function pointers.

The temporary part knows nothing about the core part. You have a create separate function declarations for the functions to want to expose to temporary parts. The implementation is like this :

WaitVBL(){__asm ld hl, ( functionPointers ) jp ( hl )__endasm;}

Functions with parameters does not have problems : SDCC makes use of stack for them. The stack gets unmodified through this code.

I advise you to think about a better solution (C's struct ?) for the indices management than hardcoding value ( "functionPointers + 2" ), but you get the idea.

Write slow code in C first, then optimize in assembly code

My recommendation is to use C code as much as possible. Even for slowest things. Then if performances are not good enough, only optimize progressively critical parts using assembly code. People usually tends to be surprised when learning that Phat's tunnel or Pheelone's 3D starfield are fully written in C !

It's faster to use global variables than using function parameters

If you are developing some routines that need to be called quite often, you sometimes have to let the good design somewhere else and think about getting the best speed possible. If your function use many parameters, then I recommend to remove them and use global variables instead.

How can I retrieve parameters in a C function from inlined assembly code ?

Let's say we want to recreate the classical C's memcpy routine. The parameters can be retrieved using the IX register (starting from index 4). It would be implemented like this :

Secondary Z80 register set is not used by SDCC...

How to use multiple C source files per project ?

SDCC2Pasmo handles only a single .asm file at a time, and - as a linker would do - adds at the end of it some C lib code used by this source. This is intended to work like that. Unfortunately, this does not let the developer to dig with multiple C files inside a single project, as each outputs would contain in that case its own C lib code (if you decided to do it that way - that would imply duplications in memory of C lib code which is not required).

One possible workaround for this is to create a .c file which includes all the other ones. This is an example of a Program.c source-file being is the only file to be compiled with SDCC, treated with SDCC2Pasmo and finally compiled by Pasmo :

So the build script does everything and creates the disk. If WinAPE locks the file though, you need to eject the existing disk before you can run the build script.

Conclusion

I don't have more tips & tricks in mind, so let's finish here this series of tutorial. I hope it gave you the wish to try SDCC and adopt it for your coming projects targeting the Amstrad CPC. Do not hesitate to contact me if there is missing information, I would be glad to help you (and eventually complete the articles).Thank you for reading !

Powered by Create your own unique website with customizable templates.