3) try to enable the SDCC codepath within z88dk - maybe some of the guys on the z88dk forum could help
Alternatively, since the SP1 is so good/fast and the C libraries so optimal - it might be better sticking with z88dk, if you can afford the code size/speed issues. Just depends on what you need for your game I guess!
I stop by occasionally so I can answer right here
You can use sdcc with z88dk's libraries now. The documentation is still being written but you can find what is done here:
www.z88dk.org/wiki/doku.php?id=temp:frontIf you're using windows, the process is very simple.
1. Download and install an sdcc nightly build from
sdcc.sourceforge.net/snap.php . Add sdcc/bin to your path. It's important to use a nightly build because a number of important(ish) bugs have been fixed since their last release.
2. Get the sdcc-z88dk patch from
z88dk.cvs.sourceforge.net/viewvc/z88dk/z88dk/libsrc/_DEVELOPMENT/sdcc_z88dk_patch.zip . Copy zsdcc to the sdcc/bin directory. This is a slightly modified version of sdcc that will be invoked by z88dk. It hasn't been accepted by the sdcc team yet because it causes some regression test failures for a few non-z80 targets supported by sdcc.
3. Get the z88dk nightly build as instructed here:
www.z88dk.org/wiki/doku.php?id=temp:front#installation You should remove your old install first and set up path information as described.
Here's an example compile with the new c library using sccz80:
zcc +zx -vn -clib=new test.c -o test
Here's the same program compiled using sdcc:
zcc +zx -vn -clib=sdcc_ix --max-allocs-per-node200000 --reserve-regs-iy test.c -o test
Note for sdcc: The code generator's optimization level (200000 here) can cause compilation to be really slow when high so you may want it low while developing. On the zx target you cannot use the iy register if the rom's isr is running. So you must compile with --reserve-regs-iy if the rom isr is active.
Another compile that will have smaller code using sdcc:
zcc +zx -vn -clib=sdcc_iy --max-allocs-per-node200000 test.c -o test
The difference here is the library will use iy instead of ix so that it does not have to save the frame pointer (ix) for the compiled code. Because iy is being used the ROM isr cannot be allowed to run.
The output is a raw binary that by default should be loaded at address 32768. You can make a tap file out of that using appmake or your own tools.
There are a few examples ready that you can read over:
www.z88dk.org/wiki/doku.php?id=temp:front#examples . These examples are somewhat over-complicated on purpose to explain some facet of the library. But the info on library configuration, pragmas and memory model are especially useful for a deeper understanding.
One difference between the classic c library and the new one is you never have to link against any other library unless you are using float math (-lm). For example, no more "-lndos -lsp1" etc. The compile lines above are sufficient for everything. You can't use "-create-app" anymore either as the output from the new c lib could be more than one binary; use appmake directly instead to make tap files. The clisp example explains it briefly and most of the example source code has an appmake invocation in the comments.
The second difference is z80asm has become section aware and the new c lib and crts use sections extensively. User code and data has to be assigned to defined user sections (code_user, rodata_user, smc_user, data_user, bss_user) in order to be placed inside the binary. You are allowed to make your own sections but as these are unknown inside the crt (it sets up the memory map), those sections will be output as separate binaries. Your sprite data, for example, can be assigned to rodata_user:
SECTION rodata_user
PUBLIC _mysprite
_mysprite: defb 0,0,0,0,...
As an example of creating your own section, you could assign data to one of the 128's extra memory banks:
SECTION BANK6
org $c000
PUBLIC _bank6_data
_bank6_data: defb 0, 0, 0...
After a compile you would get two binaries: out_CODE.bin and out_BANK6.bin. The first is the usual program and the latter is data you should place in bank6.
You will always get smaller and faster code when using sdcc in combination with z88dk. sdcc's libraries are rudimentary and written in C which makes them large versus z88dk's written in asm which are 3x smaller. z88dk implements all of sdcc's primitives in asm (this is stuff like integer mul/div, float math, etc) whereas sdcc only does 16-bit math in asm. z88dk changes all of sdcc's calls to library and primitives to callee and fastcall linkage which saves hundreds of bytes. z88dk adds a new peephole rule set that fixes a couple of sdcc code generation bugs and improves sdcc's code especially when dealing with statics. Depending on the program, you can save nearly 1k of memory on a 20k memory size. Finally, z88dk supplies a RAM model for code generation which means it throws away the duplicate data section used to iniitialize non-zero variables in RAM.
Here are the sdcc compiles that you would probably want to use on the zx target:
zcc +zx -vn -SO3 -startup=31 -clib=sdcc_ix --max-allocs-per-node200000 --reserve-regs-iy test.c -o test
zcc +zx -vn -SO3 -startup=31 -clib=sdcc_iy --max-allocs-per-node200000 test.c -o test
It's possible the -SO3 creates incorrect code (there is an issue with sdcc's peepholer that hopefully is solved sometime soon) so you may want to try without it during program development. If -SO3 leads to a crash, let me know so I can investigate
-SO3 uses a much expanded set of peephole rules.
Some more details on optimization here:
www.z88dk.org/wiki/doku.php?id=temp:front#optimization_level and the following section describes the steps taken to compile a program. Sometimes that helps to demystify how things work.
The -startup=31 uses a bare bones crt that does not instantiate anything on stdin/stdout/stderr. You can still use sprintf/sscanf families if you need them. If you do use them, make sure to configure the library to eliminate any converters (%I, %B, %x, etc) that you do not need. They have been written to allow you to reduce printf size by eliminating things you don't need.
He didn't understand the tools
He compares a bare sdcc crt with a z88dk crt that instantiates files on stdin/stdout/stderr and allocates space for a heap and other platform functions. sdcc's output also does not include the bss segment (ie your variables) -- the memory is required but it's not counted in the binary. So z88dk comes out of the gate with a high memory disadvantage. He has issues with crashing because z88dk uses the full z80 register set whereas sdcc only the main set (and index registers); the CPC's firmware requires that the exx set not be modified. He then fails to use the library code (the library supplies asm implementations of qsort and line draw which are many times faster than sdcc c code). If the goal is to compare translated C, he writes as if on a 32-bit platform. C code that accesses a stack frame leads to code that is 3-5x slower than asm code -- on small uPs statics should be preferred where acceptable. You can find some hints for better results (code size and speed) here:
www.z88dk.org/wiki/doku.php?id=temp:front#reducing_binary_size sdcc generates quite poor code when accessing statics (and we try to fix that with peephole rules -SO3) but sccz80 improves greatly. We're finding that while sdcc will usually generate faster code, sccz80 usually generates smaller code when those hints are followed. A lot of people are confused by the code generated by sccz80 vs sdcc but that's because sccz80 is trying to implement its actions as subroutine calls to reduce code size whereas sdcc is inlining everything which makes it faster yet larger.
Anyway, sorry for the long post, but the answer is you can use sp1 now with sdcc and using sdcc with z88dk's libraries gets you the best of both worlds
Careful though -- sdcc does not include the bss segment in the output binary. Actual memory usage is greater than the file size!