mikrocontroller.net

Forum: Compiler & IDEs Mehrdimensionale char-arrays


Autor: micha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Folgendes geht ohne Angabe der Feldgröße:
char abc[]={"hallo"};
char def[]="hallo";
char *ghi={"hallo"};
char *jkl="hallo";

Folgende Beispiele gehen jedoch nicht:
char abc[][]={"compiler", "meckert"};
char def[2][]={"compiler", "meckert"};
char ghi[][9]={"compiler", "meckert"};

Wieso kann wenigstens für "char def" nicht automatisch die Feldgröße
(Stringlänge) ermittelt werden?

Das hier geht allerdings wieder ohne jegliche Feldgrößenangabe:
char *abc[] = {"so", "klappt", "es"};
printf(abc[2]);  //Ausgabe: "es"

Wieso? die subtilen Regeln von C sind mir nicht klar. Vielleicht kann
mich jemand erhellen... Danke

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wieso kann wenigstens für "char def" nicht automatisch die
Feldgröße
> (Stringlänge) ermittelt werden?

ghi funktioniert anstandslos.  Die Stringlänge mehrerer Strings kann
er nicht automatisch ermitteln, aber die erste Felddimension kann
automatisch an Hand der Initializer ermittelt werden.  Aber das
mehrdimensionale Array ist für Zeichenketten ohnehin keine sehr
praktikable Lösung.

> Das hier geht allerdings wieder ohne jegliche Feldgrößenangabe:
> char *abc[] = {"so", "klappt", "es"};

Klar, jetzt bist du ja auch von einem mehrdimensionalen Array (of
char) übergegangen zu einem eindimensionalen (of pointer to char).
Das hat den zusätzlichen netten Effekt, dass du im Gegensatz zum
mehrdimensionalen Array nicht N-mal den Platz für den längsten String
allozierst, sondern N-mal den Platz für einen Zeiger, während die
Strings selbst ausschließlich den für ihre Darstellung notwendigen
Platz belegen.

Autor: micha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
char ghi[][9] als vermeintlich falsch ist mir glatt durchgegangen.
Vielen Dank für die Erklärung und den Hinweis auf Speicherbedarf! :-)

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
> Wieso? die subtilen Regeln von C sind mir nicht klar. Vielleicht
> kann mich jemand erhellen... Danke

Im Grunde ist das Prinzip sehr simpel:
Wenn du ein mehrdimensionales Feld anlegst, dann muss
der Compiler dass irgendwie im Speicher unterbringen.
Er macht das so, dass er die einzelnen Elemente der
2-ten Dimension einfach aneinanderhängt.
char Test[2][3];

  Test
  +---+---+---+---+---+---+
  |   |   |   |   |   |   |
  +---+---+---+---+---+---+
    0   1   2   0   1   2

   |          |          |
     das hier    und hier
   ist Test[0]    Test[1]
man sagt auch: "der letzte Index läuft am schnellsten"
Die Elemente [0][0], [0][1], [0][2] liegen also direkt
hintereinander, gefolgt von [1][0], [1][1], [1][2]
usw.

Wenn du daher auf ein Element [a][b] zugreifst, muss
der Compiler ausgehend von der Startadresse des Arrays
rechnen:
    Adresse von [a][b] = Startadresse +
                         a * Dimensionierung der 2.ten Dimension +
                         b
Um also die Adresse berechnen zu können, muss der Compiler wissen
wie gross den die 2. te Dimension tatsächlich ist.
Bei
 
  char Test[2][3]
wäre das die 3.

Nun hätte man natürlich für char-Arrays als Sonderfall
zulassen können, dass der Compiler die Abzählerei macht.
Schliesslich ist alles dazu Notwendige in der Initialisierung
enthalten. Ich denke aber man wollte sich einfach keinen
Sonderfall einhandeln.

Übrigens: Bei
  char *abc[] = {"so", "klappt", "es"};
wird etwas völlig anderes im Speicher aufgebaut.
Das sieht dann so aus
    abc
   +-----+        +---+---+----+
   |  o---------->| s | o | \0 |
   +-----+        +---+---+----+   +---+---+---+---+---+---+----+
   |  o--------------------------->| k | l | a | p | p | t | \0 |
   +-----+                         +---+---+---+---+---+---+----+
   |  o-----------+
   +-----+        |
                  |    +---+---+----+
                  +--->| e | s | \0 |
                       +---+---+----+
Die einzelnen Strings liegen also irgendwo im Speicher und
werden nur durch das Pointer-Array zusammengehalten.

: Bearbeitet durch Moderator
Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gut erklärt Karl Heinz, gefällt mir :-)

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dafür ist er bekannt.

