uprintf mit Festkomma
Eine printf-Implementierung in avr-gcc-Assembler.
Benötigt nur 390 Byte Kode,
gemessen ohne Zeichenausgaberoutine.
Motivation
printf
ist prinzipiell
nicht so toll für kleine Mikrocontroller geeignet.
Es ist für Programme mit Betriebssystemumgebung gemacht
(„hosted“), nicht für Programme ohne Betriebssystem
(„freestanding“).
Nervig ist:
- Die schiere Größe der
drei
mit avr-gcc mitgelieferten
printf
-Implementierungen
- Die Gleitkommabibliothek, die man nur
für die Anzeige braucht,
und die Umstände via
sprintf
,
um das Komma einzupopeln
- Das Punkt-Komma-Problem
Wünschenswert ist:
- Geringe Größe der
printf
-Funktion,
ohne externe Referenzen
- Festkommazahlenausgabe wahlweise mit Punkt oder Komma
printf
und
printf_P
in einer Funktion
- String-Alternativen der Form
"%{falsch|wahr}"
,
d.h. '{'
als neues Formatierungszeichen.
Dies wurde hier nicht implementiert.
Sondern bei (m)einem Raspberry-Programm.
- Freie Wahl der Zeichenausgabefunktion
Implementierungsdetails
Die Funktion vuprintf
ist nur von Assembler aus aufrufbar.
- Parameter-Eingabe und externe Symbole:
- Z = Formatstring-Zeiger im RAM oder (+0x8000) im Flash
- Y = Parameterliste, wie sie bei
printf
auf den Stack gelangt, wie va_list
- X = freies Zeigerregister für
chrout
chrout
= Funktion zur Zeichenausgabe in Assembler oder Inline-Assembler.
- Parameter-Eingabe:
- R24 = auszugebendes Zeichen
- X = Zeigerregister
- Parameter-Ausgabe:
- X = (ggf. verändertes) Zeigerregister
- Muss retten:
- Zusätzlich zu gcc-ABI Z und W18 (=R19:R18)
read_byte_pp
= Funktion zum Byte-Lesen von einer von-neumannisierten Adresse.
Bereits eingebaut, aber wer will kann ja noch EEPROM-Zugriff u.ä. einbauen!
- Parameter-Eingabe:
- Parameter-Ausgabe:
- R0 = gelesenes Byte
- Z = vorgerücktes Zeigerregister (je nach Logik nicht unbedingt um 1 vonnöten)
- Muss retten:
- Parameter-Ausgabe
- Z = vorgerückter Formatstring-Zeiger hinter '\0' (da könnte der nächste Formatstring stehen)
- Y = vorgerückter Zeiger in Parameterliste
- X = ggf. von
chrout
vorgerücktes Zeigerregister
- Versaut:
- R16..R25, zurzeit (ohne long-Unterstützung) W20 nicht. R17 = 0.
Die Funktion uprintf
, ein Wrapper für vuprintf
,
ist ganz normal von C/C++ aufrufbar.
Die Funktion chrout
muss selbst geschrieben werden
und ist nicht Teil der Assemblerroutine.
Mit dem Zeigerregister X ist viel Flexibilität gegeben, etwa:
- Der Wert 0 routet das Zeichen zur seriellen Schnittstelle,
- Der Wert 1 routet das Zeichen zum HD44780-kompatiblen Display,
- Jeder andere Wert schreibt in den RAM und wird inkrementiert, dadurch entsteht
sprintf
,
- Oder X ist ein Funktionszeiger, oder eine Lambdafunktion ohne Capture
- Oder X adressiert eine
struct
mit einem Ausgabemethodenzeiger,
faktisch eine Lambdafunktion mit Capture,
- Oder X adressiert ein abgeleitetes Objekt einer virtuellen Basisklasse,
ähnlich Lambdafunktion mit Capture aber noch eine weitere
Indirektion mittels VMT.
Implementierung
Implementierungen
8051 | PIC | AVR | C166 |
- | - | uprintf.S | -
|