Forum: Mikrocontroller und Digitale Elektronik SDCC für Z80: Wie überschreibt man printf / putchar?


von Christian J. (Gast)


Lesenswert?

Hallo,

ist irgendwie blöde extra einen Thread dafür aufzumachen aber es stellt 
sich die Frage wie man bei der printf Funktion die Standardausgabe 
überschreibt? Bzw. überhaupt herausfindet welches diese ist? Denn die 
z80.lib liegt nur in kompilierter Form vor und da liegt die drin. Im 
Manual wird nur vom mcs51 gesprochen und das ist ein Controller mit 
Uart, der Z80 aber ein Prozessor ohne Peripherie.

Reicht es eine eigene putchar (char c) irgendwo im Source zu haben? Oder 
muss man den Umweg über sprintf(buffer,...) gehen und dann über die 
eigene putchar ausgeben?

Gruss,
Christian

von Leo C. (rapid)


Angehängte Dateien:

Lesenswert?

Christian J. schrieb:
> Hallo,
>
> ist irgendwie blöde extra einen Thread dafür aufzumachen aber es stellt
> sich die Frage wie man bei der printf Funktion die Standardausgabe
> überschreibt?

Use the Source Luke.

> Bzw. überhaupt herausfindet welches diese ist?

UTSL

> Denn die z80.lib liegt nur in kompilierter Form vor und da liegt die
> drin.

Du behauptest allen Ernstes, ein Open Source Compiler würde ohne 
Sourcecode der zugehörigen libs veröffentlicht?

> Reicht es eine eigene putchar (char c) irgendwo im Source zu haben?

Klar, wenn Du dafür sorgst, daß der Linker Deine nimmt, statt der 
Version aus der libc. Du kannst auch die libc-Version austauschen, oder 
die letztere mal anschauen (Anhang, liegt bei Debian in 
/usr/share/sdcc/lib/src/z80). Die läd das auszugebende Zeichen in 
Register L und ruft einen RST 08 auf. Dies dürfte wohl auf die 
Debugger-Umgbung mit ucsim abgestimmt sein.

von Christian J. (Gast)


Lesenswert?

Und wenn man sich da mal durchwühlt durch die printf findet man heraus, 
dass immer auf eine outputchar() vom Typ pfn_outputchar verwiesen wird 
und wohin die ausgibt erklärt sich zumindest mir nich aus dem Kontext.
1
#ifndef SDCC_STACK_AUTO
2
  static BOOL lower_case;
3
  static pfn_outputchar output_char;
4
  static void* p;
5
  static value_t value;
6
  static int charsOutputted;
7
#endif
8
9
#ifdef SDCC_STACK_AUTO
10
  #define OUTPUT_CHAR(c, p) { output_char (c, p); charsOutputted++; }
11
#else
12
  #define OUTPUT_CHAR(c, p) _output_char (c)
13
  static void
14
  _output_char (unsigned char c)
15
  {
16
    output_char( c, p );
17
    charsOutputted++;
18
  }
19
#endif

von Leo C. (rapid)


Lesenswert?

Christian J. schrieb:
> Und wenn man sich da mal durchwühlt durch die printf findet man heraus,
> dass immer auf eine outputchar() vom Typ pfn_outputchar verwiesen wird
> und wohin die ausgibt erklärt sich zumindest mir nich aus dem Kontext.

Der Funktionszeiger heißt output_char und nicht outputchar. Kein 
Wunder, daß Du so nichts findest. Außerdem ist das nicht "immer" so, 
sondern nur in 'printf_large.c', und nicht in den anderen Varianten.
Für Z80 ist das aber die einzig interessante Variante.
1
> #ifndef SDCC_STACK_AUTO