Autor: Paul H. (powl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Thread ist zwar schon alt aber Karls Erklärung hat mich grad auch 
begeistert, besonders die netten ASCII Zeichnungen^^ (hast du die per 
Hand eingetippt? xD)

lg PoWl

Autor: emacs (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In nem emacs mit Mausunterstützung kann man die malen :D

Autor: Kay I. (imperator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin zusammen,

wie müsste ich folgendes Problem angehen ...
ein Liste von Strings in verschiedenen Sprachen:
const char str_de[][15+1]={
"Text in deutsch" // info
"hallo Welt     " // hello
}

const char str_en[][15+1]={
"text in english" // info
"hello world    " // hello
}

char **str_ptr;

(...)
// Initialisierung
if(language == deutsch){
 str_ptr = str_de;
}
else{
 str_ptr = str_en;
}

(...)
// main loop
print(str_ptr[0]);
print(str_ptr[1]);

Bei der Zuweisung des Pointers schimpft der Compiler, weil die Typen 
nicht zusammenpassen. Wie muss der Pointer aussehen, damit ich ihn auf 
die Stringliste der jeweiligen Sprache zeigen lassen kann?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
const char* str_de[] = {
 "Text in deutsch" // info
 "hallo Welt     " // hello
}

const char* str_en[] = {
  "text in english" // info
  "hello world    " // hello
}

const char** str_ptr;

(...)
  // Initialisierung
  if(language == deutsch){
    str_ptr = str_de;
  }
  else {
   str_ptr = str_en;
  }
 
  (...)
  // main loop
  print(str_ptr[0]);
  print(str_ptr[1]);


Merke: Ein Pointer ist kein Array. Ein 2-D Array, so wie du es hattest, 
ist daher auch kein Array von Pointern auf Strings. Daher kann str_ptr 
auch kein Pointer auf einen Pointer sein. Aber du kannst deine 
Textarrays so umbauen, dass es sich tatsächlich um ein Array von 
Pointern handelt.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
z.B. so:
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>

enum
{
  deutsch,
  english,
} language = english;


int main( int nargs, char **args )
{
  const char *str_de[] =
    {
      "Text in deutsch",  // info
      "hallo Welt",       // hello
    };

  const char *str_en[] =
    {
      "text in english",  // info
      "hello world",      // hello
    };

  const char **str_ptr;

  // Initialisierung
  if(language == deutsch){
    str_ptr = str_de;
  }
  else{
    str_ptr = str_en;
  }

  // main loop
  printf( "%s\n", str_ptr[0] );
  printf( "%s\n", str_ptr[1] );

  return 0;
}

Autor: Kay I. (imperator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wow ... da habt Ihr schnell geantwortet - Vielen Dank!

ich werde es genau so probieren ... gebe dann Bescheid!

Autor: Kay I. (imperator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
prima!

Das ist genau so, wie ich es mir vorgestellt habe:
An einer zentralen Stelle werden alle Strings gesammelt und
an einer zentralen Stelle wird über die Sprache entschieden.

Vielen Dank!

Autor: Mark M. (mom-jovi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

mein Compiler meckert bei einer einfache Initialisierung eines 
mehrdimensionalen char-Arrays:

struct spielfeld
{
    char koord[9][9] =  {{'x','A','B','C','D','E','F','G','H'},
                        {'A','0','0','0','0','0','0','0','0'},
                        {'B','0','0','0','0','0','0','0','0'},
                        {'C','0','0','0','0','0','0','0','0'},
                        {'D','0','0','0','0','0','0','0','0'},
                        {'E','0','0','0','0','0','0','0','0'},
                        {'F','0','0','0','0','0','0','0','0'},
                        {'G','0','0','0','0','0','0','0','0'},
                        {'H','0','0','0','0','0','0','0','0'}};
};

Dabei bringt er die Meldung
"error: exspected ':', ',', ';', '}' or '__attribute__' before '=' 
token"
und bezieht sich auf die dritte Zeile.

Ich habe den GNU GCC Compiler. Kann mir da jemand weiterhelfen? Ich hab 
absolut keine Ahnung, habe mehrmals alles abgesucht, aber diese Meldung 
hilft mir garnichts. Danke!

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du legst ja auch nur eine Stuct an und keine Variable.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eben. Bei der Deklaration einer Struktur kann nicht gleichzeitig ein 
Teil davon initialisiert werden.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... und so sieht es besser aus:
struct spielfeld
{
    char koord[9][9];
} meinSpielfeld =  {{{'x','A','B','C','D','E','F','G','H'},
                     {'A','0','0','0','0','0','0','0','0'},
                     {'B','0','0','0','0','0','0','0','0'},
                     {'C','0','0','0','0','0','0','0','0'},
                     {'D','0','0','0','0','0','0','0','0'},
                     {'E','0','0','0','0','0','0','0','0'},
                     {'F','0','0','0','0','0','0','0','0'},
                     {'G','0','0','0','0','0','0','0','0'},
                     {'H','0','0','0','0','0','0','0','0'}}};
Zu gefälligen Beachtung die Variable meinSpielfeld und das
zusätzliche {}-Paar.

Autor: Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen!

In meinem Projekt habe ich eine Funktion, die aus eine SD-Karte eine
Liste von ersten 16 Dateinamen ausliest und diese in einem
2D-Char-Array (Files[16][16]) abspeichert. Das klappt auch.

Jetzt wollte ich die Funktion so umschreiben, das ich diesen Array als 
parameter an die Funktion übergebe.

Einzigste Methode die bei mir klappt, einen Pointer auf Files[0][0] 
übergeben und jedes Byte manuell füllen. Das heisst erste Dateiname 
(z.B. 6 char lang) schreibe ich in Adresse 0 bis 5 + '0' in die Adresse 
6. Zweite in die Adresse 16 bis xx u.s.w.

Gibt es eine schönere Methode so einen Array zu Füllen?

MfG

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wärst du so nett, für eine neue Frage einen neuen Thread aufzumachen?

Es sei denn, deine Frage ist hier schon beantwortet.
Dann musst du nur lesen, und nicht fragen.

Autor: Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Problem habe ich gerade gelöst. Habe nochmal bei Wikibook den 
Kapitel "Zeiger & Arrays" durchgelesen.

Klaus Wachtler schrieb:
> Wärst du so nett, für eine neue Frage einen neuen Thread aufzumachen?

Nächstes mal mache ich!

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich wühl das hier nochmal raus, da es echt nicht so einfach ist die 
passende Syntax zu finden.

Das sollen meine Strings sein, die über einen Zeiger erreichbar sein 
sollen. Mit mehrdim. Array will ich nicht anfangen.
const char *menue[]=
{
    "Z80 System is online!\n",        // 0
    "---------------------------------"    // 1
    "\n(1)...........Load User Program",  // 2
    "\n(2)...........Start User Program",  // 3
    "\n(3)...........Clear Memory",      // 4
    "\n(4)...........Dump Memory",      // 5
    "\n(5)...........Restart System"    // 6
};

Damit sollen sie an die Uart geschickt werden
for (i=0;i<6;i++) {
  printstrng(menue[i]);
[code]

UNd das ist der Code für Strings drucken

[code]

/////////////////////////////////////////////////////////
// Zeichenketten ausgabe auf Uart
void printstrng(char *k)
{
  while ((*k) != '\0')
    putchar(*(k++));
}

Es kommt nur Müll auf dem Display, weil die Zeiger vermutlich in den 
Binärspeicher zeigen.

Es gibt eine warning: pointer target lost const qualifier.

Was nun?

: Bearbeitet durch User
Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was hat das (außer üblem Quelltext) mit dem bisherigen Thread zu tun?
Es wäre vielleicht gechickter, einen neuen aufzumachen ...

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich wüsste nicht was an meinem Quelltext übel ist. Der ist so dass er 
seine Aufgabe effzient erfüllt. Und es passt thematisch hier rein, 
deswegen erzeuge ich keinen neuen Thread.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Ich wüsste nicht was an meinem Quelltext übel ist.

An dem Quelltext ist z.B. übel, dass da ein Komma fehlt. Dadurch 
verrutscht Dir einiges im Array. menue[5] ist damit u.U. gar nicht 
initialisiert.

P.S.
Die Warnung eliminierst Du, indem Du schreibst:

void printstrng(const char *k)
...

Schließlich handelt es sich hier um const.

: Bearbeitet durch Moderator
Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank M. schrieb:
> Christian J. schrieb:
>> Ich wüsste nicht was an meinem Quelltext übel ist.
>
> An dem Quelltext ist z.B. übel, dass da ein Komma fehlt. Dadurch
> verrutscht Dir einiges im Array. menue[5] ist damit u.U. gar nicht
> initialisiert.
>

Da fehlt kein Komma ;). Keiner hat gesagt, daß das Array so belegt sein 
muß, wie's auf den ersten Blick im Quelltext aussieht.

Die Schleife läuft nur von 0 bis 5. Wär' da ein Komma, würde die letzte 
Zeile nicht mit ausgegeben werden.

Für mich stellt sich die Frage, warum hier überhaupt ein Array verwendet 
wird, das läßt doch genausogut auf einen Rutsch ausgeben?

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus F. schrieb:
> Die Schleife läuft nur von 0 bis 5. Wär' da ein Komma, würde die letzte
> Zeile nicht mit ausgegeben werden.

Stimmt, Du hast recht. Trotzdem glaube ich nicht, dass genau das im 
Sinne des Erfinders war. Sieht jedenfalls erstmal nicht so aus.

Das Programm läuft bei mir unter Linux einwandfrei - jedenfalls das, was 
da an Auszügen gepostet wurde. Fragt sich nur, ob das verwendete Display 
die putchar()-Befehle genauso umsetzt wie ein herkömmliches Terminal.

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Frank M. schrieb:
> Das Programm läuft bei mir unter Linux einwandfrei -

Das glaube ich, bei mir auch. Nur ist das der SDCC Compiler für den Z80 
und inzwischen weiss ich, dass die warning ein Bug ist. Ich werde also 
um einen Workaround nicht herum kommen. Oder mich durch den Asm Code 
wühlen, der erzeugt worden ist.

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ersetzt man i durch eine Zahl 0 im Funktionsaufruf, um es einfacher zu 
verstehen spuckt er das aus:

                         727 ;main.c:99: for (i=0;i<6;i++) {
   0203 16 00         [ 7]  728   ld  d,#0x00
   0205                     729 00107$:
                            730 ;main.c:100: printstrng(menue[0]);
   0205 2Ar00r00      [16]  731   ld  hl, (#_menue + 0)
   0208 D5            [11]  732   push  de
   0209 E5            [11]  733   push  hl
   020A CDr20r00      [17]  734   call  _printstrng
   020D F1            [10]  735   pop  af
   020E D1            [10]  736   pop  de
                            737 ;main.c:99: for (i=0;i<6;i++) {
   020F 14            [ 4]  738   inc  d
   0210 7A            [ 4]  739   ld  a,d
   0211 D6 06         [ 7]  740   sub  a, #0x06
   0213 38 F0         [12]  741   jr  C,00107$



                         788   .area _CODE
   0251                     789 ___str_0:
   0251 5A 38 30 20 53 79   790   .ascii "Z80 System is online!"
        73 74 65 6D 20 69
        73 20 6F 6E 6C 69
        6E 65 21

: Bearbeitet durch Moderator
Autor: Joachim B. (jar)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Übrigens: Bei  char *abc[] = {"so", "klappt", "es"};

geht das auch mit EEMEM ?

ich grübel immer noch wie ich ohne Abzählerei die Menüstrings 
platzsparend ins EEPROM bringe um dann wieder später zugreifen zu 
können.

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
>                          727 ;main.c:99: for (i=0;i<6;i++) {
>    0203 16 00         [ 7]  728   ld  d,#0x00
>    0205                     729 00107$:
>                             730 ;main.c:100: printstrng(menue[0]);
>    0205 2Ar00r00      [16]  731   ld  hl, (#_menue + 0)
>    0208 D5            [11]  732   push  de
>    0209 E5            [11]  733   push  hl
>    020A CDr20r00      [17]  734   call  _printstrng
>    020D F1            [10]  735   pop  af
>    020E D1            [10]  736   pop  de
>                             737 ;main.c:99: for (i=0;i<6;i++) {
>    020F 14            [ 4]  738   inc  d
>    0210 7A            [ 4]  739   ld  a,d
>    0211 D6 06         [ 7]  740   sub  a, #0x06
>    0213 38 F0         [12]  741   jr  C,00107$
>
>                          788   .area _CODE
>    0251                     789 ___str_0:
>    0251 5A 38 30 20 53 79   790   .ascii "Z80 System is online!"


Ich hab' zwar erst vor ungefähr 100 Jahren das letzte Mal Z80-Code 
angeguckt, kann aber da - zumindest auf Anhieb - keinen Fehler 
erkennen...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Frank M. schrieb:
>> Das Programm läuft bei mir unter Linux einwandfrei -
>
> Das glaube ich, bei mir auch. Nur ist das der SDCC Compiler für den Z80
> und inzwischen weiss ich, dass die warning ein Bug ist.

Auf einem Z80?

Das glaube ich ehrlich gesagt nicht.
Denn ein Z80 unterscheidet nicht zwischen Adressbereichen. Selbst wenn 
der COmpiler die Texte aufgrund ihrer Konstantheit irgendwo speziell im 
Adressberecih unterbringen würde, kann sie der Code nach wie vor über 
genau dieselben Befehle laden und bearbeiten, wie wenn sie im RAM liegen 
würden.

(NIcht gebanktes System mal vorausgesetzt)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mal ganz anders gefragt.
Hast du schon getestet, ob putchar() bzw. UART überhaupt richtig 
funktioniert?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Joachim B. schrieb:
> Karl heinz Buchegger schrieb:
>> Übrigens: Bei  char *abc[] = {"so", "klappt", "es"};
>
> geht das auch mit EEMEM ?
>
> ich grübel immer noch wie ich ohne Abzählerei die Menüstrings
> platzsparend ins EEPROM bringe um dann wieder später zugreifen zu
> können.


Müsste auch gehen.
Bei den Zugriffen musst du halt aufpassen, dass du nicht einfach 
drauflos arbeiten kannst, sondern mit den eprom Funktionen arbeiten 
musst, aber prinzipiell spricht da nichts dagegen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl Heinz schrieb:

> (NIcht gebanktes System mal vorausgesetzt)

Gerade gesehen:
Du hast ja ein komplettes Listing gepostet.
Das sieht eigentlich alles gut aus - wenn die UART grundsätzlich 
funktioniert. Davon schreibst du aber nichts. Die Stringausgaben sind 
soweit ich gesehen habe, die erste Ausgabe im Programm. Funktioniert die 
UART nicht (falsche Baudrate oder so), dann sind deine Strings beim 
Empfänger natürlich unleserlich. SChuld ist dann aber nicht die 
Stringausgabe an sich und auch nicht die Verpointerung, sondern Schuld 
daran ist dann, das die UART-Übertragung grundsätzlich nicht 
funktioniert.

: Bearbeitet durch Moderator
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Karl Heinz schrieb:
> Mal ganz anders gefragt.
> Hast du schon getestet, ob putchar() bzw. UART überhaupt richtig
> funktioniert?

Ja, einwandfrei. Ausgaben über prinft klappen. Ich habe alles stückweise 
durchgeprüft in der Kette der Glieder bis zmum PC hin. Die Ausgabe bei 
dem Beispiel, auch mit Komma ist Binärmüll auf dem Terminalprogram.

: Bearbeitet durch User
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Hase liegt her im Peffer:

                           730 ;main.c:100: printstrng(menue[i]);
   0205 6A            [ 4]  731   ld  l,d
   0206 26 00         [ 7]  732   ld  h,#0x00
   0208 29            [11]  733   add  hl, hl
   0209 01r00r00      [10]  734   ld  bc,#_menue
   020C 09            [11]  735   add  hl,bc
   020D 4E            [ 7]  736   ld  c,(hl)
   020E 23            [ 6]  737   inc  hl
   020F 46            [ 7]  738   ld  b,(hl)
   0210 D5            [11]  739   push  de
   0211 C5            [11]  740   push  bc
   0212 CDr20r00      [17]  741   call  _printstrng
   0215 F1            [10]  742   pop  af
   0216 D1            [10]  743   pop  de

Üblicherweise übergeben Compiler Variablen auf dem Stack an 
Unterroutinen. Und da weiss ich eben nicht genau, ob der die Adressen 
der Strings, unten im Listing zu sehen wirklich richtig übermittelt. So 
fit bin ich da auch´nicht drin. Vermutlich wird die Adresse in BC, DE 
übergeben an _printstrng.

printstrng holt sie sich ja auch und korrigiert dann den Stack schnell 
wieder:

;  ---------------------------------
                            156 ; Function printstrng
                            157 ; ---------------------------------
   0020                     158 _printstrng_start::
   0020                     159 _printstrng:
                            160 ;driver.c:28: while ((*k) != '\0')
   0020 C1            [10]  161   pop  bc
   0021 E1            [10]  162   pop  hl
   0022 E5            [11]  163   push  hl
   0023 C5            [11]  164   push  bc
   0024                     165 00101$:
   0024 7E            [ 7]  166   ld  a,(hl)
   0025 B7            [ 4]  167   or  a, a
   0026 C8            [11]  168   ret  Z
                            169 ;driver.c:29: putchar(*(k++));

: Bearbeitet durch User
Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:

> Unterroutinen. Und da weiss ich eben nicht genau, ob der die Adressen
> der Strings, unten im Listing zu sehen wirklich richtig übermittelt.

Ich denke du hast recht. Da stimmt wirklich was nicht.


> So
> fit bin ich da auch´nicht drin. Vermutlich wird die Adresse in BC, DE
> übergeben an _printstrng.

BC

DE ist da nur Nebenschauplatz. Könnte damit zusammenhängen, dass 
Calling-Konventions einzuhalten sind, die 2 Registerpärchen am Stack 
vorschreiben.

Aber die Reihenfolge in der auf den Stack gepusht wird, ist tatsächlich 
falsch rum.

printstrng will die Adresse offnbar in HL haben. Sieht man ganz deutlich 
hier
    0024 7E            [ 7]  166   ld  a,(hl)

HL hilt sich die Funktion aber
0020 C1 [10] 161 pop bc
0021 E1 [10] 162 pop hl

als 2.tes vom Stack. D.h. das ist der ältere der beiden PUSH vom 
Aufrufer hier
020F 46 [ 7] 738 ld b,(hl)
0210 D5 [11] 739 push de
0211 C5 [11] 740 push bc
0212 CDr20r00 [17] 741 call _printstrng
...

also der Wert vom PUSH DE

in DE steht aber zu diesem Zeitpunkt nicht die Adresse vom String 
drinnen. Die ist in BC.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl Heinz schrieb:

> als 2.tes vom Stack. D.h. das ist der ältere der beiden PUSH vom
> Aufrufer hier
>
> 020F 46 [ 7] 738 ld b,(hl)
> 0210 D5 [11] 739 push de
> 0211 C5 [11] 740 push bc
> 0212 CDr20r00 [17] 741 call _printstrng
> ...
> 
>
> also der Wert vom PUSH DE
>
> in DE steht aber zu diesem Zeitpunkt nicht die Adresse vom String
> drinnen. Die ist in BC.

Arg.
Kommando zurück.
Ich hab auf die Return Adresse vergessen, die liegt ja auch noch auf dem 
Stack. Berücksichtigt man die auch noch, dann kriegt _printstrng den 
korrekten Wert ins richtige Register.

: Bearbeitet durch Moderator
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, wollte ich grd schreiben, dass das schon richtig ist :-) Bin auch 
grad dran. Tja, weiter weiss ich nicht außer alles so lange umzubauen 
und immer neue EEPROM zubrennen bis es klappt.

Die Addy kommt hier in BC zu liegen, etwas umständlich aber halt 
Compiler.

 0209 01r00r00      [10]  734   ld  bc,#_menue
   020C 09            [11]  735   add  hl,bc
   020D 4E            [ 7]  736   ld  c,(hl)
   020E 23            [ 6]  737   inc  hl
   020F 46            [ 7]  738   ld  b,(hl)

Funktionieren tut

char m1[] = "Text 1"
char m2[] = "Text 2"

und Call mit

printstrng((char*)m1);

Der SDCC ist bei weitem nicht bug frei!

Ein

IO_REG | = (1 << 7)

lässt ihn mit "internal compiler error" abschmieren.

: Bearbeitet durch User
Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:

> Tja, weiter weiss ich nicht

Da bist du nicht alleine :-)

> Die Addy kommt hier in BC zu liegen, etwas umständlich aber halt
> Compiler.
>
>  0209 01r00r00      [10]  734   ld  bc,#_menue
>    020C 09            [11]  735   add  hl,bc
>    020D 4E            [ 7]  736   ld  c,(hl)
>    020E 23            [ 6]  737   inc  hl
>    020F 46            [ 7]  738   ld  b,(hl)

Ist nicht wirklich umständlich.
Du vergisst, dass es ja da noch ein Zwischenarray gibt, in dem die 
Adresse des eigentlichen Strings liegt. D.h. der Compiler berechnet erst 
mal an welcher Position im Pointer Array der richtige Pointer liegt (das 
ist das Vorgeplänkel mit dem D Register und der Addition der Adresse von 
'_menu'), holt sich dann von dort die Adresse des Strings nach BC.
Selbst wenn du das händisch in Assembler programmierst, wirst du das 
nicht wesentlich anders lösen. Von daher sehe ich das nicht so, dass der 
Compiler das umständlich gelöst hätte. Da muss ich den SDCC 
freisprechen.

> Der SDCC ist bei weitem nicht bug frei!

Das glaub ich schon. Wird der überhaupt noch gewartet?

Aber: im geposteten Listing kann ich nichts entdecken, was da schief 
laufen würde. Ich würde sagen, compilerseitig hat er den Teil richtig 
umgesetzt.

: Bearbeitet durch Moderator
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl Heinz schrieb:

> Compiler das umständlich gelöst hätte. Da muss ich den SDCC
> freisprechen.
>
>> Der SDCC ist bei weitem nicht bug frei!
>
> Das glaub ich schon. Wird der überhaupt noch gewartet?
>
> Aber: im geposteten Listing kann ich nichts entdecken, was da schief
> laufen würde. Ich würde sagen, compilerseitig hat er den Teil richtig
> umgesetzt.

Letze Version die ich habe ist von 18.10.2014. Und die Buglist bei 
sourceforge ist schon recht "üppig". Ansonsten aber bin ich erstaunt wie 
clever er manche Sachen umsetzt. wie zb Bit-Tests. dass er merkt, dass 
ein & 0x80 der Test des linken Bits ist, das rausschiebt ins Carry und 
dann testet. & 0x01 schiebt er es rechts raus. Der Code ist nicht viel 
größer als Asm, vielleicht 25% mehr aber pfeif drauf, dafür ist C 
deutlich fixer in der Programmierung.

Jetzt kann ich ur noch versuchen den Code mal durch einen Simulator zu 
jagen, denn es gibt ihn auch als compilierbaren Asm und nicht nur als 
Listing.

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ist das wirklich ok? Habe mal ein

printstrg(menue[0]);

kompiliert.

Das ergibt
                      725 ;main.c:95: printstrng(menue[0]);
   0200 2Ar00r00      [16]  726   ld  hl, (#_menue + 0)
   0203 E5            [11]  727   push  hl
   0204 CDr20r00      [17]  728   call  _printstrng
   0207 F1            [10]  729   pop  af


ld  hl, (#_menue + 0) = Lade HL mit der absoluten Adresse von _menue + 
Index 0, weil ich ja String 0 ausgeben will.

2Ar00r00 ist der Befehl ld hl,... und die 00r00 sind Platzhalter.

Das kommt nochmal hier vor:

0000                     829 __xinit__menue:
   0000r61r02               830   .dw ___str_0
   0002r78r02               831   .dw ___str_1
   0004r9Ar02               832   .dw ___str_2
   0006rBBr02               833   .dw ___str_3
   0008rDDr02               834   .dw ___str_4
   000ArF9r02               835   .dw ___str_5
   000Cr14r03               836   .dw ___str_6
                            837   .area _CABS (ABS)

0000r61r02 + 0x100 Offset für.code könnte 0x0361 sein mit etwas 
Phantasie. Da liegt der [0] String. siehe Hex Dump. Bei 0x378 liegt auch 
der 2.te String und die sind in 0002r78r02  codiert.

Und die _str sind hier:
                         800   .area _CODE
   0261                     801 ___str_0:
   0261 5A 38 30 20 53 79   802   .ascii "Z80 System is online!"
        73 74 65 6D 20 69
        73 20 6F 6E 6C 69
        6E 65 21
   0276 0A                  803   .db 0x0A
   0277 00                  804   .db 0x00

Die 00 00 sind Platzhalter für den Linker. Der Hex Dump zeigt hier:

2A 02 20            = ld hl, #2002

Der String steht aber bei 0361. 0x100 muss man draufaddieren, das ist 
der Code Offset.

Kompiliere ich menue[1] steht da 2A 04 20, also ein Wort weiter.

Bei 2002 liegt das RAm, ab 0x2000 ist es da.
Area                                    Addr        Size        Decimal Bytes (Attributes)
--------------------------------        ----        ----        ------- ----- ------------
_INITIALIZER                        00002020    0000000E =          14. bytes (REL,CON)

UNd hier tauchen die 2020 wieder auf, im Map File in einer .initializer 
Area. 2020 und nicht 2002 !

Sehr seltsam..... das stimmt nicht. Das HL Register wird mit einem 
völlig falschen Wert geladen, mitten aus dem RAM und das dann Blödsinn 
rauskommt ist klar.

Für mich sieht das schwer nach einem Bug aus. Der Source liegt mir vor, 
allerding hat der 2h kompiliert und das sind hunderte Dateien in eben so 
vielen Unterverzeichnissen. Keine Chance wo ich da suchen müsste das zu 
fixen.

Und hier scheint der Bug auch schonmal aufgefallen zu sein:

http://sourceforge.net/p/sdcc/mailman/message/29544602/

: Bearbeitet durch User
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nach endlosem Testen mit und ohne Klammern, mit "" und ohne "" ist mir 
klar, dass da was nicht stimmt mit dem sdcc, allein schon die seltsamen 
Fehlermeldungen oder "critical internal error"

Was mit einer Reihe Zeichenketten funktioniert ist:
wobei man die scharf begrenzen muss, ein [] funktioniert nicht, er muss 
wissen wie lang der laengste String ist.

const char array[6][34] = {
      ("111111111111111111111111111111111"),
      ("222222222222222222222222222222222"),
      ("333333333333333333333333333333333"),
      ("444444444444444444444444444444444"),
      ("555555555555555555555555555555555"),
      ("666666666666666666666666666666666"),


};


printstrng(array[0]);
printstrng(array[1]);

ergibt die richtige lesbare Ausgabe

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:

> 2Ar00r00 ist der Befehl ld hl,... und die 00r00 sind Platzhalter.

Vorsicht. Das ist ein anderer Befehl.

Der Z80 kann

    LD   HL, nn          ; lade HL mit dem Wert nn

    LD   HL,(nn)         ; lade HL mit dem Wert, den du unter der
                         ; Adresse nn im Speicher findest

Der erste Befehl ist also der 'Immediate', während der zweite der 
'indirect' Kategorie zuzuordnen ist.

Der SDCC benutzt da schon den richtigen.

Bei
   0200 2Ar00r00      [16]  726   ld  hl, (#_menue + 0)

holt er sich also den Inhalt des Speichers von hier
0000                     829 __xinit__menue:
   0000r61r02               830   .dw ___str_0

Unter Berücksichtigung der Relokierung durch den Linker, sollte nach dem 
Befehl daher 0x0361 im Register HL stehen, was korrekt wäre.

> Kompiliere ich menue[1] steht da 2A 04 20, also ein Wort weiter.

Jup. Jetzt holt er sich den Wert von hier
0000                     829 __xinit__menue:
   0000r61r02               830   .dw ___str_0
   0002r78r02               831   .dw ___str_1    ; <----------
   0004r9Ar02               832   .dw ___str_2
   0006rBBr02               833   .dw ___str_3

nach dem 'Load HL indirect' steht also 0378 im Registerpaar HL.
AUch das wieder korrekt die Startsdresse des 2.ten Strings im Speicher.


> Der Hex Dump zeigt hier:
> 2A 02 20 = ld hl, #2002
> ....
> Bei 2002 liegt das RAm, ab 0x2000 ist es da.
>
> Area                                    Addr        Size        Decimal Bytes 
(Attributes)
> --------------------------------        ----        ----        ------- ----- 
------------
> _INITIALIZER                        00002020    0000000E =          14. bytes 
(REL,CON)

Das ist allerdings in der Tat interessant.
Was zeigt dir denn der Hexdump bei 0x2002 nachdem das Pgm geladen wurde 
und ev, Hochfahrinitialisierungen gemacht wurden?

: Bearbeitet durch Moderator
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl-Heinz,

erstmal danke dass du da so tief mit reinkriechst und das ganz ohne 
dafür bezhahlt zu werden.

Ich stelle nur fest, dass es nicht funktioniert, da ich hier die 
Hardware habe und das ganze Drumherum aufgesetzt, so dass ich unter 
Linux editiere, der Cubietruck den Code kompiliert, der direkt im 
Brenner ist, so dass ich  ganz fix von der Änderung zum Neubrand komme.

Mir ist soweit klar, dass eine Tabelle angelegt wird, eben diese _xinit, 
wo Vektoren auf die Strings ablegt werden und dass eine indirekte 
Adressierung nötig ist. Aber das erklärt noch nicht den Zahlendreher mit 
den 0202 und 2020.

Tiefer will ich da nicht einsteigen, da ich einen workaroud habe, es sei 
denn Du hast Lust den Asm Code mal durch einen Debugger zu jagen und zu 
schauen was da wirklich passiert.

PS: Ich kann nur den Hexdump des Brenners aufrufen, der das ROM abdeckt, 
alles hinter 0x1fff ist nicht zu sehen, da das schon das RAM ist. Und da 
komme ich nicht dran, da ich erst den Monitor schreibe.

: Bearbeitet durch User
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PS:

Aktuell habe ich auf jeden Fall eine lauffähige Umgebung um auch Int 
Mode 2 usw auf einem Z80 Minimalsystem zu fahren und dafür habe ich Tage 
gebraucht, da es nirgends im Netz darüber was gibt und der sdcc Int 
Modes nicht unterstützt. Man muss da einiges selbst stricken. Falls das 
von Interesse ist stelle ich den gesamten Projektcode, der aktuell aus 
viel Testroutinen besteht gern hier rein. Irgendjemand wird sicher mal 
wieder einen Z80 bauen und vor genau den gleichen Problemen stehen, die 
ich gelöst habe.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:

> Mir ist soweit klar, dass eine Tabelle angelegt wird, eben diese _xinit,
> wo Vektoren auf die Strings ablegt werden und dass eine indirekte
> Adressierung nötig ist. Aber das erklärt noch nicht den Zahlendreher mit
> den 0202 und 2020.

Der ist allerdings interessant.
Wenn das Bestand hat, dann könnte das aber eher ein Linker Fehler sein, 
der die Bestandteile im Code dann an die richtige Stelle setzt.

Du könntest interessehalber mal probieren, ob Compiler und Linker die 
Tabelle im ROM lassen, wenn du sie so anlegst
const char* const menu[] = {
  "String 1",
  "String 2"
};

dadurch, dass jetzt das Pointer Array ebenfalls const ist (und nicht nur 
die Texte), müsste das Pointer Array nicht im RAM allokiert werden und 
damit dann auch nicht aus dem ROM initialisiert werden.

> PS: Ich kann nur den Hexdump des Brenners aufrufen, der das ROM abdeckt,

Das ist zu früh. Denn vor dem main läuft ja eine 
Initialisierungsroutine, die die Initalwerte aus dem ROM ins RAM 
kopiert. D.h. die müsste ablaufen, dann könnte man im Speicher 
nachsehen, was bei 0x2002 tatsächlich im Speicher steht.

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Karl Heinz schrieb:
> Das ist zu früh. Denn vor dem main läuft ja eine
> Initialisierungsroutine, die die Initalwerte aus dem ROM ins RAM
> kopiert.

Nein, ich weiss dass sowas zb beim ARM gemacht wird im Startup Code. 
Hier habe ich aber die volle Kontrolle über alles und den Startup selbst 
geschrieben. Da wird nix kopiert. Was ich kompiliere steht im ROM drin.

Allerdings hat die area .initializier sicher was zu bedeuten und man 
kann da auch selbst Code für schreiben, wenn man diese Area definiert.

Dein Vorschlag erzeugt:
                         740 ;main.c:95: printstrng(menu[0]);
   0209 2Ar6Br02      [16]  741   ld  hl, (#_menu + 0)
   020C E5            [11]  742   push  hl
   020D CDr20r00      [17]  743   call  _printstrng
   0210 F1            [10]  744   pop  af

und
026B                     814 _menu:
   026BrC3r03               815   .dw __str_0
   026DrCCr03               816   .dw __str_1

und
03C3                     923 __str_0:
   03C3 53 74 72 69 6E 67   924   .ascii "String 1"
        20 31
   03CB 00                  925   .db 0x00
   03CC                     926 __str_1:
   03CC 53 74 72 69 6E 67   927   .ascii "String 2"
        20 32
   03D4 00                  928   .db 0x00



Just for fun mal hier der Startup Code
;--------------------------------------------------------------------------
; crt0.s - Generic crt0.s for a Z80
;
; Written by Christian Julius in 10.2014 for a Minimum Z80 System
; with Mostek 3801 Multi I/O Chip
;--------------------------------------------------------------------------

  .module crt0      ; Modul Name für den Linker

  ; Memory Map Adressen der Zeropage (vom Benutzer definierbar)
  ; 0x00           Reset Vector und Aufruf Hauptprogramm
  ; 0x38          Mode 1 Int Vektor
  ; 0x40          Mode 2 Vektor Tabelle für STI Mostek Multi I/O
  ; 0x66          NMI Reset Vektor
  ; 0x80          Copyright String
  ; 0x100          User Programm

  ; Definitions
  stack          = 0xffff  ; fix
  adr_vec_table    = 0x40    ; frei
  adr_copyright       = 0x80    ; frei
  adr_nmi        = 0x66    ; fix

  ; Globale Funktionen und Variablen für das C-Programm

    .globl  _main
  .globl  _nmi_vint     ; Funktion des NMI Handlers

  ; Interruptroutinen für den Mostek MK3801 Multi I/O Baustein
  ; Manual STI Baustein MK3801 Figure 7
  .globl  _int_sti_gpi_0  ; General Purpose Interrupt 0
  .globl  _int_sti_gpi_1  ; General Purpose Interrupt 1
  .globl  _int_sti_gpi_2   ; General Purpose Interrupt 2
  .globl  _int_sti_gpi_3  ; General Purpose Interrupt 3
  .globl  _int_sti_timer_d
  .globl  _int_sti_timer_c
  .globl  _int_sti_gpi_4  ; General Purpose Interrupt 4
  .globl  _int_sti_gpi_5  ; General Purpose Interrupt 5
  .globl  _int_sti_timer_b
  .globl  _int_sti_transmit_error
  .globl  _int_sti_transmit_buffer_empty
  .globl  _int_sti_receive_error
  .globl  _int_sti_receive_buffer_full
  .globl  _int_sti_timer_a
  .globl  _int_sti_gpi_6  ; General Purpose Interrupt 6
  .globl  _int_sti_gpi_7  ; General Purpose Interrupt 7
  ; Mode 1, alles auf eine Routine umleiten
  .globl  _int_sti_all


  ; -------------------------------------------------------------
  .area  _HEADER (ABS)  ; Ende des Headers


  ;///////////////////////////////////////////////////////////
  ; Reset vector bei Kaltstart und Sprung ins User Programm

  .org   0

   jp init
  
  ; Copyright String (maximal 16 Zeichen)
  .org adr_copyright
  .ascis "(C)2014\20C.Julius\0"

  ;///////////////////////////////////////////////////////////
  ;// Mode 1 Interrupt
  .org 0x38
  jp _int_sti_all


  ;///////////////////////////////////////////////////////////
  ; Tabelle der Mode 2 Int Vektoren auf die Handler Funktionen im C Modul
  ; Reihenfolge beachten !!! Siehe Manual Mostek 3801, Interrupt Tabelle
  .org 0x40
  .dw (_int_sti_gpi_0)
  .dw (_int_sti_gpi_1)
  .dw (_int_sti_gpi_2)
  .dw (_int_sti_gpi_3)
  .dw (_int_sti_timer_d)
  .dw (_int_sti_timer_c)
  .dw (_int_sti_gpi_4)
  .dw (_int_sti_gpi_5)
  .dw  (_int_sti_timer_b)
  .dw  (_int_sti_transmit_error)
  .dw  (_int_sti_transmit_buffer_empty)
  .dw  (_int_sti_receive_error)
  .dw  (_int_sti_receive_buffer_full)
  .dw  (_int_sti_timer_a)
  .dw  (_int_sti_gpi_6)
  .dw  (_int_sti_gpi_7)

  ;///////////////////////////////////////////////////////////
  ; NMI Interrupt 0x66, muss mit retn abgeschlossen werden
  .org  0x66
  jp _nmi_vint    ; Aufruf Handler im C Modul main.c
  
  ;; Start des Hauptprogramms nach der Zeropage
  
init:
  ;; Stack an Spitze des RAM legen
  ld  sp,#stack
    jp   _main    ; ###### Hauptprogramm aufrufen #######
  halt      ; Stop und Schluss
endlos:
  jr endlos    ; Sicher ist sicher
    
  
  ; Area Definitionen, nicht verändern!

  ;; Ordering of segments for the linker.
  .area _HOME
  .area _CODE
  .area _GSINIT
  .area _GSFINAL
  .area _GSINIT
  .area _DATA
  .area _BSEG
  .area _BSS
  .area _HEAP

: Bearbeitet durch User
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachwort:

Dein Vorschlag funktioniert !!!!!

Woran lag es jetzt? An dem extra "const" ?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Karl Heinz schrieb:
>> Das ist zu früh. Denn vor dem main läuft ja eine
>> Initialisierungsroutine, die die Initalwerte aus dem ROM ins RAM
>> kopiert.
>
> Nein, ich weiss dass sowas zb beim ARM gemacht wird im Startup Code.
> Hier habe ich aber die volle Kontrolle über alles und den Startup selbst
> geschrieben. Da wird nix kopiert.

Da muss aber was kopiert werden!


wenn du im C Code schreibst
int arr[] = { 1, 2, 3, 4, 5 };

dann muss das Array im RAM angelegt werden (denn du könntest ja im 
Programm dann eine Zuweisung an eines der Array Elemente machen, ergo 
muss es änderbar sein) UND irgendwie müssen ja beim Hochfahren des 
Systems die Initialwerte in diesen Speicher bugsiert werden. Die 
Initialwerte müssen daher irgendwo im ROM stehen und beim Startup werden 
sie ins RAM kopiert.
Wenn du das in deinem Startup nicht machst, ist aber klar dass aus dem 
nicht ordnungsgemäss initialisiertem RAM nur Unsinn gelesen wird.

> Was ich kompiliere steht im ROM drin.

Auch.


> Dein Vorschlag erzeugt:
> [code]
>                          740 ;main.c:95: printstrng(menu[0]);
>    0209 2Ar6Br02      [16]  741   ld  hl, (#_menu + 0)

Was wird da im Hex-Dump draus?
Ist die Adresse beim 2A dann eine ROM oder eine RAM Adresse. Sprich: Hat 
der Compiler das const Array im ROM belassen, oder hat er dafür RAM 
angefordert?

: Bearbeitet durch Moderator
Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Nachwort:
>
> Dein Vorschlag funktioniert !!!!!

Hätte ich dem SDCC jetzt gar nicht zugetraut, dass er das handhabt. :-)

>
> Woran lag es jetzt? An dem extra "const" ?

Ja.
Denn jetzt ist auch das Array mit den Pointer-Werten const. Ergo ist es 
nicht mehr veränderbar. Ergo braucht es kein RAM dafür und kann im ROM 
verbleiben. Alle Lesezugriffe können daher direkt aus dem ROM 
abgewickelt werden, wo der Compiler die Initialwerte angelegt hat.

: Bearbeitet durch Moderator
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mir macht die Sache mit dem Initilizer noch Sorge, grad mal etwas 
gebastelt:

Damit er nicht alles wegoptimiert ein volatile
volatile uint16_t n = 0x1234;
volatile uint16_t myvar = 0xabcd;

n = 5 * i;
n = myvar;  
Er macht es tatsächlich, vor Main fängt er globale Vars zu init'en:
                        743 ;main.c:90: volatile uint16_t n = 0x1234;
   0210 DD 36 FE 34   [19]  744   ld  -2 (ix),#0x34
   0214 DD 36 FF 12   [19]  745   ld  -1 (ix),#0x12
                            746 ;main.c:91: volatile uint16_t myvar = 0xabcd;
   0218 21 CD AB      [10]  747   ld  hl,#0xABCD
   021B E3            [19]  748   ex  (sp), hl
Allerdings frage ich mich ob er diese .initializer Section noch sonstwie 
braucht und ich da Code für schreiben muss.

Aus deinem Beispielarray macht er nix, legt nur eine Tabelle an. Aber 
irgendwelche Zuweisungen stehen da nicht.

                          960   .area _INITIALIZER
   0000                     961 __xinit__arr:
   0000 01 00               962   .dw #0x0001
   0002 02 00               963   .dw #0x0002
   0004 03 00               964   .dw #0x0003
   0006 04 00               965   .dw #0x0004
   0008 05 00               966   .dw #0x0005
                            967   .area _CABS (ABS)

: Bearbeitet durch User
Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:

> Er macht es tatsächlich, vor Main fängt er globale Vars zu init'en:
>
>
>                         743 ;main.c:90: volatile uint16_t n = 0x1234;
>    0210 DD 36 FE 34   [19]  744   ld  -2 (ix),#0x34
>    0214 DD 36 FF 12   [19]  745   ld  -1 (ix),#0x12
>                             746 ;main.c:91: volatile uint16_t myvar = 
> 0xabcd;
>    0218 21 CD AB      [10]  747   ld  hl,#0xABCD
>    021B E3            [19]  748   ex  (sp), hl
> 

Interessant wie er das macht.
Die übliche Variante ist nicht, da extra Code für jede Variable zu 
schreiben, sondern Compiler und Linker bauen da normalerweise im ROM im 
Grunde genommen ein Speicherabbild zusammen, wie es eigentlich im RAM 
vorliegen müsste und eine stinknormale Byteschleife kopiert dann einfach 
alles ins RAM. Der Z80 kann das mit einem LDIR besonders gut.

Kann natürlich sein, dass das System das hier einzeln auf den Variablen 
macht, weil so ein Speicherabbild zusammen mit der Kopierschleife mehr 
Platz verbrauchen würde.
Leg doch mal ein Array mit 20 Einträgen an und sieh nach, wie sich der 
Compiler vorstellt das zu initialisieren

volatile int a[20] = { 0, 10, 1, 11, 2, 12, 3, 13, 4, 14,
                       5, 15, 6, 16, 7, 17, 8, 18, 9, 19 };

int main()
{
}

irgendeine Form eines Initialisierungscodes muss es geben.

: Bearbeitet durch Moderator
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Doch macht er in einer lokalen Funktion:

                          131 ;driver.c:19: volatile int foom[] = { 1, 2, 3, 4, 5 };
   0008 21 00 00      [10]  132   ld  hl,#0x0000
   000B 39            [11]  133   add  hl,sp
   000C 36 01         [10]  134   ld  (hl),#0x01
   000E 23            [ 6]  135   inc  hl
   000F 36 00         [10]  136   ld  (hl),#0x00
   0011 21 02 00      [10]  137   ld  hl,#0x0002
   0014 39            [11]  138   add  hl,sp
   0015 36 02         [10]  139   ld  (hl),#0x02
   0017 23            [ 6]  140   inc  hl
   0018 36 00         [10]  141   ld  (hl),#0x00
   001A 21 04 00      [10]  142   ld  hl,#0x0004
   001D 39            [11]  143   add  hl,sp
   001E 36 03         [10]  144   ld  (hl),#0x03
   0020 23            [ 6]  145   inc  hl
   0021 36 00         [10]  146   ld  (hl),#0x00
   0023 21 06 00      [10]  147   ld  hl,#0x0006
   0026 39            [11]  148   add  hl,sp
   0027 36 04         [10]  149   ld  (hl),#0x04
   0029 23            [ 6]  150   inc  hl
   002A 36 00         [10]  151   ld  (hl),#0x00
   002C 21 08 00      [10]  152   ld  hl,#0x0008
   002F 39            [11]  153   add  hl,sp
   0030 36 05         [10]  154   ld  (hl),#0x05
   0032 23            [ 6]  155   inc  hl
   0033 36 00         [10]  156   ld  (hl),#0x00


Aber nicht wenn man es global definiert, dann gibts nur
 000A                     972 __xinit__foom:
   000A 01 00               973   .dw #0x0001
   000C 02 00               974   .dw #0x0002
   000E 03 00               975   .dw #0x0003
   0010 04 00               976   .dw #0x0004
   0012 05 00               977   .dw #0x0005
                            978   .area _CABS (ABS)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Doch macht er in einer lokalen Funktion:

Da haben sie wohl davor zurückgeschreckt :-)

WOW. Was das an ROM kostet!

> Aber nicht wenn man es global definiert, dann gibts nur
>
>  000A                     972 __xinit__foom:
>    000A 01 00               973   .dw #0x0001
>    000C 02 00               974   .dw #0x0002
>    000E 03 00               975   .dw #0x0003
>    0010 04 00               976   .dw #0x0004
>    0012 05 00               977   .dw #0x0005
>                             978   .area _CABS (ABS)
> 

Hilft aber nichts. Irgendwo MUSS kopiert werden! Das RAM initialisiert 
sich nicht von alleine auf die richtigen Werte.

: Bearbeitet durch Moderator
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kriege nur grad die Krise:

Er soll sich ja das Programm Hex File vom PC reinziehen und das wird 
dann auf 0x2000 lokiert sein, da das RAM da anfängt. Nach dem Reinladen 
soll er dann auf 0x2000 springen und das RAM ausführen.

Hoffe mal da gibt es keine Probleme bei mit den ganzen Segmenten, Inits 
usw.

>>Hilft aber nichts. Irgendwo MUSS kopiert werden! Das RAM initialisiert
>>sich nicht von alleine auf die richtigen Werte.

Wie ?????? Ein Königreich dafür, wenn ich das wüsste, weil ich es 
eigentlich gar nicht wissen muss, es soll nur funktionieren.

: Bearbeitet durch User
Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl Heinz schrieb:


> Hilft aber nichts. Irgendwo MUSS kopiert werden!

Oder sonst irgendwie dafür gesorgt werden, zb mit LD Instruktionen.

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Ich kriege nur grad die Krise:
>
> Er soll sich ja das Programm Hex File vom PC reinziehen und das wird
> dann auf 0x2000 lokiert sein, da das RAM da anfängt. Nach dem Reinladen
> soll er dann auf 0x2000 springen und das RAM ausführen.

?
Dein Speicherdump spricht da aber eine andere Sprache.
Der Code ist nicht auf 0x2000 relokiert.

> Wie ?????? Ein Königreich dafür, wenn ich das wüsste, weil ich es
> eigentlich gar nicht wissen muss, es soll nur funktionieren.

Wie hast du denn den Rest des Startup Codes geschrieben?
Der Linker wird da ja Code einbinden, der vor main() abläuft. Da muss 
diese Initialisierung irgendwo drinn stecken.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Da steht was drüber
>
> http://atariage.com/forums/topic/212505-sdcc-330-r...

Das
        .area _GSINIT
gsinit::
        ld      bc, #l__INITIALIZER
        ld      a,b
        or      a,c
        jr      z, gsinit_next
        ld      de, #s__INITIALIZED
        ld      hl, #s__INITIALIZER

        ldir
gsinit_next:


        .area _GSFINAL
        ret
        ;
sieht vernünftig aus. Genau so etwas würde ich da erwarten.
Der LDIR kopiert BC Bytes von (HL) nach (DE).
In HL steht die Adresse vom Bytefeld, in dem alle Initialisierungen 
zusammengetragen wurden (ist also eine Adresse im ROM), in DE steht die 
Adresse vom RAM, wo sie hinmuessen.

: Bearbeitet durch Moderator
Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zu deinem Startup Code
....
    jmp init

....

init:
  ;; Stack an Spitze des RAM legen
  ld  sp,#stack
    jp   _main    ; ###### Hauptprogramm aufrufen #######
....

logisch. Du initialisierst ja das RAM überhaupt nicht!
Bevor du nach _main weitergehst müssen doch erst mal die 
Initialisierungen ins RAM kopiert werden. Das ist klar, dass da nichts 
geht.

Ohne mich da jetzt näher damit befasst zu haben:
....

init:
  ;; Stack an Spitze des RAM legen
  ld  sp,#stack
  call gsinit
  jp   _main    ; ###### Hauptprogramm aufrufen #######

: Bearbeitet durch Moderator
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok,genug für heute.

Habe es eingebaut und er springt an die falsche Adresse, nämlich ins Ram 
und da steht nix drin.

call gsinit

wird zu

call 202A  im Dump File


Aber jetzt in die Heia...



 00A3 CD 00 00      [17]  109   call gsinit    ;; Initialize Global 
Variables
   00A6 C3 00 00      [10]  110     jp   _main    ; ###### Hauptprogramm 
aufrufen #######
   00A9 76            [ 4]  111   halt      ; Stop und Schluss
   00AA                     112 endlos:
   00AA 18 FE         [12]  113   jr endlos    ; Sicher ist sicher
                            114
                            115
                            116   ; Area Definitionen, nicht verändern!
                            117
                            118   ;; Ordering of segments for the 
linker.
                            119   .area _HOME
                            120   .area _CODE
                            121   .area _GSINIT
                            122
   0000                     123   gsinit::
   0000 01 00 00      [10]  124         ld      bc, #l__INITIALIZER
   0003 78            [ 4]  125         ld      a,b
   0004 B1            [ 4]  126         or      a,c
   0005 28 08         [12]  127         jr      z, gsinit_next
   0007 11 00 00      [10]  128         ld      de, #s__INITIALIZED
   000A 21 00 00      [10]  129         ld      hl, #s__INITIALIZER
                            130
   000D ED B0         [21]  131         ldir
   000F                     132 gsinit_next:
                            133
                            134         .area _GSFINAL
   0000 C9            [10]  135         ret
                            136
                            137
                            138   .area _GSINIT
                            139   .area _DATA
                            140   .area _BSEG
                            141   .area _BSS
                            142   .area _HEAP

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
?
    
  
  ; Area Definitionen, nicht verändern!

  ;; Ordering of segments for the linker.
  .area _HOME
  .area _CODE
  .area _GSINIT
  .area _GSFINAL
  .area _GSINIT
  .area _DATA
  .area _BSEG
  .area _BSS
  .area _HEAP

_GSINIT wird 2 mal angegeben? Da stimmt doch schon wieder was nicht.
Sieh dir mal das in deinem Link angegebene Startup File an. Ist zwar für 
ein anderes System, aber die generelle Strategie kann man dort schon 
sehen.
start_program:

;
; Vorgeplänkel wegen Interrupts. Wird dich weniger interessieren
;
  im       1                      ; interrupt mode -> rst 38h
  di

;
; BSS ausnullen, damit wie vom C Standard vorgeschrieben alle globalen
; Variablen einen Wert von 0 haben
;
  xor     a                       ; clear carry
  ld      bc,#0x3b8    ; ram size left
  ld      hl,#0x7000    ; starting from 7000
  ld      de,#0x7001
  ld      (hl),a
  ldir                            ; zero-fill bss

;
; dann die globalen Variablen initialisieren, die im C Code
; von 0 verschiedene Werte haben
;
  call gsinit          ; Initialize global variables.

;
; irgend eine systemspezifische Initialisierung. Offenbar irgendwas mit Sounds
; interessiert dich nicht und fliegt raus
;
  ld  h,#0 ; set dummy sound table
  call set_snd_table

;
;
; random Generator.
; wenn mans braucht
;
  ld      hl,#0x0033                ; initialise random generator
  ld      (0x73c8),hl

;
; dann kommt irgendwas mit einem Display
;
                                    ; set screen mode 2 text
  call    0x1f85                   ; set default VDP regs 16K
  ld      de,#0x4000                ; clear VRAM
  xor     a
  ld      l,a
  ld      h,a
  call    0x1f82

;
;
; und erst jetzt ist der Startup soweit fertig, dass main loslegen kann
;
    ; call main rountine
  jp      _main

bei dir fehlt da ja einiges im Startup!

: Bearbeitet durch Moderator
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt nicht mehr. Trotzdem führt der Sprung von call gsinit ins Ram.
Der wird als

CD 2A 20

übersetzt. Vermutlich weil diese Area da hingelegt wird. Leider weiss 
ich nicht ob ich da was verändern kann, da das wohl Schlüsselworte sind, 
die man nicht verändern sollte. Sonst würde ich gsinit zu meinem Code 
nehmen vor dem Sprung ins hauptprogramm.

Du, Heinz, ich dank dir aber ich muss jetzt schlafen. Versuche das 
morgen rauszufinden, ist ja schon eine Menge gewesen heute.


;--------------------------------------------------------------------------
; crt0.s - Generic crt0.s for a Z80
;
; Written by Christian Julius in 10.2014 for a Minimum Z80 System
; with Mostek 3801 Multi I/O Chip
;--------------------------------------------------------------------------

  .module crt0      ; Modul Name für den Linker

  ; Memory Map Adressen der Zeropage (vom Benutzer definierbar)
  ; 0x00           Reset Vector und Aufruf Hauptprogramm
  ; 0x38          Mode 1 Int Vektor
  ; 0x40          Mode 2 Vektor Tabelle für STI Mostek Multi I/O
  ; 0x66          NMI Reset Vektor
  ; 0x80          Copyright String
  ; 0x100          User Programm

  ; Definitions
  stack          = 0xffff  ; fix
  adr_vec_table    = 0x40    ; frei
  adr_copyright       = 0x80    ; frei
  adr_nmi        = 0x66    ; fix

  ; Globale Funktionen und Variablen für das C-Programm

    .globl  _main
  .globl  _nmi_vint     ; Funktion des NMI Handlers

  ; Interruptroutinen für den Mostek MK3801 Multi I/O Baustein
  ; Manual STI Baustein MK3801 Figure 7
  .globl  _int_sti_gpi_0  ; General Purpose Interrupt 0
  .globl  _int_sti_gpi_1  ; General Purpose Interrupt 1
  .globl  _int_sti_gpi_2   ; General Purpose Interrupt 2
  .globl  _int_sti_gpi_3  ; General Purpose Interrupt 3
  .globl  _int_sti_timer_d
  .globl  _int_sti_timer_c
  .globl  _int_sti_gpi_4  ; General Purpose Interrupt 4
  .globl  _int_sti_gpi_5  ; General Purpose Interrupt 5
  .globl  _int_sti_timer_b
  .globl  _int_sti_transmit_error
  .globl  _int_sti_transmit_buffer_empty
  .globl  _int_sti_receive_error
  .globl  _int_sti_receive_buffer_full
  .globl  _int_sti_timer_a
  .globl  _int_sti_gpi_6  ; General Purpose Interrupt 6
  .globl  _int_sti_gpi_7  ; General Purpose Interrupt 7
  ; Mode 1, alles auf eine Routine umleiten
  .globl  _int_sti_all
  
  
    .globl l__INITIALIZER
    .globl s__INITIALIZER
    .globl s__INITIALIZED


  ; -------------------------------------------------------------
  .area  _HEADER (ABS)  ; Ende des Headers


  ;///////////////////////////////////////////////////////////
  ; Reset vector bei Kaltstart und Sprung ins User Programm

  .org   0

   jp init
  
  ; Copyright String (maximal 16 Zeichen)
  .org adr_copyright
  .ascis "(C)2014\20C.Julius\0"

  ;///////////////////////////////////////////////////////////
  ;// Mode 1 Interrupt
  .org 0x38
  jp _int_sti_all


  ;///////////////////////////////////////////////////////////
  ; Tabelle der Mode 2 Int Vektoren auf die Handler Funktionen im C Modul
  ; Reihenfolge beachten !!! Siehe Manual Mostek 3801, Interrupt Tabelle
  .org 0x40
  .dw (_int_sti_gpi_0)
  .dw (_int_sti_gpi_1)
  .dw (_int_sti_gpi_2)
  .dw (_int_sti_gpi_3)
  .dw (_int_sti_timer_d)
  .dw (_int_sti_timer_c)
  .dw (_int_sti_gpi_4)
  .dw (_int_sti_gpi_5)
  .dw  (_int_sti_timer_b)
  .dw  (_int_sti_transmit_error)
  .dw  (_int_sti_transmit_buffer_empty)
  .dw  (_int_sti_receive_error)
  .dw  (_int_sti_receive_buffer_full)
  .dw  (_int_sti_timer_a)
  .dw  (_int_sti_gpi_6)
  .dw  (_int_sti_gpi_7)

  ;///////////////////////////////////////////////////////////
  ; NMI Interrupt 0x66, muss mit retn abgeschlossen werden
  .org  0x66
  jp _nmi_vint    ; Aufruf Handler im C Modul main.c
  
  ;; Start des Hauptprogramms nach der Zeropage
  .org 0xa0
  
init:
  
  ld  sp,#stack  ;; Stack an Spitze des RAM legen
  call gsinit    ;; Initialize Global Variables
    jp   _main    ; ###### Hauptprogramm aufrufen #######
endlos:
  jr endlos    ; Sicher ist sicher
    
  
  ;; Ordering of segments for the linker.
  .area _HOME
  .area _CODE
  .area _INITILIZER
  .area _GSINIT
  .area _GSFINAL
  .area _DATA
  .area _INITILIZED
  .area _BSEG
  .area _BSS
  .area _HEAP
  
  .area _GSINIT
  gsinit::
        ld      bc, #l__INITIALIZER
        ld      a,b
        or      a,c
        jr      z, gsinit_next
        ld      de, #s__INITIALIZED
        ld      hl, #s__INITIALIZER
        ldir

gsinit_next:

     .area _GSFINAL
     ret


: Bearbeitet durch User
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch andere haben das gleiche Problem... gähn

http://comments.gmane.org/gmane.comp.compilers.sdc...

Hi,

When I use my custom crt0, in the final binary, gsinit: is pointing to
GSFINAL instead of GSINIT. Therefore, global variables do not get
initialised. Also, GSINIT is placed into DATA which seems to be wrong.
Finally, since my device only has RAM and not ROM, I don't think I
need separate CODE and DATA areas - all variables can be stored in
CODE like consts are. Is there some way to tell the compiler to do
that?

Umschreiben der Kopierroutine in die .code area hat nix genutzt. Er wird 
ausgeführt aber ein Test ergab dass eine 6 nicht auf dem Display kommt, 
also wird sie nicht eingeschrieben.
  
init:
  
  ld  sp,#stack  ;; Stack an Spitze des RAM legen
  
  ld      bc, #l__INITIALIZER
    ld      a,b
    or      a,c
    jr      z, gsinit_next
    ld      de, #s__INITIALIZED
    ld      hl, #s__INITIALIZER
    ldir

gsinit_next:
   
  ;call gsinit    ;; Initialize Global Variables
  
    jp   _main    ; ###### Hauptprogramm aufrufen #######
endlos:
  jr endlos    ; Sicher ist sicher
    
  
  ;; Ordering of segments for the linker.
  .area _HOME
  .area _CODE
  .area _INITILIZER
  .area _GSINIT
  .area _GSFINAL
  .area _DATA
  .area _INITILIZED
  .area _BSEG
  .area _BSS
  .area _HEAP


Kontrolle im lst File des Startups ergab
   0083 01 00 00      [10]  106   ld      bc, #l__INITIALIZER
   0086 78            [ 4]  107     ld      a,b
   0087 B1            [ 4]  108     or      a,c
   0088 28 08         [12]  109     jr      z, gsinit_next
   008A 11 00 00      [10]  110     ld      de, #s__INITIALIZED
   008D 21 00 00      [10]  111     ld      hl, #s__INITIALIZER
   0090 ED B0         [21]  112     ldirsembler V02.00 + NoICE + SDCC mods  (Zilog Z80 / Hitachi HD64180), page 3.
0083 01 00 00      [10]  106   ld      bc, #l__INITIALIZER

wird erzeugt zu

01 17 00   also ld bc,#0017

also 2 x 0x17 Bytes kopieren.
008D 21 00 00      [10]  111     ld      hl, #s__INITIALIZER

wird zu

21 20 20 also hl, 2029

das passt?
008A 11 00 00      [10]  110     ld      de, #s__INITIALIZED
wird zu

11 02 20   also ld de,2002

das passt auch.

: Bearbeitet durch User
Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:

> das passt auch.

Das kann aber nicht stimmen.
Die Routine kopiert  x Bytes von der Adresse 0x2002 nach 0x2020. Auf 
deinem System ist das aber, wenn ich mich recht erinnere RAM und nicht 
ROM. D.h. die kopiert von uninitalisiertem RAM ins uninitialisierte RAM.

Die Initialiwerte müssen irgendwo in deiner ROM Sektion liegen. Denn nur 
der wird ja von deinem Loader (Brenner?) beschrieben, wie du weiter oben 
irgendwo erzählt hast (also von 0x0000 bis 0x1FFF).

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Könnte der Tippfehler hier
  ;; Ordering of segments for the linker.
  .area _HOME
  .area _CODE
  .area _INITILIZER
mit reinspielen (da fehlt ein A in INITIALIZER)

hier
...
  .area _INITILIZED
nochmal.

: Bearbeitet durch Moderator
Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl Heinz schrieb:
> Christian J. schrieb:
>> Doch macht er in einer lokalen Funktion:
>
> Da haben sie wohl davor zurückgeschreckt :-)
>
> WOW. Was das an ROM kostet!

Es war mal etwas effizienter, und wird es hoffentlich auch irgendwann 
mal wieder sein:

https://sourceforge.net/p/sdcc/bugs/1565/

Philipp

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Philipp Klaus Krause schrieb:
> Karl Heinz schrieb:
>> Christian J. schrieb:
>>> Doch macht er in einer lokalen Funktion:
>>
>> Da haben sie wohl davor zurückgeschreckt :-)
>>
>> WOW. Was das an ROM kostet!
>
> Es war mal etwas effizienter, und wird es hoffentlich auch irgendwann
> mal wieder sein:
>
> https://sourceforge.net/p/sdcc/bugs/1565/

Da du dich mit dem SDCC scheinbar auskennst, kannst du Christian mit 
seinem Startup Code helfen?
Ich hab da nicht wirklich Ahnung davon, wie das funktioniert und muss da 
mehr mit educated guesses arbeiten.

Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> push  bc
>    0212 CDr20r00      [17]  741   call  _printstrng
>    0215 F1            [10]  742   pop  af

Karl Heinz schrieb:
>> So
>> fit bin ich da auch´nicht drin. Vermutlich wird die Adresse in BC, DE
>> übergeben an _printstrng.
>
> BC
>
> DE ist da nur Nebenschauplatz. Könnte damit zusammenhängen, dass
> Calling-Konventions einzuhalten sind, die 2 Registerpärchen am Stack
> vorschreiben.

Eher damit, dass in D oder E lokale Variablen gespeichert sind, die nach 
dem Aufruf noch gebraucht werden (und die Aufrufkonvention _printstrng 
erlaubt, D und E zu überschreiben).

Philipp

Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zur Initialiserung von Variablen im Z80-port von sdcc (gilt auch für 
z180, gbz80, r2k, r3ka, tlcs90):

Die wichtigsten areas sind:
  .area  _CODE
  .area  _INITIALIZER
  .area  _HOME
  .area  _GSINIT
  .area  _DATA
  .area  _INITIALIZED

_CODE: Enthält Code und konstante Variablen. Auf Systemen mit ROM wird 
dieser Bereich im ROM angelegt.
_INITALIZER: Enthält ein Speicherabbild nichtkonstanter globaler 
Variablen, die explizit initialisiert wurden. Dieses wird im ROM 
angelegt, und muß in crt0 nach _INITIALIZED kopiert werden.
_GSINIT: Enthält code, der Variablen initialisiert, die nicht auf 
anderem Weg intialisert werden. Muß0 von crt0m ausgeführt werden. Dieser 
Bereich liegt auch im ROM.
_DATA: Hier liegen im RAM die Variablen die entweder nicht explizit 
initialisiert werden (und dann von crt0 mit 0 initialisiert werden 
müssen) sowie die Variablen, die in _GSINIT initalisert werden.
_INITIALIZED: Hier liegen im RAM die explizit initialisierten Variablen.

Philipp

Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier ein Beispiel für crt0.s (etwas älter, für ColecoVision, aus libcv 
0.22):
; crt0.s for Colecovision cart

  .module crt0
  .globl _main
  .globl _cv_init
  .globl _cv_spint_handler
  .globl _cv_vint
  .globl _cv_start
  .globl __sdcc_call_hl

  .area _HEADER(ABS)
  .org 0x8000

  .db 0x55, 0xaa      ; Title screen and 12 second delay - swap 0x55 and 0xaa not to skip it.
  .dw 0                ; Sprite name table for BIOS
  .dw 0                ; Sprite order table for BIOS.
  .dw 0                ; Buffer for BIOS.
  .dw 0                ; Controller map for BIOS.
  .dw _cv_start            ; where to start execution of program.
  jp  0x0    ; RST 0x08      
  jp  0x0    ; RST 0x10
  jp  0x0    ; RST 0x18
  jp  0x0    ; RST 0x20
  jp  0x0    ; RST 0x28
  jp  0x0    ; RST 0x30
  jp spint  ; RST 0x38 - spinner - maskable interrupt
  jp vint    ; Vertical retrace - NMI
  .ascii " / / NOT"

  ; Ordering of segments for the linker - copied from sdcc crt0.s
  .area  _CODE
  .area  _INITIALIZER
  .area  _HOME
  .area  _GSINIT
  .area  _GSFINAL
  .area  _DATA
  .area  _INITIALIZED
  .area  _BSEG
  .area  _BSS
  .area  _HEAP

  .area  _CODE

_cv_start:
  ld sp, #0x7400      ; Set stack pointer directly above top of memory.

  ; Implicitly zeroed global and static variables. Do it here, before any call to not corrupt stack!
  ld  bc, #1023
  ld  hl,  #0x7000
  ld  (hl), #0x00
  ld  e, l
  ld  d, h
  inc  de
  ldir

  call gsinit        ; Initialize global and static variables.

  call _cv_init      ; Initialize Colecovision specific stuff.
  call _main
  rst 0x0        ; Restart when main() returns.

vint:
  push  af
  push  bc
  push  de
  push  hl
  push  iy
  call  _cv_vint
  pop  iy
  pop  hl
  pop  de
  pop  bc
  pop  af
  retn

spint:
  push  af
  push  bc
  push  de
  push  hl
  push  iy
  in  a, (#0xfc)
  ld  b, a
  in  a, (#0xff)
  ld  c, a
  push  bc
  ld  hl, (#_cv_spint_handler)
  call  __sdcc_call_hl
  pop  af
  pop  iy
  pop  hl
  pop  de
  pop  bc
  ei
  reti

  .area   _GSINIT
gsinit::

  ; Explicitly initialized global variables.
  ld  bc, #l__INITIALIZER
  ld  a, b
  or  a, c
  jr  Z, gsinit_static
  ld  de, #s__INITIALIZED
  ld  hl, #s__INITIALIZER
  ldir

gsinit_static:
  ; Explicitly initialized static variables inserted by compiler here.

  .area   _GSFINAL
  ret

  .area _HOME

Wenn ich mir das durchlese, sehe ich, dass ich manches da inzwischen 
schöner schreiben könnte. Aber verwednen wir trotzdem 'mal dieses 
Beispiel zur weiteren Erläuterung.

Philipp

Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Am Anfang gibt es ein paar Bytes, deren Bedeutung vom BIOS des 
ColecoVision bestimmt wird. Insbesondere sind dort Adressen für 
Interruptroutinen.

Beim Einschalten des ColecoVision übergibt das BIOS irgendwann an 
_cv_start.

Dort wird dann zuwerst der stackpointer initialisert.
Dann wird der RAM mit 0 initialisiert (ginge etwas effizienter, da es 
ausreichend wäre nur _DATA mit 0 zu initialisieren).
Dann geht es weiter bei _gsinit. Dort wird dann _INITIALIZER nach 
_INITIALIZED kopiert. Die Symbole l__X und s__X werden für jeden Bereich 
X vom Linker durch die Größe des Bereichs und die Startadresse des 
Bereichs ersetzt.

Philipp

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

danke für die Ausführungen. Ich werde mal versuchen das hinzukriegen, 
sobald ich vom Zahnarzt wiederkommen, falls ich dann noch den Nerv dazu 
habe :-)

Der SDCC ist soweit klasse aber die Doku ist etwas zu wenig. Bei mir 
funktioniert das Variaben kopieren immer noch nicht und ich weiss nicht 
mehr was ich noch wohin schieben oder kopieren muss. Ich habe wohl alles 
ausgereizt. So ein Schaubild würde echt helfen, wie da was angeordnet 
wird im Speicher, der ja nun mal sehr einfach ist bei Z80.

Das ganze soll klar strukturiert sein und vor allem müssen Defintionen 
klar von Code unterschieden werden können. Warum taucht 2 Mal .gsinit 
auf?

;--------------------------------------------------------------------------
; crt0.s - Generic crt0.s for a Z80
;
; Written by Christian Julius 
; with Mostek 3801 Multi I/O Chip
;--------------------------------------------------------------------------

  .module crt0      ; Modul Name für den Linker

  ; Memory Map Adressen der Zeropage (vom Benutzer definierbar)
  ; 0x00           Reset Vector und Aufruf Hauptprogramm
  ; 0x38          Mode 1 Int Vektor
  ; 0x40          Mode 2 Vektor Tabelle für STI Mostek Multi I/O
  ; 0x66          NMI Reset Vektor
  ; 0x80          Copyright String
  ; 0x100          User Programm

  ; Definitions
  stack          = 0xffff  ; fix
  adr_vec_table    = 0x40    ; frei
  adr_copyright       = 0x80    ; frei
  adr_nmi        = 0x66    ; fix

  ; Globale Funktionen und Variablen für das C-Programm

    .globl  _main
  .globl  _nmi_vint     ; Funktion des NMI Handlers

  ; Interruptroutinen für den Mostek MK3801 Multi I/O Baustein
  ; Manual STI Baustein MK3801 Figure 7
  .globl  _int_sti_gpi_0  ; General Purpose Interrupt 0
  .globl  _int_sti_gpi_1  ; General Purpose Interrupt 1
  .globl  _int_sti_gpi_2   ; General Purpose Interrupt 2
  .globl  _int_sti_gpi_3  ; General Purpose Interrupt 3
  .globl  _int_sti_timer_d
  .globl  _int_sti_timer_c
  .globl  _int_sti_gpi_4  ; General Purpose Interrupt 4
  .globl  _int_sti_gpi_5  ; General Purpose Interrupt 5
  .globl  _int_sti_timer_b
  .globl  _int_sti_transmit_error
  .globl  _int_sti_transmit_buffer_empty
  .globl  _int_sti_receive_error
  .globl  _int_sti_receive_buffer_full
  .globl  _int_sti_timer_a
  .globl  _int_sti_gpi_6  ; General Purpose Interrupt 6
  .globl  _int_sti_gpi_7  ; General Purpose Interrupt 7
  ; Mode 1, alles auf eine Routine umleiten
  .globl  _int_sti_all
  
  
    .globl l__INITIALIZER
    .globl s__INITIALIZER
    .globl s__INITIALIZED


  ; -------------------------------------------------------------
  .area  _HEADER (ABS)  ; Ende des Headers


  ;///////////////////////////////////////////////////////////
  ; Reset vector bei Kaltstart und Sprung ins User Programm

  .org   0

   jp init
  
  ;///////////////////////////////////////////////////////////
  ;// Mode 1 Interrupt
  .org 0x38
  jp _int_sti_all


  ;///////////////////////////////////////////////////////////
  ; Tabelle der Mode 2 Int Vektoren auf die Handler Funktionen im C Modul
  ; Reihenfolge beachten !!! Siehe Manual Mostek 3801, Interrupt Tabelle
  .org 0x40
  .dw (_int_sti_gpi_0)
  .dw (_int_sti_gpi_1)
  .dw (_int_sti_gpi_2)
  .dw (_int_sti_gpi_3)
  .dw (_int_sti_timer_d)
  .dw (_int_sti_timer_c)
  .dw (_int_sti_gpi_4)
  .dw (_int_sti_gpi_5)
  .dw  (_int_sti_timer_b)
  .dw  (_int_sti_transmit_error)
  .dw  (_int_sti_transmit_buffer_empty)
  .dw  (_int_sti_receive_error)
  .dw  (_int_sti_receive_buffer_full)
  .dw  (_int_sti_timer_a)
  .dw  (_int_sti_gpi_6)
  .dw  (_int_sti_gpi_7)

  ;///////////////////////////////////////////////////////////
  ; NMI Interrupt 0x66, muss mit retn abgeschlossen werden
  .org  0x66
  jp _nmi_vint    ; Aufruf Handler im C Modul main.c
  
  ;; Start des Hauptprogramms nach der Zeropage
  .org 0x80
  
init:
  
  ld  sp,#stack  ;; Stack an Spitze des RAM legen
  
  ; Ram ausnullen
  xor     a             ; clear a and carry
  ld      bc,#0xdfff    ; ram size left
  ld      hl,#0x2000    ; starting from 2000
  ld      de,#0x2001
  ld      (hl),a      ; 0 -> (2000)  
  ldir                  ; (HL) -> (DE)
  
    jp   _main    ; ###### Hauptprogramm aufrufen #######
endlos:
  jr endlos    ; Sicher ist sicher
    
  
  ;; Ordering of segments for the linker.

  .area  _CODE
  .area  _INITIALIZER
  .area  _HOME
  .area  _GSINIT
  .area  _GSFINAL
  .area  _DATA
  .area  _INITIALIZED
  .area  _BSEG
  .area  _BSS
  
  .area   _GSINIT
  ; Explicitly initialized global variables.
  ld  bc, #l__INITIALIZER
  ld  a, b
  or  a, c
  jr  Z, gsinit_static
  ld  de, #s__INITIALIZED
  ld  hl, #s__INITIALIZER
  ldir
  
gsinit_static:
  ; Explicitly initialized static variables inserted by compiler here.

  .area   _GSFINAL
  ret  

  .area _HOME
  
  



: Bearbeitet durch User
Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da fehlt zumindest der Aufruf des codes in _GSINIT (siehe folgende 
zeilen aus meinem Beispiel:)
call gsinit        ; Initialize global and static variables.

und
gsinit::

Philipp

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Da warst du schneller :-) Ich konnte es nicht mehr korrigiere. Leider 
zeigt der Call ins RAM, wie ich im Hex File sehe. UNd da liegt natürlich 
kein Code :-( Das Programm schmiert direkt ab.

CD 18 20 wird aus call gsinit. also call 2018.

Wie kriege ich gsinit dazu, dass es in der Zeropage liegt? Da wo es hin 
gehört?


  ;; Start des Hauptprogramms nach der Zeropage
  .org 0x80

init:

  ld  sp,#stack  ;; Stack an Spitze des RAM legen

  ; Ram ausnullen
  xor     a             ; clear a and carry
  ld      bc,#0xdfff    ; ram size left
  ld      hl,#0x2000    ; starting from 2000
  ld      de,#0x2001
  ld      (hl),a      ; 0 -> (2000)
  ldir                  ; (HL) -> (DE)

  call gsinit
    jp   _main    ; ###### Hauptprogramm aufrufen #######
endlos:
  jr endlos    ; Sicher ist sicher


  ;; Ordering of segments for the linker.

  .area  _CODE
  .area  _INITIALIZER
  .area  _HOME
  .area  _GSINIT
  .area  _GSFINAL
  .area  _DATA
  .area  _INITIALIZED
  .area  _BSEG
  .area  _BSS

  .area   _GSINIT

gsinit::

  ; Explicitly initialized global variables.
  ld  bc, #l__INITIALIZER
  ld  a, b
  or  a, c
  jr  Z, gsinit_static
  ld  de, #s__INITIALIZED
  ld  hl, #s__INITIALIZER
  ldir

gsinit_static:
  ; Explicitly initialized static variables inserted by compiler here.

  .area   _GSFINAL
  ret

  .area _HOME

: Bearbeitet durch User
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PS: Ich kompiliere mit

sdcc -mz80 --no-std-crt0 --vc --code-loc 0x100 --data-loc 0x2000 
main.rel crt0.rel

Ok, Zahnarzt wartet...

: Bearbeitet durch User
Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was passiert, wenn Du crt0.rel zuerst aufführtst?
sdcc -mz80 --no-std-crt0 --code-loc 0x100 --data-loc 0x2000 crt0.rel main.rel

Philipp

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Philipp Klaus Krause schrieb:
> Was passiert, wenn Du crt0.rel zuerst aufführtst?
>
>
> sdcc -mz80 --no-std-crt0 --code-loc 0x100 --data-loc 0x2000 crt0.rel 
> main.rel
> 
>
> Philipp

Das Gleiche, die Reihenfolge sollte ja egal sein.

PS: Wenn das erfolgreich alles klappt schreibe ich nen schönen Wiki 
Artikel über das Thema.

: Bearbeitet durch User
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Philipp Klaus Krause schrieb:

> Zur Initialiserung von Variablen im Z80-port von sdcc (gilt auch für
> z180, gbz80, r2k, r3ka, tlcs90):
>
> Die wichtigsten areas sind:
>
>
>   .area  _CODE
>   .area  _INITIALIZER
>   .area  _HOME
>   .area  _GSINIT
>   .area  _DATA
>   .area  _INITIALIZED
> 
>
> _CODE: Enthält Code und konstante Variablen. Auf Systemen mit ROM wird
> dieser Bereich im ROM angelegt.
> _INITALIZER: Enthält ein Speicherabbild nichtkonstanter globaler
> Variablen, die explizit initialisiert wurden. Dieses wird im ROM
> angelegt, und muß in crt0 nach _INITIALIZED kopiert werden.
> _GSINIT: Enthält code, der Variablen initialisiert, die nicht auf
> anderem Weg intialisert werden. Muß0 von crt0m ausgeführt werden. Dieser
> Bereich liegt auch im ROM.
> _DATA: Hier liegen im RAM die Variablen die entweder nicht explizit
> initialisiert werden (und dann von crt0 mit 0 initialisiert werden
> müssen) sowie die Variablen, die in _GSINIT initalisert werden.
> _INITIALIZED: Hier liegen im RAM die explizit initialisierten Variablen.
>
> Philipp


Ich knüpfe hier nochmal an, da es wirklich nirgendwo Infos darüber gibt, 
was das alles zu bedeuten hat und weil ich mein Projekt nicht deswegen 
aufgeben werde.


  .area  _CODE
  .area  _INITIALIZER
  .area  _HOME
  .area  _GSINIT
  .area  _GSFINAL
  .area  _DATA
  .area  _INITIALIZED
  .area  _BSEG
  .area  _BSS
  .area _HOME

Da würde noch ein Stack Segment fehlen, wie zb beim 486er.

Ein Z80 Minisystem besteht aus ROM und RAM. Code wird aus dem Rom heraus 
ausgeführt und dieser Code erzeugt Variablen etc im Ram. Im Ram liegt 
grundsätzlich kein Code. Gewisse Variablen haben Startwerte, sie liegen 
alle hintereinander im Ram und könnten wie ein Image aus dem ROM 
bespielt werden.

Es fehlt jede Info darüber wie der sdcc diese "Segmente" verteilt, 
klatscht er sie einfach hintereinander? Oder teilt er sie in Gruppen 
auf? Was hat die Reihenfolge zu bedeuten? Und wo müssen diese Inits im 
crt0.s stehen? Mittendrin? Unten? Darf man sie doppelt definieren?

Einen Teil ins ROM, den anderen ins Ram? HEAP kann ja nur im Ram liegen.

  .area  _GSFINAL

Das sagt mir soweit nichts.

Wie gesagt zeigt bei mir der Vektor er GSINIT ins RAm, weil dort eine 
Routine vermutet wird, die nicht da ist. Packe ich den Init Code ins Rom 
klappt es trotzdem nicht.

Ich bin da mit meinem Latein am Ende :-(


Hier nochmal mein batch Compile File

# Assembliere das crt0 startup file
sdasz80 -o -l crt0.rel crt0.s
# Kompilieren aber nicht linken
echo "Kompilieren....."
sdcc -mz80 main.c -c
#sdcc -mz80 tools.c -c

# Nun alles Linken
echo "Linking....."
sdcc -mz80 --no-std-crt0 --vc --code-loc 0x0100 --data-loc 0x2000 
crt0.rel main.rel

: Bearbeitet durch User
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

falls hier noch jemand mal reinschaut, so habe ich kapiert was falsch 
läuft indem ich ein Minimalprogramm aufsetzte, so dass alles Unötige weg 
war.
Area                                    Addr        Size        Decimal Bytes (Attributes)
--------------------------------        ----        ----        ------- ----- ------------
_INITIALIZER                        00000307    00000007 =           7. bytes (REL,CON)
                             82   .area _CODE
                             83   .area _INITIALIZER
   0000                      84 __xinit__myvar:
   0000 06                   85   .db #0x06  ; 6
   0001                      86 __xinit__arr:
   0001 55                   87   .db #0x55  ;  85  'U'
   0002 AA                   88   .db #0xAA  ; -86
   0003 55                   89   .db #0x55  ;  85  'U'
   0004 AA                   90   .db #0xAA  ; -86
   0005 55                   91   .db #0x55  ;  85  'U'
   0006 AA                   92   .db #0xAA  ; -86
                             93   .area _CABS (ABS)

Die Kopieroutine wird bei -data-loc 0x300 zu
  ; Explicitly initialized global variables.
  ld  bc, #07
  ld  a, b
  or  a, c
  jr  Z, gs1
  ld  de, #0321
  ld  hl, #0307
  ldir

Da liegt der Wurm drin !!!!

Mich wunderte es dass die Intialisierten Variablen nirgendwo auftauchten 
im brennbare Hex Dump. Klar, denn sie wurden weit außerhalb des ROM 
gelegt. Daher lief auch die Kopierroutine nichtl, denn die kopierte 
Nichts nach Nichts.

Übeltäter:

--data-loc 0x300 im Bash File zum Kompilieren

Testweise mal auf 0x300 gesetzt, damit er meint das Ram liege dort, 
obwohl es ROM ist. Und oh Wunder, da lagen die Variablen dann auch artig 
hintereinander.

Was da eigentlich kopiert wird entzieht sich meinem Verständnis

Der Compiler erzeugt den Code so, dass die intialisierten Variablen auch 
direkt da im Ram zu liegen kommen, wo sie hin sollen. Meine 0x2000 lagen 
weit außerhalb des 8kb ROMs, daher verschwanden sie einfach.

Leider kann man ihm nicht beibringen wo denn die _INITIALIZER Area sein 
soll.

Damit dürfte dieses Problem als nicht lösbar abgeklärt sein.

: Bearbeitet durch User
Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eigentlich sollte sdcc, wenn crt0.rel die erste aufgeführte Objektdatei 
ist, die areas so wie in crt0 aufgelistet anordnen, also _INITIALIZER 
direkt nach _CODE.

Es gibt aber auch die Linker-Option -b um manuell festzulegen, welche 
area wohin kommt.

Philipp

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine Linker Option -b ist nicht dokumentiert. Und die Reihenfolge darf 
keine Rolle spielen. Ein Vertauschen ändert auch den Namen der .hex 
Datei, hat aber keinen Einfluss auf das Ergebnis.

Glaube du hast mich nicht richtig verstanden. Der sdcc macht das richtig 
aber er legt die Init Werte schon sofort und direkt ins Ram ab, da wo 
--data-loc hinzeigt.

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Problem wir auch hier näher beschrieben:

http://dirk-hobbyblog.blogspot.de/2012/12/sdcc-crt...

Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Eine Linker Option -b ist nicht dokumentiert.

Man muß dazu sdld selbst aufrufen, statt das sdcc zu überlassen. Zur 
Dokumentation:
>sdld

sdld Linker V03.00 + NoICE + sdld

Usage: [-Options] [-Option with arg] file
Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]
Startup:
  -p   Echo commands to stdout (default)
  -n   No echo of commands to stdout
Alternates to Command Line Input:
  -c                   ASlink >> prompt input
  -f   file[.lk]       Command File input
Libraries:
  -k   Library path specification, one per -k
  -l   Library file specification, one per -l
Relocation:
  -b   area base address = expression
  -g   global symbol = expression
Map format:
  -m   Map output generated as (out)file[.map]
  -w   Wide listing format for map file
  -x   Hexadecimal (default)
  -d   Decimal
  -q   Octal
Output:
  -i   Intel Hex as (out)file[.ihx]
  -s   Motorola S Record as (out)file[.s19]
  -j   NoICE Debug output as (out)file[.noi]
  -y   SDCDB Debug output as (out)file[.cdb]
List:
  -u   Update listing file(s) with link data as file(s)[.rst]
Case Sensitivity:
  -z   Disable Case Sensitivity for Symbols
Miscellaneous:
  -I   [iram-size] Check for internal RAM overflow
  -X   [xram-size] Check for external RAM overflow
  -C   [code-size] Check for code overflow
  -M   Generate memory usage summary file[.mem]
  -Y   Pack internal ram
  -S   [stack-size] Allocate space for stack
End:
  -e   or null line terminates input

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Leider kann ich mit

area base address = expression

nichts anfangen und alle möglichen Sytaxversuche sind auch gescheitert.
man sdld und man sdcc bringen auch keine Klarheit.

Ich lege die Sache daher beiseite, da ich darauf schon zuviel Zeit 
verschwendet habe und ich mich eigentlich um sowas auch nicht kümmern 
möchte, wenn ich einen Compiler benutze. Es ist zwar Open Source und 
eine freiwillige Arbeit aber die ist leider schlecht dokumentiert.

Es erzeugt darüber hinaus unterschiedlichen Code, ob man erst beide 
Teile kompiliert und dann linkt, oder ob man das in einem Rutsch macht.
Dann sind die Konstanten nämlich doppelt im Speicher vorhanden, hinter 
dem Code, wo sie hingehören sollten und im RAM auch noch was ja nicht 
gebrannt werden kann. Ein

char array[10000]

bläst das Hex File auf über 10000 Bytes so auf, dass man es nicht mehr 
brennen kann, weil es ein direktes Speicherabbild ist. Auch das ist in 
dem obigen Link beschrieben.

Der SDCC erwartet, dass ein "Image" in ein Z80 Memory aus reinem RAM 
geschoben wird. Dann ist es nämlich richtig. Mit ROM und RAM zusammen 
kommt er nicht klar.

Ok, abgehakt.... ich schaue mich nach was anderem um als dem sdcc. Auch 
wenn ich dafür was bezahlen muss. Oder vermeide initilisierte Variablen 
und schreibe erst im Code das rein was rein muss.

: Bearbeitet durch User
Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Kannst Du uns 'mal genau sagen, was Dein Problem ist?

Also:
Bis zu 20 Zeilen kompilierbarer C-Code, zusammen mit Deiner crt0.s. 
Mit der Kommandozeile, die Du verwendet. Und mit Angaben, an welchen 
Adressen Deines Zielsystems RAM bzw. ROM liegen.

Philipp

Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich sehe gerade, dass Du Angaben zum System in einer Mail gemacht hast 
("System 0-1ffff ROM, 2000-ffff RAM."), und die crt0.s läßt sich 
möglicherweise auch zusammen suchen. Ich mache 'mal ein BEispiel für 
Dein System.

Philipp

Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier ein Bespiel mit Deine Angaben:

test.c:
char ca[5] = "test";
char c;

void main(void)
{
}

crt0.s:
;--------------------------------------------------------------------------
; crt0.s - Generic crt0.s for a Z80
;
;
; with Mostek 3801 Multi I/O Chip
;--------------------------------------------------------------------------

    .module crt0            ; Modul Name für den Linker

    ; Memory Map Adressen der Zeropage (vom Benutzer definierbar)
    ; 0x00                     Reset Vector und Aufruf Hauptprogramm
    ; 0x38                    Mode 1 Int Vektor
    ; 0x40                    Mode 2 Vektor Tabelle für STI Mostek Multi I/O
    ; 0x66                    NMI Reset Vektor
    ; 0x80                    Copyright String
    ; 0x100                    User Programm

    ; Definitions
    stack                  = 0xffff    ; fix
    adr_vec_table        = 0x40        ; frei
    adr_copyright       = 0x80        ; frei
    adr_nmi                = 0x66        ; fix

    ; Globale Funktionen und Variablen für das C-Programm

    .globl    _main
    .globl  _nmi_vint         ; Funktion des NMI Handlers

    ; Interruptroutinen für den Mostek MK3801 Multi I/O Baustein
    ; Manual STI Baustein MK3801 Figure 7
    .globl  _int_sti_gpi_0    ; General Purpose Interrupt 0
    .globl  _int_sti_gpi_1    ; General Purpose Interrupt 1
    .globl  _int_sti_gpi_2     ; General Purpose Interrupt 2
    .globl  _int_sti_gpi_3    ; General Purpose Interrupt 3
    .globl  _int_sti_timer_d
    .globl  _int_sti_timer_c
    .globl  _int_sti_gpi_4    ; General Purpose Interrupt 4
    .globl  _int_sti_gpi_5    ; General Purpose Interrupt 5
    .globl  _int_sti_timer_b
    .globl  _int_sti_transmit_error
    .globl  _int_sti_transmit_buffer_empty
    .globl  _int_sti_receive_error
    .globl  _int_sti_receive_buffer_full
    .globl  _int_sti_timer_a
    .globl  _int_sti_gpi_6    ; General Purpose Interrupt 6
    .globl  _int_sti_gpi_7    ; General Purpose Interrupt 7
    ; Mode 1, alles auf eine Routine umleiten
    .globl  _int_sti_all
    
    
    .globl l__INITIALIZER
    .globl s__INITIALIZER
    .globl s__INITIALIZED


    ;///////////////////////////////////////////////////////////
    ; Reset vector bei Kaltstart und Sprung ins User Programm
    .area _HEADER(ABS)
    .org     0

     jp init
    
    ;///////////////////////////////////////////////////////////
    ;// Mode 1 Interrupt
    .org 0x38
    jp _int_sti_all


    ;///////////////////////////////////////////////////////////
    ; Tabelle der Mode 2 Int Vektoren auf die Handler Funktionen im C Modul
    ; Reihenfolge beachten !!! Siehe Manual Mostek 3801, Interrupt Tabelle
    .org 0x40
    .dw (_int_sti_gpi_0)
    .dw (_int_sti_gpi_1)
    .dw (_int_sti_gpi_2)
    .dw (_int_sti_gpi_3)
    .dw (_int_sti_timer_d)
    .dw (_int_sti_timer_c)
    .dw (_int_sti_gpi_4)
    .dw (_int_sti_gpi_5)
    .dw    (_int_sti_timer_b)
    .dw    (_int_sti_transmit_error)
    .dw    (_int_sti_transmit_buffer_empty)
    .dw    (_int_sti_receive_error)
    .dw    (_int_sti_receive_buffer_full)
    .dw    (_int_sti_timer_a)
    .dw    (_int_sti_gpi_6)
    .dw    (_int_sti_gpi_7)

    ;///////////////////////////////////////////////////////////
    ; NMI Interrupt 0x66, muss mit retn abgeschlossen werden
    .org  0x66
    jp _nmi_vint        ; Aufruf Handler im C Modul main.c
    
  ; Ordering of segments for the linker - copied from sdcc crt0.s
  .area  _CODE
  .area  _INITIALIZER
  .area  _HOME
  .area  _GSINIT
  .area  _GSFINAL
  .area  _DATA
  .area  _INITIALIZED
  .area  _BSEG
  .area  _BSS
  .area  _HEAP

  .area  _CODE
    
init:
    
    ld    sp,#stack    ;; Stack an Spitze des RAM legen
    
    ; Ram ausnullen
    xor     a             ; clear a and carry
    ld      bc,#0xdfff    ; ram size left
    ld      hl,#0x2000    ; starting from 2000
    ld      de,#0x2001
    ld      (hl),a          ; 0 -> (2000)   
    ldir                  ; (HL) -> (DE)
    
  call gsinit
    jp     _main        ; ###### Hauptprogramm aufrufen #######

endlos:
    jr endlos        ; Sicher ist sicher
       
    
gsinit::

  ; Explicitly initialized global variables.
  ld  bc, #l__INITIALIZER
  ld  a, b
  or  a, c
  jr  Z, gsinit_static
  ld  de, #s__INITIALIZED
  ld  hl, #s__INITIALIZER
  ldir

gsinit_static:
  ; Explicitly initialized static variables inserted by compiler here.

  .area   _GSFINAL
  ret

  .area _HOME

Kompilieren mit:
sdasz80 -plosgff crt0.s
sdcc -mz80 test.c -c
sdcc -mz80 --code-loc 0x0100 --data-loc 0x2000 --no-std-crt0 crt0.rel test.rel

Ich sehe da keine Probleme. Alles liegt da im Speicher, wo es sein soll.

Philipp

Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Der SDCC erwartet, dass ein "Image" in ein Z80 Memory aus reinem RAM
> geschoben wird.

Nein.

> Dann ist es nämlich richtig. Mit ROM und RAM zusammen
> kommt er nicht klar.

Doch.

Philipp

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Phillip,

anbei mal ein "20 Zeilen" projekt, direkt kompilierbar mit compile.sh
Ich habe alles weggelöscht was zuviel ist und es auf das Wesentlich 
rediziert. Vieleicht noch etwas mit den Zahlen spielen in der compile.sh

Gleich noch mehr dazu....

PS: Ich sehe grad dass die .org Statements im crts0.s entfernt sind. Die 
erzeugen Assemblerfehler, zumindest an bestimmten Stellen. Ich wollte 
den Startupcode abgesetzt in der Zeropage und das Userprogramm ab 0x100 
liegen haben.

Bin dabei .....

: Bearbeitet durch User
Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> anbei mal ein "20 Zeilen" projekt

Da seehe ich im .map schon mal, dass ein paar areas an der falschen 
Stelle liegen. Ich schaue 'mal nach, was der Grund dafür ist.

Philipp

Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> anbei mal ein "20 Zeilen" projekt, direkt kompilierbar mit compile.sh
> Ich habe alles weggelöscht was zuviel ist und es auf das Wesentlich
> rediziert. Vieleicht noch etwas mit den Zahlen spielen in der compile.sh

Zwei kleine Änderungen an Deinem Projekt sind nötig, damit es klappt:

1) Die Reihenfolge der areas in Deiner crt0.s:
  ;; Ordering of segments for the linker.
  .area  _CODE
  .area   _HEADER
  .area   _HEADER0
  .area   _HEADER1
  .area   _HEADER2
  .area   _HEADER3
  .area   _HEADER4
  .area   _HOME
  .area  _INITIAL
  .area   _INITILIZER
  .area  _GSINIT
  .area  _GSFINAL
  .area  _DATA
  .area  _BSEG
  .area  _BSS
  .area   _HEAP

_INITIALIZED muß aber im RAM, also nach _DATA kommen.

Richtig wäre z.B.:
  ;; Ordering of segments for the linker.
  .area  _CODE
  .area  _INITIALIZER
  .area  _HOME
  .area  _GSINIT
  .area  _GSFINAL
  .area  _DATA
  .area  _INITIALIZED
  .area  _BSEG
  .area  _BSS
  .area  _HEAP

2) Der Aufruf von sdcc zum Linken

Aus compile.sh:
sdcc -mz80 --no-std-crt0 --vc --code-loc 0x0100 --data-loc 0x300 main.rel crt0.rel

Der RAM liegt aber, soweit ich weiß, an 0x3000, nicht 0x300. Und 
crt0.rel muß zuerst kommen, damit der Linker die Reihenfolge der areas 
von dort übernimmt.

Richtig wäre z.B.:
sdcc -mz80 --no-std-crt0 --vc --code-loc 0x0100 --data-loc 0x3000 crt0.rel main.rel

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So,

ich bin durch. Es funktioniert nicht. Ich habe dazu das ganze 
Testprojekt genommen, da ich nur da die Ausgabe auf einer Anzeige habe, 
die mir die Realtität wiedergibt. Die crts0 habe ich soweit veinfacht 
wie es geht, keinen Call mehr zum gsinit usw. So weit es geht jede 
Fehlerquelle rausgenommen.

Auffällig ist, dass

.globl l__INITIALIZER
.globl s__INITIALIZER
.globl s__INITIALIZED

extra angegeben werden müssen in crt0.s. Ich dachte die seien 
vordefiniert und daher bekannt. Das sind bekanntlich Schlüsselworte.

Es kann direkt mit ./compile.sh fehlerfrei durchkompiliert werden und 
erzeugt main.ihx als Ausgabe.

Es kann alles ignoriert werden (dient nur der Hardware Initilisierung) 
außer der crt0.s und im Bereich main.c der letzte Teil
char abc = 5;

int main() {

    InitHardware();
    SetDigit(abc);
    while(1);
    return(0);
}

Würde abc wirklich mit 5 initialisiert, dann stünde auf der 7-Segment 
Anzeige eine 5 beim Starten. Es steht aber eine 0 dort, weil ich das RAM 
ausnulle. Nulle ich es nicht, sondern "viere" es steht da eine 4 drin.

Ändert man den Code ab

SetDigit(5);

wird richtig eine 5 angezeigt.

Im Hex Dump Editor sehe ich die Strings und anderes hinter dem 
Codesegment, wo sie wohl auch hingehören

Fazit:

Der Kopiervorgang der Initwerte findet nicht statt.

Ich würde Dir einen Orden umhängen, wenn das Problem endlich gelköst 
wäre!

Gruss,
Christian

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moment..... da warst Du schon schneller. Ich muss das jetzt erstmal 
durchtesten. Kann ich Dich ggf mal anrufen? Bist Du aus Deutschland oder 
Schweiz oder Österreich?

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So, fertig. Ich habe alles so gemacht wie beschrieben. Das ERgebnis ist 
"0" auf der Anzeige und nicht "5". Anbei alles wie gerade vor 5 Minuten 
durchkompiliert.

ROM: 0x0000 - 0x1fff
RAM: 0x2000 - 0xffff

Jetzt weiss ich nicht mehr weiter :-((((

Gruss,
Christian

: Bearbeitet durch User
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Und nochwas, siehe Bild:

Das ist das Eprom Brennprogram mit dem Hex Dump. Setzt man --data-loc 
auf 0x500 testweise, so liegt das RAM ja im "sichtbaren" Bereich für das 
Brennprogram, was genau 8kb abbildet, die Größe des EPROM.

Und wie man sieht liegen da jetzt vorbelegte Strings von RAM Variablen:

char array[]="Hallo Welt! Hier bin ich!";

Und die sind doppelt vorhanden, hinter dem Code und dann nochmal im 
"Pseudo-Ram" ab 0x500. (siehe anderes Bild)

Ich habe es auch ausprobiert erst zu kompilieren und dann zu linken in 
einem zweiten Schritt. Gleiches Ergebnis

sdcc -mz80 main.c -c
sdcc -mz80 --code-loc 0x100 --data-loc 0x200 --no-std-crt0 crt0.rel 
main.rel


Ich habe mir jezt grösste Mühe gegeben das zu beschreiben, hoffe es 
hilft.

: Bearbeitet durch User
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es läuft !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Und zwar nur mit genau dieser Anordung und Konstellation in der crt0.s
Das Dumme ist nur, ich weiss nicht genau warum.....

sdasz80 -plosgff -o -l crt0.rel crt0.s
sdcc -mz80 main.c -c
echo "Linke beide Dateien...."
sdcc -mz80 --verbose --no-std-crt0 --vc --code-loc 0x0100 --data-loc 0x2000 crt0.rel main.rel

Entfernt habe ich _GSFINAL vor dem ret unten weil ich das seltsam fand.
; NMI Interrupt 0x66, muss mit retn abgeschlossen werden
  .org  0x66
  jp _nmi_vint    ; Aufruf Handler im C Modul main.c

  ; Ordering of segments for the linker - copied from sdcc crt0.s
    ;; Ordering of segments for the linker.
    .area  _CODE
    .area  _INITIALIZER
    .area  _HOME
    .area  _GSINIT
    .area  _GSFINAL
    .area  _DATA
    .area  _INITIALIZED
    .area  _BSEG
    .area  _BSS
    .area  _HEAP

    .area  _CODE
  
  ;; ------- Start des Hauptprogramms nach der Zeropage  -----------
  
  init:
  
  ld  sp,#stack  ;; Stack an Spitze des RAM legen
  
  ; Ram ausnullen
  xor     a             ; clear a and carry
  ld      bc,#0xdfff    ; ram size left
  ld      hl,#0x2000    ; starting from 2000
  ld      de,#0x2001
  ld      (hl),a      ; 0 -> (2000)  
  ldir                  ; (HL) -> (DE)

  ; Explicitly initialized global variables.
  ld  bc, #l__INITIALIZER
  ld  a, b
  or  a, c
  jr  Z, weiter
  ld  de, #s__INITIALIZED
  ld  hl, #s__INITIALIZER
  ldir

weiter:  
  jp   _main    ; ###### Hauptprogramm aufrufen #######
endlos:
  jr endlos    ; Sicher ist sicher
    halt
  ret


Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> So, fertig. Ich habe alles so gemacht wie beschrieben. Das ERgebnis ist
> "0" auf der Anzeige und nicht "5". Anbei alles wie gerade vor 5 Minuten
> durchkompiliert.
>
> ROM: 0x0000 - 0x1fff
> RAM: 0x2000 - 0xffff
>
> Jetzt weiss ich nicht mehr weiter :-((((
>
> Gruss,
> Christian

Wenn ich getrennt kompiliere, also Deine compile.sh z.B. zu
sdasz80 -plosgff -o -l crt0.rel crt0.s
sdcc -mz80 main.c
sdcc -mz80 --verbose --no-std-crt0 --vc --code-loc 0x0100 --data-loc 0x2000 crt0.rel main.rel

ändere, sehen crt0.map und crt0.ihx bei mir gut aus.

Philipp

Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du brauchst dann, später noch den Sprung nach gsinit, da leider die 
Initalisierung mit _INITIALIZER / _INITALIZED zur Zeit nur für globale 
Variablen funktioniert. Der _GSINIT-Mechanismus wird noch für lokale 
Variablen mit storage class static gebraucht.

Philipp

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Philipp Klaus Krause schrieb:
> Du brauchst dann, später noch den Sprung nach gsinit, da leider die
> Initalisierung mit _INITIALIZER / _INITALIZED zur Zeit nur für globale
> Variablen funktioniert. Der _GSINIT-Mechanismus wird noch für lokale
> Variablen mit storage class static gebraucht.
>
> Philipp

Hi,

zumindest klappt es jetzt, dass die globalen Vars richtig eingestellt 
werden, das habe ich grad auch mit dem Menue getestet was ich von

const char* const menu...

auf

const char* menue

änderte.

Denn Sprung nach gsinit? Ich habe doch alles sprunglos gemacht. Ich 
verwende in Interrupts static char Variablen, die aber alle mit 0 
eingestellt sind. Wären es 5 gäbe es da Probleme? Weil ausgenullt ist ja 
alles schon.

Damit kann ich leben wenn static nicht läuft, da kann man auch 
workarounds programmieren.

: Bearbeitet durch User
Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich fasse, da Du ja zum Team von sdcc gehörst mal ein paar Fragen 
zusammen, damit ich und vielleicht auch andere es verstehen, wie läuft. 
Eine Ergänzung der Doku wäre auch ganz wichtig was den Z80 angeht, damit 
man das wirklich verinnerlicht.


1. Stört die Verwendung von .org 0xxxx im crt0.s File irgendwie?
   Der Assembler meckert dann. Der Startup Code wird jetzt direkt vor
  das  Userprogramm geklebt. Ich hätte ihn gern in der Zeropage gehabt.

2. Ist es irgendwie wichtig an welcher Stelle diese .area Defintionen
   im crt0.s File stehen? Vorne, hinten, mittig? Biher merke ich nur, 
dass man danach kein .org mehr setzen darf, wie zb vorher bei den Ints.

3. Das sieht seltsam aus, es ist von oben kopiert. Muss in die _GSFINAL 
noch irgendwas rein?

 ; Explicitly initialized global variables.
  ld  bc, #l__INITIALIZER
  ld  a, b
  or  a, c
  jr  Z, gsinit_static
  ld  de, #s__INITIALIZED
  ld  hl, #s__INITIALIZER
  ldir

gsinit_static:
  ; Explicitly initialized static variables inserted by compiler here.

  .area   _GSFINAL
  ret

  .area _HOME

: Bearbeitet durch User
Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Ich fasse, da Du ja zum Team von sdcc gehörst mal ein paar Fragen
> zusammen, damit ich und vielleicht auch andere es verstehen, wie läuft.
> Eine Ergänzung der Doku wäre auch ganz wichtig was den Z80 angeht, damit
> man das wirklich verinnerlicht.

Allerding befasse ich mich kaum mit Assembler oder Linker, sondern 
hauptsächlich mit manchen der Backends im Compiler.

Philipp

Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> 1. Stört die Verwendung von .org 0xxxx im crt0.s File irgendwie?
>    Der Assembler meckert dann. Der Startup Code wird jetzt direkt vor
>   das  Userprogramm geklebt. Ich hätte ihn gern in der Zeropage gehabt.

Es gibt verschiedene Arten von areas: ABS und REL. Erstere werden von 
Hand platziert, letztere vom Linker. .org sollte nur in ersteren 
vorkommen, d.h.
.area _TEST1(ABS)
.org     23

ist ok, aber

[code
.area _TEST2
.org     42
[/code]

nicht.

Philipp

Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> 3. […] Muss in die _GSFINAL
> noch irgendwas rein?

Soweit ich weiß, ist _GSFINAL nur für das ret da:

Der Compiler generiert Code zur Initalisierung von Variaben (lokale 
static) in _GSINIT. Der Linker setzt alles dasin _GSINIT nacheinander, 
und da er weiß, dass danach _GSFINAL kommt, steht dann das ret an der 
richtigen Stelle.

Philipp

Autor: Philipp Klaus Krause (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> 2. Ist es irgendwie wichtig an welcher Stelle diese .area Defintionen
>    im crt0.s File stehen? Vorne, hinten, mittig? Biher merke ich nur,
> dass man danach kein .org mehr setzen darf, wie zb vorher bei den Ints.

Entscheidend ist, in welcher Reihenfolge der Linker die areas zum ersten 
Mal sieht. Denn in dieser Reihenfolge versucht er, sie anzuordnen 
(soweit man ihm nicht per -b etwas anderes sagt). Es wäre also schlecht, 
wenn eine .area, die in der Liste vorkommt auch vor der Liste schonmal 
vorkommt. Ein weiteres Vorkommen nach der Liste schadet dann nicht mehr.

Philipp

Autor: Christian J. (Firma: Hobbywerkstatt) (hobel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

hauptsache ist, dass es jetzt funktioniert und mein kleines Maschinchen 
mit dem hohen Stromverbrauch sinnvolle Sachen macht! Auf die static 
verzichte ich, das geht auch anders zb als globale Variablen.

Ich danke Dir ganz herzlich für Deine Geduld und dass ich es jetzt 
verstanden habe. Habe den Startup jetzt wieder bei 0x80 liegen in dem 
ich die areas hinten an gestellt habe, ganz zum Schluss bis auf Header. 
Und so ist es auch logisch und verständlich.

Die Frage ob das alles auch noch klappt, wenn ich künftig das Programm 
vom PC über die Uart durch den Monitor als Hex oder Bin einlade und es 
dann direkt aus dem Ram starte kommt später, denn dann wird der 
Startupcode ja zweimal ausgeführt, da sich das im RAM liegende Programm 
ja auch  initialisieren muss. Wobei es dann auch egal ist ob die 
Einstellung des Monitors im Eprom überschrieben werden, sie werden nicht 
mehr gebraucht.

Aber das kommt später....

Grüße,
Christian

: Bearbeitet durch User
Autor: Jens (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> ; Ram ausnullen
>   xor     a             ; clear a and carry
>   ld      bc,#0xdfff    ; ram size left
>   ld      hl,#0x2000    ; starting from 2000
>   ld      de,#0x2001
>   ld      (hl),a      ; 0 -> (2000)
>   ldir                  ; (HL) -> (DE)

Hallo Christian,
Dein Code ist nicht wirklich schön, da nicht portabel.

Ich habe Deinen Code mal etwas aufgehübscht:
    .area   _GSINIT
gsinit::
    ; copy initialized variables to 'RAM'
    ld  bc, #l__INITIALIZER
    ld  a, b
    or  a, c
    jr  Z, gsinit_zero
    ld  de, #s__INITIALIZED
    ld  hl, #s__INITIALIZER
    ldir

gsinit_zero:
    ; did we have data to zero out?
    ld  bc, #l__DATA
    ld  a, b
    or  a, c
    jr  Z, gsinit_next

    ; zero uninitialized stuff
    xor     a             ; clear a and carry
    ld      bc,#l__DATA   ; ram size left
    ld      hl,#s__DATA
    ld      de,#s__DATA+1
    ld      (hl),a        
    ldir

gsinit_next:

    .area   _GSFINAL
    ret

Jens

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.