ColecoVision

colecovision.eu

ColecoVision

STM8

MCS-51

LLVM+SDCC

Contact

Ein kleiner Überblick zu sdcc

Ein paar Worte dazu, was den sdcc nutzenden C-Programmierer zur Zeit (sdcc 3.4.0) so erwartet.

Allgemeines

sdcc ist ein C-Compiler, der versucht, sich weitgehend an die Standards (ISO C90, ISO C99, ISO C11) zu halten. Innerhalb der Spielräume, die der Standard läßt, wird gelegentlich anders als bei gcc vorgegangen. Üblicherweise dürfte man im C99-Modus (Kommandozeilenoption --std-c99) arbeiten wollen. sdcc ist auf 8-Bit-Architekturen ausgelegt, und kann halbwegs effizienten Code für diese erzeugen. Leider fehlen noch ein paar Features aus den Standards, allerdings hauptsächlich solche, die auf 8-Bit Microcontrollern eher selten verwendet werden.

sdcc ist ausgereifte Software, es gibt selten schwere Bugs. Nächtlich laufen regression tests auf verschiedenen Plattformen, d.h. es werden kleine C-Programme mit sdcc auf verschiedenen Architekturen und Betriebssystemen für verschiedene Zielarchitekturen kompiliert, und dann im Simulator ausgeführt, um zu testen, ob sie sich korrekt verhalten. Ein paar der Tests wurden bei der Implementierung von Features in sdcc geschrieben. Aber die meisten stammen aus Bug reports: Wenn ein Bug in sdcc behoben wird, wird ein regression test geschrieben, um sicherzustellen, das dieser Bug nicht wieder auftreten kann. Außerdem wurden viele regression tests von gcc übernommen.

Optimierung

Die wichtigsten Optionen zur Optimierung sind --opt-code-size, --opt-code-speed und --max-allocs-per-node. Mittels --opt-code-size bzw. --opt-code-speed läßt sich das Optimierungsziel wählen. Die Option --max-allocs-per-node dient dazu, einen Wert anzugeben, der festlegt, wieviel Aufwand sdcc zur Optimierung treibt. Der Standardwert ist 3000. Je größer der Wert, desto mehr Mühe gibt sich sdcc bei der Optimierung.

Ports

Portmcs51, ds390hc08, s08z80, z180, r2k, r3kagbz80tlcs90pic14, pic16stm8
Funktionen reentrentOptionOptionJaJaJaOptionJa
Registerallokatoraltneu (alt)neu (alt)neuneu (alt)altneu
Regression TestsJaJaJaJaNeinNeinJa

Bei manchen ports sind Funktionen nur reentrent, wenn explizit angegeben (per Schlüsselwort oder Kommandozeilenoption). Bei Ports, die den neuen Registerallokator verwenden, hat --max-allocs-per-node deutlich größeren Einfluß. Bei Ports, bei denen der alte Registeralloaktor in Klammern angegeben ist, kann er mittels --oldralloc gewählt werden. Der alte Registerallokator ist üblicherweise schneller, erzeugt aber schlechteren Code. Beides ist bei hohen Werten für --max-allocs-per-node am stärksten spürbar.

mcs51- und ds390-port

mcs51 und ds390 sind relativ alte Ports. Soweit ich weiß, sind sie recht stabil, aber es gibt hie und da ein paar fehlende Features, die in anderen Ports drin sind. An manchen Ecken wurde zugunsten von Speicherplatzeffizienz gegen Standardkompatiblität entschieden (bool als bit impementiert).

hc08- und s08-port

Auch hc08 und s08 sind etablierte, stabile ports. Da der s08 port aus dem hc08 port entwickelt wurde, mag es hie und da noch ungenutzes Optimierungspotential geben. Der erzeugte Code ist recht gut, aber üblicheweise etwas größer als bei den nichtfreien Compilern.

z80-, gbz80-, r2k-, r3ka-, und tlcs90-port

Der Z80-Port ist recht alt, hat aber im Laufe der Zeit bedeutende Verbesserungen erfahren. Die anderen (z180, gbz80, r2k, r3ka, tlcs90) Ports sind daraus entwickelt worden. Der tlcs90-Port hat keinen Simulator, und wird daher von den regression tests nicht erfasst. Recht effizienter Code wird generiert für z80, z180, r2k. Bei den anderen gibt es noch etwas mehr ungenutzes Potential. Im Vergleich zu den nicht-freien Compilern erzeugt sdcc üblicherweise besseren Code als CROSS-C und HITECH-C, aber etwas schlechteren als IAR.

Manche dieser Prozessoren haben ein paar komplexe Instruktionen, wie z.B. ldir. Für einen Compiler ist es nicht einfach, zu erkennen, wann z.B. eine Schleife mit Hilfe ldir effizienter implementiert werden könnte. Die Befehle werden aber in den Bibliotheksfunktionen (z.B. memmove()) genutzt. Und für manche Bibliotheksfunktionen (memcpy(), strcpy(), strncpy(), strchr(), memset()) wird, wo möglich, auch kein Funktionsaufruf erzeugt, sondern direkt Code generiert.

Da der Z80 nur ein Prozessor, kein ganzes System ist, gibt es ein paar Dinge, die der Programmierer selbst erledigen muß (z.B. Speicherinitialisierung), die ihm bei anderen Ports von sdcc abgenommen werden. Dazu dient die crt0. Als Beispiele können dir crt0.s von sdcc (sdcc/device/lib/z80/crt0.s) oder aus der libcv für ColecoVision dienen.

pic14, und pic16-port

Die pic-ports hinken den anderen Ports weit hinterher. Etwas die Hälfte der offenen Bugreports in sdcc bezieht sich auf pics.

Es gibt den pic14-port für die pics mit 14-bit Instruktionen (z.B. 16Fxxx, 12Fxxx) und den pic16 für die pics mit 16-bit Instruktionen (z.B. PIC18Fxxx). Wobei der pic16-port sich deutlich besser schlägt als der pic14 port. Der pic16 port ist kurz davor, in die nächtlichen regression tests aufgenommen zu werden. Der pic14-port ist weit davon entfernt. In beide ports müßte noch viel Arbeit reingesteckt werden.

stm8-port

Dies ist der neueste Port. Einerseits schleppt er weniger Altlasten mit sich herum als die anderen, andererseits könnte es noch den einen oder anderen Bug mehr, und etwas mehr ungenutzes Optimierungspotential geben. Aber er besteht die regression tests, und erzeugt kompakteren Code als die anderen Ports. Im Vergleich zu den nichtfreien Compilern ist der erzuegte Code aber dennoch oft 10 bis 20 Prozent größer.

Es gibt auch ein paar einfache Tutorials zur Verwendung von sdcc für den stm8.