Da der Z80 einen vernünftigen Stack hat, ist dieses Macro 
sinnvollerweise immer defined. Also können wir alles mit SDCC_STACK_AUTO 
undefined ausblenden.
1
> #ifdef SDCC_STACK_AUTO
2
>   #define OUTPUT_CHAR(c, p) { output_char (c, p); charsOutputted++; }
3
> #else
Wenn wir uns mal auf die Funktion konzentrieren, die hier die 
Hauptarbeit leistet:
1
int
2
_print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
3
{
dann finden wir hier:
1
#ifdef __SDCC_STACK_AUTO
2
  #define output_char   pfn
3
  #define p             pvoid
4
#else
Die Funktion, die ein Zeichen ausgibt, wird als erster Parameter ('pfn') 
an _print_format() übergeben.

_print_format() wird von printf(), vprintf(), sprintf() und vsprintf() 
aufgerufen.
Den Rest findest Du selber.

von S. R. (svenska)


Lesenswert?

Vielleicht solltest du die Antworten auf deine Frage mal lesen. Ich habe 
dir sogar mal funktionierenden Beispielcode für printf mit SDCC und SFRs 
vor die Nase geworfen. Den hast du aber ignoriert und nach "mehr 
Beispielcode" gefragt. Mehr Silbertablett gibt's von mir nicht.

Tipp: Ausprobieren. Einfach mal ein printf("hallo welt") programmieren. 
Das sollte dir einen Linkerfehler schenken, aus dem du genau rauslesen 
kannst, was du tun musst, um printf auf deinem System hinzubekommen. So 
ein bisschen C hinklappern solltest du schon können.

von Christian J. (Gast)


Lesenswert?

@S.R. Ich kenne den Codefetzen, das funktioniert aber nicht mehr. Wüsste 
auch keinen Grund warum er deine putchar nehmen sollte.

Macht man es so, erhält man im map File den Veweis auf die eigene 
Routine. Eine manuelle Suche im Hex Dump Code ergab, dass es keinen CALL 
/ JMP etc auf meine putchar gibt.
1
Files Linked                              [ module(s) ]
2
3
main.rel                                  [ main ]
4
crt0.rel                                  [ crt0 ]
5
6
7
Libraries Linked                          [ object file ]
8
9
/usr/local/bin/../share/sdcc/lib/z80/z80.lib
10
                                          [ vprintf.rel ]
11
/usr/local/bin/../share/sdcc/lib/z80/z80.lib
12
                                          [ printf_large.rel ]
13
/usr/local/bin/../share/sdcc/lib/z80/z80.lib
14
                                          [ strlen.rel ]
15
/usr/local/bin/../share/sdcc/lib/z80/z80.lib
16
                                          [ crtcall.rel ]

Das einzige was zu finden ist, ist das hier in einer putchar.s. Und das 
ist einkompiliert in die Z80-Lib.  Also würde mir nur noch einfallen die 
putchar.s als eigenes File mit einzulinken, getrennt zu übersetzen und 
in Asm dort meine Uart anzusprechen.

Und wenn alles nicht geht eben printf(buf,....)

Ich hätte sicher nicht gefragt, wenn ich es wüsste.  Egal, ich kriege es 
sicher irgendwann raus....

putchar::
_putchar_rr_s::
        ld      hl,#2
        add     hl,sp

        ld      l,(hl)
        ld      a,#1
        rst     0x08

        ret

_putchar_rr_dbs::
        ld      l,e
        ld      a,#1
        rst     0x08

        ret

von Leo C. (rapid)


Lesenswert?

S. R. schrieb:
> Vielleicht solltest du die Antworten auf deine Frage mal lesen. Ich habe

Im sdcc-Forum auf Sourceforge wurde ihm ja auch noch ein möglicher Weg 
gezeigt...

Christian J. schrieb:
> Macht man es so, erhält man im map File den Veweis auf die eigene
> Routine.
> Eine manuelle Suche im Hex Dump Code ergab, dass es keinen CALL
> / JMP etc auf meine putchar gibt.

Kunststück, putchar wird ja über einen Funktionspointer aufgerufen. 
Schon vergessen?
Du kanst ja mal in Deinem Hexdump nach E9 suchen, Opcode für 'JP (HL)'. 
Und dann nach den Stellen, an denen ein Call darauf steht.

> Das einzige was zu finden ist, ist das hier in einer putchar.s. Und das
> ist einkompiliert in die Z80-Lib.

Das putchar() aus der Lib wird aber nicht verwendet, wenn der Linker ein 
anderes findet. Ansonsten bekämst Du nämlich einen "Multible defined 
error" oder so.

> Also würde mir nur noch einfallen die
> putchar.s als eigenes File mit einzulinken, getrennt zu übersetzen

In welcher Datei die Funktion (das Symbol) steht, ist dem Linker völlig 
Wurst.

> und in Asm dort meine Uart anzusprechen.

Ob C oder Assembler ist auch Wurst.

von S. R. (svenska)


Lesenswert?

Christian J. schrieb:
> @S.R. Ich kenne den Codefetzen, das funktioniert aber nicht mehr. Wüsste
> auch keinen Grund warum er deine putchar nehmen sollte.

Vielleicht, weil ein Überschreiben von putchar einfach mal vorgesehen 
ist. Der Linker ist vielleicht nicht ganz so intelligent wie ein Sack 
Holz, aber schwach definierte Symbole kennt er immerhin. Aber gut, wer 
nicht will der hat schon. Ich klinke mich dann mal aus.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.