4 ms·
Well, while certainly imperfect, some like SDCC are good enough to write some games with nontrivial logic. Here’s an open source game (disclosure: I wrote it)
by s_gourichon 6y ago
Well, while certainly imperfect, some like SDCC are good enough to write some games with nontrivial logic.
Here’s an open source game (disclosure: I wrote it) that compiles with SDCC and runs a game involving a flood fill algorithm, a tiny GUI with checkboxes and buttons and only one assembly routine, all running on the Amstrad CPC464 and above:
https://github.com/cpcitor/color-flood-for-amstrad-cpc https://github.com/cpcitor/color-flood-for-amstrad-cpc
It’s much easier to write and much faster (and probably smaller) to run than the same in BASIC.
- loeg 6y agoFrom what I've heard, SDCC generates pretty bad z80 code. It might be good enough if your application isn't super demanding.
- vardump 6y agoWrite in C and implement portions requiring higher performance in assembler. Nineties style.
- s_gourichon 6y agoThe whole point of the project was to go from "from what I've heard" to "I observe (and it's remarkable)". Write non-trivial code, see it run, look at the generated ASM. You can git clone the project above in a Debian/Ubuntu or similar, do "make" and have a look at the .lst listing of generated assembly with opcode bytes. I consistently observed that while z88dk produced extremely verbose code, with many steps back and forth and many extra push and pop, SDCC produced sane code. Of course it helps a lot when you "const" all relevant variable, and "const type const (star)" all relevant pointers when applicable, when you use uint8_t instead of int. Else generated code is heavy because it pays the code of high genericity that is probably not necessary. Help the compiler and, if it's a good compiler, it will help you. SDCC is a good compiler in this regard. This is especially important in the Z80 context because registers are smaller than the default integer types. I observed good code produced by SDCC. Too long to explain here but for example it allocates local variables to registers when applicable and code is somehow close to hand-written code (like in answers of the SO question). For example, it replaces a memset() C function call with this code which fits what one SO answer calls "kind of code one writes where optimization does not matter", which z88dk could not do: 243 ;model.c:132: memset( &connections, 0, sizeof( connections ) ); 00A2 21r68r00 [ 3] 244 ld hl, #_connections 00A5 06 19 [ 2] 245 ld b, #0x19 00A7 246 00244$: 00A7 36 00 [ 3] 247 ld (hl), #0x00 00A9 23 [ 2] 248 inc hl 00AA 10 FB [ 4] 249 djnz 00244$ (you might have zeroed a and done ld (hl),a, or even ldir, but this is still correct code) The next one below looks like it's easy. It is, if the compiler can figure out what is constant, and because you write sane C code. Garbage C code would yield garbage ASM code. Line uint8_t column = 20 - ( sizeof( message ) - 1 ) / 2; below yields no code, zero bytes. push de is the C ABI Code: [Select] 63 ;uint8_t column = 20 - ( sizeof( message ) - 1 ) / 2; 64 ;testfixture.c:23: fw_txt_set_cursor( 2, column ); 4058 11 02 03 [ 3] 65 ld de, #0x0302 405B D5 [ 4] 66 push de 405C CD 43 41 [ 5] 67 call _fw_txt_set_cursor Another Z80-specific consideration: Z80 is not made to access data off a stack. From the 8080 it added IX and IY index registers. You can `ld someregister, (ix-+127)` and family. They are somehow handy (somehow short code) but slow. SDCC uses this extensively. Chart of Z80 instruction timings: https://wiki.octoate.de/lib/exe/fetch.php/amstradcpc:z80_cpc_timings_cheat_sheet.20131019.pdf https://wiki.octoate.de/lib/exe/fetch.php/amstradcpc:z80_cpc... Z80 is more comfortable with all-fixed-addresses code. In a function, making local variables static kills the reentrancy but then you can replace the slow `ld someregister, (ix-+127)` with faster and shorter `ld a,(someaddress)`. I observed 20% reduction in SDCC-generated code in a big algorithmic function, which is attributable both to Z80 constraints and ability of SDCC somehow navigate those decently. In complex functions, code generated by SDCC is not extremely nice, but it's decent. It'd good enough so that only the performance-critical parts have to be written in assembly. On another side, SDCC supports most (all?) of C11. I've tested it, you can e.g. print(var) like you'd stdout << var in C++ and let the compiler do what you mean. Unusual in a microcontroller context.