Forum: Compiler & IDEs Mehrdimensionale char-arrays


von micha (Gast)


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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von micha (Gast)


Lesenswert?

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

von Karl heinz B. (kbucheg)


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.
1
char Test[2][3];
2
3
  Test
4
  +---+---+---+---+---+---+
5
  |   |   |   |   |   |   |
6
  +---+---+---+---+---+---+
7
    0   1   2   0   1   2
8
9
   |          |          |
10
     das hier    und hier
11
   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:
1
    Adresse von [a][b] = Startadresse +
2
                         a * Dimensionierung der 2.ten Dimension +
3
                         b
Um also die Adresse berechnen zu können, muss der Compiler wissen
wie gross den die 2. te Dimension tatsächlich ist.
Bei
1
 
2
  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
1
  char *abc[] = {"so", "klappt", "es"};
wird etwas völlig anderes im Speicher aufgebaut.
Das sieht dann so aus
1
    abc
2
   +-----+        +---+---+----+
3
   |  o---------->| s | o | \0 |
4
   +-----+        +---+---+----+   +---+---+---+---+---+---+----+
5
   |  o--------------------------->| k | l | a | p | p | t | \0 |
6
   +-----+                         +---+---+---+---+---+---+----+
7
   |  o-----------+
8
   +-----+        |
9
                  |    +---+---+----+
10
                  +--->| e | s | \0 |
11
                       +---+---+----+
Die einzelnen Strings liegen also irgendwo im Speicher und
werden nur durch das Pointer-Array zusammengehalten.

: Bearbeitet durch User
von Simon K. (simon) Benutzerseite


Lesenswert?

Gut erklärt Karl Heinz, gefällt mir :-)

von Rolf Magnus (Gast)


Lesenswert?

Dafür ist er bekannt.

von Paul H. (powl)


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

von emacs (Gast)


Lesenswert?

In nem emacs mit Mausunterstützung kann man die malen :D

von Kay I. (imperator)


Lesenswert?

Moin zusammen,

wie müsste ich folgendes Problem angehen ...
ein Liste von Strings in verschiedenen Sprachen:
1
const char str_de[][15+1]={
2
"Text in deutsch" // info
3
"hallo Welt     " // hello
4
}
5
6
const char str_en[][15+1]={
7
"text in english" // info
8
"hello world    " // hello
9
}
10
11
char **str_ptr;
12
13
(...)
14
// Initialisierung
15
if(language == deutsch){
16
 str_ptr = str_de;
17
}
18
else{
19
 str_ptr = str_en;
20
}
21
22
(...)
23
// main loop
24
print(str_ptr[0]);
25
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?

von Karl H. (kbuchegg)


Lesenswert?

1
const char* str_de[] = {
2
 "Text in deutsch" // info
3
 "hallo Welt     " // hello
4
}
5
6
const char* str_en[] = {
7
  "text in english" // info
8
  "hello world    " // hello
9
}
10
11
const char** str_ptr;
12
13
(...)
14
  // Initialisierung
15
  if(language == deutsch){
16
    str_ptr = str_de;
17
  }
18
  else {
19
   str_ptr = str_en;
20
  }
21
 
22
  (...)
23
  // main loop
24
  print(str_ptr[0]);
25
  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.

von Klaus W. (mfgkw)


Lesenswert?

z.B. so:
1
#include <stdlib.h>
2
#include <stddef.h>
3
#include <stdio.h>
4
#include <string.h>
5
6
enum
7
{
8
  deutsch,
9
  english,
10
} language = english;
11
12
13
int main( int nargs, char **args )
14
{
15
  const char *str_de[] =
16
    {
17
      "Text in deutsch",  // info
18
      "hallo Welt",       // hello
19
    };
20
21
  const char *str_en[] =
22
    {
23
      "text in english",  // info
24
      "hello world",      // hello
25
    };
26
27
  const char **str_ptr;
28
29
  // Initialisierung
30
  if(language == deutsch){
31
    str_ptr = str_de;
32
  }
33
  else{
34
    str_ptr = str_en;
35
  }
36
37
  // main loop
38
  printf( "%s\n", str_ptr[0] );
39
  printf( "%s\n", str_ptr[1] );
40
41
  return 0;
42
}

von Kay I. (imperator)


Lesenswert?

Wow ... da habt Ihr schnell geantwortet - Vielen Dank!

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

von Kay I. (imperator)


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!

von Mark M. (mom-jovi)


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!

von Peter (Gast)


Lesenswert?

du legst ja auch nur eine Stuct an und keine Variable.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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

von Klaus W. (mfgkw)


Lesenswert?

... und so sieht es besser aus:
1
struct spielfeld
2
{
3
    char koord[9][9];
4
} meinSpielfeld =  {{{'x','A','B','C','D','E','F','G','H'},
5
                     {'A','0','0','0','0','0','0','0','0'},
6
                     {'B','0','0','0','0','0','0','0','0'},
7
                     {'C','0','0','0','0','0','0','0','0'},
8
                     {'D','0','0','0','0','0','0','0','0'},
9
                     {'E','0','0','0','0','0','0','0','0'},
10
                     {'F','0','0','0','0','0','0','0','0'},
11
                     {'G','0','0','0','0','0','0','0','0'},
12
                     {'H','0','0','0','0','0','0','0','0'}}};
Zu gefälligen Beachtung die Variable meinSpielfeld und das
zusätzliche {}-Paar.

von Anfänger (Gast)


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

von Klaus W. (mfgkw)


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.

von Anfänger (Gast)


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!

von Christian J. (Gast)


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.
1
const char *menue[]=
2
{
3
    "Z80 System is online!\n",        // 0
4
    "---------------------------------"    // 1
5
    "\n(1)...........Load User Program",  // 2
6
    "\n(2)...........Start User Program",  // 3
7
    "\n(3)...........Clear Memory",      // 4
8
    "\n(4)...........Dump Memory",      // 5
9
    "\n(5)...........Restart System"    // 6
10
};

Damit sollen sie an die Uart geschickt werden
1
for (i=0;i<6;i++) {
2
  printstrng(menue[i]);
3
[code]
4
5
UNd das ist der Code für Strings drucken
6
7
[code]
8
9
/////////////////////////////////////////////////////////
10
// Zeichenketten ausgabe auf Uart
11
void printstrng(char *k)
12
{
13
  while ((*k) != '\0')
14
    putchar(*(k++));
15
}

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?

von Klaus W. (mfgkw)


Lesenswert?

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

von Christian J. (Gast)


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.

von Frank M. (ukw) (Moderator) Benutzerseite


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
von Markus F. (mfro)


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?

von Frank M. (ukw) (Moderator) Benutzerseite


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.

von Christian J. (Gast)


Angehängte Dateien:

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.

von Christian J. (Gast)


Lesenswert?

Ersetzt man i durch eine Zahl 0 im Funktionsaufruf, um es einfacher zu 
verstehen spuckt er das aus:
1
                         727 ;main.c:99: for (i=0;i<6;i++) {
2
   0203 16 00         [ 7]  728   ld  d,#0x00
3
   0205                     729 00107$:
4
                            730 ;main.c:100: printstrng(menue[0]);
5
   0205 2Ar00r00      [16]  731   ld  hl, (#_menue + 0)
6
   0208 D5            [11]  732   push  de
7
   0209 E5            [11]  733   push  hl
8
   020A CDr20r00      [17]  734   call  _printstrng
9
   020D F1            [10]  735   pop  af
10
   020E D1            [10]  736   pop  de
11
                            737 ;main.c:99: for (i=0;i<6;i++) {
12
   020F 14            [ 4]  738   inc  d
13
   0210 7A            [ 4]  739   ld  a,d
14
   0211 D6 06         [ 7]  740   sub  a, #0x06
15
   0213 38 F0         [12]  741   jr  C,00107$
16
17
18
19
                         788   .area _CODE
20
   0251                     789 ___str_0:
21
   0251 5A 38 30 20 53 79   790   .ascii "Z80 System is online!"
22
        73 74 65 6D 20 69
23
        73 20 6F 6E 6C 69
24
        6E 65 21

: Bearbeitet durch User
von Joachim B. (jar)


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.

von Markus F. (mfro)


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...

von Karl H. (kbuchegg)


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)

von Karl H. (kbuchegg)


Lesenswert?

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

von Karl H. (kbuchegg)


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.

von Karl H. (kbuchegg)


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 User
von Christian J. (Gast)


Angehängte Dateien:

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.

von Christian J. (Gast)


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++));

von Karl H. (kbuchegg)


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
1
    0024 7E            [ 7]  166   ld  a,(hl)

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

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

also der Wert vom PUSH DE

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

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> als 2.tes vom Stack. D.h. das ist der ältere der beiden PUSH vom
> Aufrufer hier
>
1
> 020F 46 [ 7] 738 ld b,(hl)
2
> 0210 D5 [11] 739 push de
3
> 0211 C5 [11] 740 push bc
4
> 0212 CDr20r00 [17] 741 call _printstrng
5
> ...
6
>
>
> 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 User
von Christian J. (Gast)


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.

von Karl H. (kbuchegg)


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 User
von Christian J. (Gast)


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.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Ist das wirklich ok? Habe mal ein

printstrg(menue[0]);

kompiliert.

Das ergibt
1
                      725 ;main.c:95: printstrng(menue[0]);
2
   0200 2Ar00r00      [16]  726   ld  hl, (#_menue + 0)
3
   0203 E5            [11]  727   push  hl
4
   0204 CDr20r00      [17]  728   call  _printstrng
5
   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.
1
Das kommt nochmal hier vor:
2
3
0000                     829 __xinit__menue:
4
   0000r61r02               830   .dw ___str_0
5
   0002r78r02               831   .dw ___str_1
6
   0004r9Ar02               832   .dw ___str_2
7
   0006rBBr02               833   .dw ___str_3
8
   0008rDDr02               834   .dw ___str_4
9
   000ArF9r02               835   .dw ___str_5
10
   000Cr14r03               836   .dw ___str_6
11
                            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:
1
                         800   .area _CODE
2
   0261                     801 ___str_0:
3
   0261 5A 38 30 20 53 79   802   .ascii "Z80 System is online!"
4
        73 74 65 6D 20 69
5
        73 20 6F 6E 6C 69
6
        6E 65 21
7
   0276 0A                  803   .db 0x0A
8
   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.
1
Area                                    Addr        Size        Decimal Bytes (Attributes)
2
--------------------------------        ----        ----        ------- ----- ------------
3
_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/

von Christian J. (Gast)


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

von Karl H. (kbuchegg)


Lesenswert?

Christian J. schrieb:

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

Vorsicht. Das ist ein anderer Befehl.

Der Z80 kann
1
    LD   HL, nn          ; lade HL mit dem Wert nn
1
    LD   HL,(nn)         ; lade HL mit dem Wert, den du unter der
2
                         ; 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
1
   0200 2Ar00r00      [16]  726   ld  hl, (#_menue + 0)

holt er sich also den Inhalt des Speichers von hier
1
0000                     829 __xinit__menue:
2
   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
1
0000                     829 __xinit__menue:
2
   0000r61r02               830   .dw ___str_0
3
   0002r78r02               831   .dw ___str_1    ; <----------
4
   0004r9Ar02               832   .dw ___str_2
5
   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 User
von Christian J. (Gast)


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.

von Christian J. (Gast)


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.

von Karl H. (kbuchegg)


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
1
const char* const menu[] = {
2
  "String 1",
3
  "String 2"
4
};

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.

von Christian J. (Gast)


Angehängte Dateien:

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:
1
                         740 ;main.c:95: printstrng(menu[0]);
2
   0209 2Ar6Br02      [16]  741   ld  hl, (#_menu + 0)
3
   020C E5            [11]  742   push  hl
4
   020D CDr20r00      [17]  743   call  _printstrng
5
   0210 F1            [10]  744   pop  af

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

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


Just for fun mal hier der Startup Code
1
;--------------------------------------------------------------------------
2
; crt0.s - Generic crt0.s for a Z80
3
;
4
; Written by Christian Julius in 10.2014 for a Minimum Z80 System
5
; with Mostek 3801 Multi I/O Chip
6
;--------------------------------------------------------------------------
7
8
  .module crt0      ; Modul Name für den Linker
9
10
  ; Memory Map Adressen der Zeropage (vom Benutzer definierbar)
11
  ; 0x00           Reset Vector und Aufruf Hauptprogramm
12
  ; 0x38          Mode 1 Int Vektor
13
  ; 0x40          Mode 2 Vektor Tabelle für STI Mostek Multi I/O
14
  ; 0x66          NMI Reset Vektor
15
  ; 0x80          Copyright String
16
  ; 0x100          User Programm
17
18
  ; Definitions
19
  stack          = 0xffff  ; fix
20
  adr_vec_table    = 0x40    ; frei
21
  adr_copyright       = 0x80    ; frei
22
  adr_nmi        = 0x66    ; fix
23
24
  ; Globale Funktionen und Variablen für das C-Programm
25
26
    .globl  _main
27
  .globl  _nmi_vint     ; Funktion des NMI Handlers
28
29
  ; Interruptroutinen für den Mostek MK3801 Multi I/O Baustein
30
  ; Manual STI Baustein MK3801 Figure 7
31
  .globl  _int_sti_gpi_0  ; General Purpose Interrupt 0
32
  .globl  _int_sti_gpi_1  ; General Purpose Interrupt 1
33
  .globl  _int_sti_gpi_2   ; General Purpose Interrupt 2
34
  .globl  _int_sti_gpi_3  ; General Purpose Interrupt 3
35
  .globl  _int_sti_timer_d
36
  .globl  _int_sti_timer_c
37
  .globl  _int_sti_gpi_4  ; General Purpose Interrupt 4
38
  .globl  _int_sti_gpi_5  ; General Purpose Interrupt 5
39
  .globl  _int_sti_timer_b
40
  .globl  _int_sti_transmit_error
41
  .globl  _int_sti_transmit_buffer_empty
42
  .globl  _int_sti_receive_error
43
  .globl  _int_sti_receive_buffer_full
44
  .globl  _int_sti_timer_a
45
  .globl  _int_sti_gpi_6  ; General Purpose Interrupt 6
46
  .globl  _int_sti_gpi_7  ; General Purpose Interrupt 7
47
  ; Mode 1, alles auf eine Routine umleiten
48
  .globl  _int_sti_all
49
50
51
  ; -------------------------------------------------------------
52
  .area  _HEADER (ABS)  ; Ende des Headers
53
54
55
  ;///////////////////////////////////////////////////////////
56
  ; Reset vector bei Kaltstart und Sprung ins User Programm
57
58
  .org   0
59
60
   jp init
61
  
62
  ; Copyright String (maximal 16 Zeichen)
63
  .org adr_copyright
64
  .ascis "(C)2014\20C.Julius\0"
65
66
  ;///////////////////////////////////////////////////////////
67
  ;// Mode 1 Interrupt
68
  .org 0x38
69
  jp _int_sti_all
70
71
72
  ;///////////////////////////////////////////////////////////
73
  ; Tabelle der Mode 2 Int Vektoren auf die Handler Funktionen im C Modul
74
  ; Reihenfolge beachten !!! Siehe Manual Mostek 3801, Interrupt Tabelle
75
  .org 0x40
76
  .dw (_int_sti_gpi_0)
77
  .dw (_int_sti_gpi_1)
78
  .dw (_int_sti_gpi_2)
79
  .dw (_int_sti_gpi_3)
80
  .dw (_int_sti_timer_d)
81
  .dw (_int_sti_timer_c)
82
  .dw (_int_sti_gpi_4)
83
  .dw (_int_sti_gpi_5)
84
  .dw  (_int_sti_timer_b)
85
  .dw  (_int_sti_transmit_error)
86
  .dw  (_int_sti_transmit_buffer_empty)
87
  .dw  (_int_sti_receive_error)
88
  .dw  (_int_sti_receive_buffer_full)
89
  .dw  (_int_sti_timer_a)
90
  .dw  (_int_sti_gpi_6)
91
  .dw  (_int_sti_gpi_7)
92
93
  ;///////////////////////////////////////////////////////////
94
  ; NMI Interrupt 0x66, muss mit retn abgeschlossen werden
95
  .org  0x66
96
  jp _nmi_vint    ; Aufruf Handler im C Modul main.c
97
  
98
  ;; Start des Hauptprogramms nach der Zeropage
99
  
100
init:
101
  ;; Stack an Spitze des RAM legen
102
  ld  sp,#stack
103
    jp   _main    ; ###### Hauptprogramm aufrufen #######
104
  halt      ; Stop und Schluss
105
endlos:
106
  jr endlos    ; Sicher ist sicher
107
    
108
  
109
  ; Area Definitionen, nicht verändern!
110
111
  ;; Ordering of segments for the linker.
112
  .area _HOME
113
  .area _CODE
114
  .area _GSINIT
115
  .area _GSFINAL
116
  .area _GSINIT
117
  .area _DATA
118
  .area _BSEG
119
  .area _BSS
120
  .area _HEAP

von Christian J. (Gast)


Lesenswert?

Nachwort:

Dein Vorschlag funktioniert !!!!!

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

von Karl H. (kbuchegg)


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
1
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 User
von Karl H. (kbuchegg)


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 User
von Christian J. (Gast)


Lesenswert?

Mir macht die Sache mit dem Initilizer noch Sorge, grad mal etwas 
gebastelt:

Damit er nicht alles wegoptimiert ein volatile
1
volatile uint16_t n = 0x1234;
2
volatile uint16_t myvar = 0xabcd;
3
4
n = 5 * i;
5
n = myvar;
Er macht es tatsächlich, vor Main fängt er globale Vars zu init'en:
1
                        743 ;main.c:90: volatile uint16_t n = 0x1234;
2
   0210 DD 36 FE 34   [19]  744   ld  -2 (ix),#0x34
3
   0214 DD 36 FF 12   [19]  745   ld  -1 (ix),#0x12
4
                            746 ;main.c:91: volatile uint16_t myvar = 0xabcd;
5
   0218 21 CD AB      [10]  747   ld  hl,#0xABCD
6
   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
von Karl H. (kbuchegg)


Lesenswert?

Christian J. schrieb:

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

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
1
volatile int a[20] = { 0, 10, 1, 11, 2, 12, 3, 13, 4, 14,
2
                       5, 15, 6, 16, 7, 17, 8, 18, 9, 19 };
3
4
int main()
5
{
6
}

irgendeine Form eines Initialisierungscodes muss es geben.

: Bearbeitet durch User
von Christian J. (Gast)


Lesenswert?

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

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

von Karl H. (kbuchegg)


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
>
1
>  000A                     972 __xinit__foom:
2
>    000A 01 00               973   .dw #0x0001
3
>    000C 02 00               974   .dw #0x0002
4
>    000E 03 00               975   .dw #0x0003
5
>    0010 04 00               976   .dw #0x0004
6
>    0012 05 00               977   .dw #0x0005
7
>                             978   .area _CABS (ABS)
8
>

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

: Bearbeitet durch User
von Christian J. (Gast)


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.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:


> Hilft aber nichts. Irgendwo MUSS kopiert werden!

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

von Christian J. (Gast)


Lesenswert?


von Karl H. (kbuchegg)


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.

von Karl H. (kbuchegg)


Lesenswert?

Christian J. schrieb:
> Da steht was drüber
>
> http://atariage.com/forums/topic/212505-sdcc-330-released-today/

Das
1
        .area _GSINIT
2
gsinit::
3
        ld      bc, #l__INITIALIZER
4
        ld      a,b
5
        or      a,c
6
        jr      z, gsinit_next
7
        ld      de, #s__INITIALIZED
8
        ld      hl, #s__INITIALIZER
9
10
        ldir
11
gsinit_next:
12
13
14
        .area _GSFINAL
15
        ret
16
        ;
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 User
von Karl H. (kbuchegg)


Lesenswert?

Zu deinem Startup Code
1
....
2
    jmp init
3
4
....
5
6
init:
7
  ;; Stack an Spitze des RAM legen
8
  ld  sp,#stack
9
    jp   _main    ; ###### Hauptprogramm aufrufen #######
10
....

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:
1
....
2
3
init:
4
  ;; Stack an Spitze des RAM legen
5
  ld  sp,#stack
6
  call gsinit
7
  jp   _main    ; ###### Hauptprogramm aufrufen #######

: Bearbeitet durch User
von Christian J. (Gast)


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

von Karl H. (kbuchegg)


Lesenswert?

?
1
    
2
  
3
  ; Area Definitionen, nicht verändern!
4
5
  ;; Ordering of segments for the linker.
6
  .area _HOME
7
  .area _CODE
8
  .area _GSINIT
9
  .area _GSFINAL
10
  .area _GSINIT
11
  .area _DATA
12
  .area _BSEG
13
  .area _BSS
14
  .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.
1
start_program:
2
3
;
4
; Vorgeplänkel wegen Interrupts. Wird dich weniger interessieren
5
;
6
  im       1                      ; interrupt mode -> rst 38h
7
  di
8
9
;
10
; BSS ausnullen, damit wie vom C Standard vorgeschrieben alle globalen
11
; Variablen einen Wert von 0 haben
12
;
13
  xor     a                       ; clear carry
14
  ld      bc,#0x3b8    ; ram size left
15
  ld      hl,#0x7000    ; starting from 7000
16
  ld      de,#0x7001
17
  ld      (hl),a
18
  ldir                            ; zero-fill bss
19
20
;
21
; dann die globalen Variablen initialisieren, die im C Code
22
; von 0 verschiedene Werte haben
23
;
24
  call gsinit          ; Initialize global variables.
25
26
;
27
; irgend eine systemspezifische Initialisierung. Offenbar irgendwas mit Sounds
28
; interessiert dich nicht und fliegt raus
29
;
30
  ld  h,#0 ; set dummy sound table
31
  call set_snd_table
32
33
;
34
;
35
; random Generator.
36
; wenn mans braucht
37
;
38
  ld      hl,#0x0033                ; initialise random generator
39
  ld      (0x73c8),hl
40
41
;
42
; dann kommt irgendwas mit einem Display
43
;
44
                                    ; set screen mode 2 text
45
  call    0x1f85                   ; set default VDP regs 16K
46
  ld      de,#0x4000                ; clear VRAM
47
  xor     a
48
  ld      l,a
49
  ld      h,a
50
  call    0x1f82
51
52
;
53
;
54
; und erst jetzt ist der Startup soweit fertig, dass main loslegen kann
55
;
56
    ; call main rountine
57
  jp      _main

bei dir fehlt da ja einiges im Startup!

: Bearbeitet durch User
von Christian J. (Gast)


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.

1
;--------------------------------------------------------------------------
2
; crt0.s - Generic crt0.s for a Z80
3
;
4
; Written by Christian Julius in 10.2014 for a Minimum Z80 System
5
; with Mostek 3801 Multi I/O Chip
6
;--------------------------------------------------------------------------
7
8
  .module crt0      ; Modul Name für den Linker
9
10
  ; Memory Map Adressen der Zeropage (vom Benutzer definierbar)
11
  ; 0x00           Reset Vector und Aufruf Hauptprogramm
12
  ; 0x38          Mode 1 Int Vektor
13
  ; 0x40          Mode 2 Vektor Tabelle für STI Mostek Multi I/O
14
  ; 0x66          NMI Reset Vektor
15
  ; 0x80          Copyright String
16
  ; 0x100          User Programm
17
18
  ; Definitions
19
  stack          = 0xffff  ; fix
20
  adr_vec_table    = 0x40    ; frei
21
  adr_copyright       = 0x80    ; frei
22
  adr_nmi        = 0x66    ; fix
23
24
  ; Globale Funktionen und Variablen für das C-Programm
25
26
    .globl  _main
27
  .globl  _nmi_vint     ; Funktion des NMI Handlers
28
29
  ; Interruptroutinen für den Mostek MK3801 Multi I/O Baustein
30
  ; Manual STI Baustein MK3801 Figure 7
31
  .globl  _int_sti_gpi_0  ; General Purpose Interrupt 0
32
  .globl  _int_sti_gpi_1  ; General Purpose Interrupt 1
33
  .globl  _int_sti_gpi_2   ; General Purpose Interrupt 2
34
  .globl  _int_sti_gpi_3  ; General Purpose Interrupt 3
35
  .globl  _int_sti_timer_d
36
  .globl  _int_sti_timer_c
37
  .globl  _int_sti_gpi_4  ; General Purpose Interrupt 4
38
  .globl  _int_sti_gpi_5  ; General Purpose Interrupt 5
39
  .globl  _int_sti_timer_b
40
  .globl  _int_sti_transmit_error
41
  .globl  _int_sti_transmit_buffer_empty
42
  .globl  _int_sti_receive_error
43
  .globl  _int_sti_receive_buffer_full
44
  .globl  _int_sti_timer_a
45
  .globl  _int_sti_gpi_6  ; General Purpose Interrupt 6
46
  .globl  _int_sti_gpi_7  ; General Purpose Interrupt 7
47
  ; Mode 1, alles auf eine Routine umleiten
48
  .globl  _int_sti_all
49
  
50
  
51
    .globl l__INITIALIZER
52
    .globl s__INITIALIZER
53
    .globl s__INITIALIZED
54
55
56
  ; -------------------------------------------------------------
57
  .area  _HEADER (ABS)  ; Ende des Headers
58
59
60
  ;///////////////////////////////////////////////////////////
61
  ; Reset vector bei Kaltstart und Sprung ins User Programm
62
63
  .org   0
64
65
   jp init
66
  
67
  ; Copyright String (maximal 16 Zeichen)
68
  .org adr_copyright
69
  .ascis "(C)2014\20C.Julius\0"
70
71
  ;///////////////////////////////////////////////////////////
72
  ;// Mode 1 Interrupt
73
  .org 0x38
74
  jp _int_sti_all
75
76
77
  ;///////////////////////////////////////////////////////////
78
  ; Tabelle der Mode 2 Int Vektoren auf die Handler Funktionen im C Modul
79
  ; Reihenfolge beachten !!! Siehe Manual Mostek 3801, Interrupt Tabelle
80
  .org 0x40
81
  .dw (_int_sti_gpi_0)
82
  .dw (_int_sti_gpi_1)
83
  .dw (_int_sti_gpi_2)
84
  .dw (_int_sti_gpi_3)
85
  .dw (_int_sti_timer_d)
86
  .dw (_int_sti_timer_c)
87
  .dw (_int_sti_gpi_4)
88
  .dw (_int_sti_gpi_5)
89
  .dw  (_int_sti_timer_b)
90
  .dw  (_int_sti_transmit_error)
91
  .dw  (_int_sti_transmit_buffer_empty)
92
  .dw  (_int_sti_receive_error)
93
  .dw  (_int_sti_receive_buffer_full)
94
  .dw  (_int_sti_timer_a)
95
  .dw  (_int_sti_gpi_6)
96
  .dw  (_int_sti_gpi_7)
97
98
  ;///////////////////////////////////////////////////////////
99
  ; NMI Interrupt 0x66, muss mit retn abgeschlossen werden
100
  .org  0x66
101
  jp _nmi_vint    ; Aufruf Handler im C Modul main.c
102
  
103
  ;; Start des Hauptprogramms nach der Zeropage
104
  .org 0xa0
105
  
106
init:
107
  
108
  ld  sp,#stack  ;; Stack an Spitze des RAM legen
109
  call gsinit    ;; Initialize Global Variables
110
    jp   _main    ; ###### Hauptprogramm aufrufen #######
111
endlos:
112
  jr endlos    ; Sicher ist sicher
113
    
114
  
115
  ;; Ordering of segments for the linker.
116
  .area _HOME
117
  .area _CODE
118
  .area _INITILIZER
119
  .area _GSINIT
120
  .area _GSFINAL
121
  .area _DATA
122
  .area _INITILIZED
123
  .area _BSEG
124
  .area _BSS
125
  .area _HEAP
126
  
127
  .area _GSINIT
128
  gsinit::
129
        ld      bc, #l__INITIALIZER
130
        ld      a,b
131
        or      a,c
132
        jr      z, gsinit_next
133
        ld      de, #s__INITIALIZED
134
        ld      hl, #s__INITIALIZER
135
        ldir
136
137
gsinit_next:
138
139
     .area _GSFINAL
140
     ret

von Christian J. (Gast)


Lesenswert?

Auch andere haben das gleiche Problem... gähn

http://comments.gmane.org/gmane.comp.compilers.sdcc.user/2405

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.
1
  
2
init:
3
  
4
  ld  sp,#stack  ;; Stack an Spitze des RAM legen
5
  
6
  ld      bc, #l__INITIALIZER
7
    ld      a,b
8
    or      a,c
9
    jr      z, gsinit_next
10
    ld      de, #s__INITIALIZED
11
    ld      hl, #s__INITIALIZER
12
    ldir
13
14
gsinit_next:
15
   
16
  ;call gsinit    ;; Initialize Global Variables
17
  
18
    jp   _main    ; ###### Hauptprogramm aufrufen #######
19
endlos:
20
  jr endlos    ; Sicher ist sicher
21
    
22
  
23
  ;; Ordering of segments for the linker.
24
  .area _HOME
25
  .area _CODE
26
  .area _INITILIZER
27
  .area _GSINIT
28
  .area _GSFINAL
29
  .area _DATA
30
  .area _INITILIZED
31
  .area _BSEG
32
  .area _BSS
33
  .area _HEAP

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

wird zu

21 20 20 also hl, 2029

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

11 02 20   also ld de,2002

das passt auch.

von Karl H. (kbuchegg)


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).

von Karl H. (kbuchegg)


Lesenswert?

Könnte der Tippfehler hier
1
  ;; Ordering of segments for the linker.
2
  .area _HOME
3
  .area _CODE
4
  .area _INITILIZER
mit reinspielen (da fehlt ein A in INITIALIZER)

hier
1
...
2
  .area _INITILIZED
nochmal.

: Bearbeitet durch User
von Philipp Klaus Krause (Gast)


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

von Karl H. (kbuchegg)


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.

von Philipp Klaus Krause (Gast)


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

von Philipp Klaus Krause (Gast)


Lesenswert?

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

Die wichtigsten areas sind:
1
  .area  _CODE
2
  .area  _INITIALIZER
3
  .area  _HOME
4
  .area  _GSINIT
5
  .area  _DATA
6
  .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

von Philipp Klaus Krause (Gast)


Lesenswert?

Hier ein Beispiel für crt0.s (etwas älter, für ColecoVision, aus libcv 
0.22):
1
; crt0.s for Colecovision cart
2
3
  .module crt0
4
  .globl _main
5
  .globl _cv_init
6
  .globl _cv_spint_handler
7
  .globl _cv_vint
8
  .globl _cv_start
9
  .globl __sdcc_call_hl
10
11
  .area _HEADER(ABS)
12
  .org 0x8000
13
14
  .db 0x55, 0xaa      ; Title screen and 12 second delay - swap 0x55 and 0xaa not to skip it.
15
  .dw 0                ; Sprite name table for BIOS
16
  .dw 0                ; Sprite order table for BIOS.
17
  .dw 0                ; Buffer for BIOS.
18
  .dw 0                ; Controller map for BIOS.
19
  .dw _cv_start            ; where to start execution of program.
20
  jp  0x0    ; RST 0x08      
21
  jp  0x0    ; RST 0x10
22
  jp  0x0    ; RST 0x18
23
  jp  0x0    ; RST 0x20
24
  jp  0x0    ; RST 0x28
25
  jp  0x0    ; RST 0x30
26
  jp spint  ; RST 0x38 - spinner - maskable interrupt
27
  jp vint    ; Vertical retrace - NMI
28
  .ascii " / / NOT"
29
30
  ; Ordering of segments for the linker - copied from sdcc crt0.s
31
  .area  _CODE
32
  .area  _INITIALIZER
33
  .area  _HOME
34
  .area  _GSINIT
35
  .area  _GSFINAL
36
  .area  _DATA
37
  .area  _INITIALIZED
38
  .area  _BSEG
39
  .area  _BSS
40
  .area  _HEAP
41
42
  .area  _CODE
43
44
_cv_start:
45
  ld sp, #0x7400      ; Set stack pointer directly above top of memory.
46
47
  ; Implicitly zeroed global and static variables. Do it here, before any call to not corrupt stack!
48
  ld  bc, #1023
49
  ld  hl,  #0x7000
50
  ld  (hl), #0x00
51
  ld  e, l
52
  ld  d, h
53
  inc  de
54
  ldir
55
56
  call gsinit        ; Initialize global and static variables.
57
58
  call _cv_init      ; Initialize Colecovision specific stuff.
59
  call _main
60
  rst 0x0        ; Restart when main() returns.
61
62
vint:
63
  push  af
64
  push  bc
65
  push  de
66
  push  hl
67
  push  iy
68
  call  _cv_vint
69
  pop  iy
70
  pop  hl
71
  pop  de
72
  pop  bc
73
  pop  af
74
  retn
75
76
spint:
77
  push  af
78
  push  bc
79
  push  de
80
  push  hl
81
  push  iy
82
  in  a, (#0xfc)
83
  ld  b, a
84
  in  a, (#0xff)
85
  ld  c, a
86
  push  bc
87
  ld  hl, (#_cv_spint_handler)
88
  call  __sdcc_call_hl
89
  pop  af
90
  pop  iy
91
  pop  hl
92
  pop  de
93
  pop  bc
94
  ei
95
  reti
96
97
  .area   _GSINIT
98
gsinit::
99
100
  ; Explicitly initialized global variables.
101
  ld  bc, #l__INITIALIZER
102
  ld  a, b
103
  or  a, c
104
  jr  Z, gsinit_static
105
  ld  de, #s__INITIALIZED
106
  ld  hl, #s__INITIALIZER
107
  ldir
108
109
gsinit_static:
110
  ; Explicitly initialized static variables inserted by compiler here.
111
112
  .area   _GSFINAL
113
  ret
114
115
  .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

von Philipp Klaus Krause (Gast)


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

von Christian J. (Gast)


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?

1
;--------------------------------------------------------------------------
2
; crt0.s - Generic crt0.s for a Z80
3
;
4
; Written by Christian Julius 
5
; with Mostek 3801 Multi I/O Chip
6
;--------------------------------------------------------------------------
7
8
  .module crt0      ; Modul Name für den Linker
9
10
  ; Memory Map Adressen der Zeropage (vom Benutzer definierbar)
11
  ; 0x00           Reset Vector und Aufruf Hauptprogramm
12
  ; 0x38          Mode 1 Int Vektor
13
  ; 0x40          Mode 2 Vektor Tabelle für STI Mostek Multi I/O
14
  ; 0x66          NMI Reset Vektor
15
  ; 0x80          Copyright String
16
  ; 0x100          User Programm
17
18
  ; Definitions
19
  stack          = 0xffff  ; fix
20
  adr_vec_table    = 0x40    ; frei
21
  adr_copyright       = 0x80    ; frei
22
  adr_nmi        = 0x66    ; fix
23
24
  ; Globale Funktionen und Variablen für das C-Programm
25
26
    .globl  _main
27
  .globl  _nmi_vint     ; Funktion des NMI Handlers
28
29
  ; Interruptroutinen für den Mostek MK3801 Multi I/O Baustein
30
  ; Manual STI Baustein MK3801 Figure 7
31
  .globl  _int_sti_gpi_0  ; General Purpose Interrupt 0
32
  .globl  _int_sti_gpi_1  ; General Purpose Interrupt 1
33
  .globl  _int_sti_gpi_2   ; General Purpose Interrupt 2
34
  .globl  _int_sti_gpi_3  ; General Purpose Interrupt 3
35
  .globl  _int_sti_timer_d
36
  .globl  _int_sti_timer_c
37
  .globl  _int_sti_gpi_4  ; General Purpose Interrupt 4
38
  .globl  _int_sti_gpi_5  ; General Purpose Interrupt 5
39
  .globl  _int_sti_timer_b
40
  .globl  _int_sti_transmit_error
41
  .globl  _int_sti_transmit_buffer_empty
42
  .globl  _int_sti_receive_error
43
  .globl  _int_sti_receive_buffer_full
44
  .globl  _int_sti_timer_a
45
  .globl  _int_sti_gpi_6  ; General Purpose Interrupt 6
46
  .globl  _int_sti_gpi_7  ; General Purpose Interrupt 7
47
  ; Mode 1, alles auf eine Routine umleiten
48
  .globl  _int_sti_all
49
  
50
  
51
    .globl l__INITIALIZER
52
    .globl s__INITIALIZER
53
    .globl s__INITIALIZED
54
55
56
  ; -------------------------------------------------------------
57
  .area  _HEADER (ABS)  ; Ende des Headers
58
59
60
  ;///////////////////////////////////////////////////////////
61
  ; Reset vector bei Kaltstart und Sprung ins User Programm
62
63
  .org   0
64
65
   jp init
66
  
67
  ;///////////////////////////////////////////////////////////
68
  ;// Mode 1 Interrupt
69
  .org 0x38
70
  jp _int_sti_all
71
72
73
  ;///////////////////////////////////////////////////////////
74
  ; Tabelle der Mode 2 Int Vektoren auf die Handler Funktionen im C Modul
75
  ; Reihenfolge beachten !!! Siehe Manual Mostek 3801, Interrupt Tabelle
76
  .org 0x40
77
  .dw (_int_sti_gpi_0)
78
  .dw (_int_sti_gpi_1)
79
  .dw (_int_sti_gpi_2)
80
  .dw (_int_sti_gpi_3)
81
  .dw (_int_sti_timer_d)
82
  .dw (_int_sti_timer_c)
83
  .dw (_int_sti_gpi_4)
84
  .dw (_int_sti_gpi_5)
85
  .dw  (_int_sti_timer_b)
86
  .dw  (_int_sti_transmit_error)
87
  .dw  (_int_sti_transmit_buffer_empty)
88
  .dw  (_int_sti_receive_error)
89
  .dw  (_int_sti_receive_buffer_full)
90
  .dw  (_int_sti_timer_a)
91
  .dw  (_int_sti_gpi_6)
92
  .dw  (_int_sti_gpi_7)
93
94
  ;///////////////////////////////////////////////////////////
95
  ; NMI Interrupt 0x66, muss mit retn abgeschlossen werden
96
  .org  0x66
97
  jp _nmi_vint    ; Aufruf Handler im C Modul main.c
98
  
99
  ;; Start des Hauptprogramms nach der Zeropage
100
  .org 0x80
101
  
102
init:
103
  
104
  ld  sp,#stack  ;; Stack an Spitze des RAM legen
105
  
106
  ; Ram ausnullen
107
  xor     a             ; clear a and carry
108
  ld      bc,#0xdfff    ; ram size left
109
  ld      hl,#0x2000    ; starting from 2000
110
  ld      de,#0x2001
111
  ld      (hl),a      ; 0 -> (2000)  
112
  ldir                  ; (HL) -> (DE)
113
  
114
    jp   _main    ; ###### Hauptprogramm aufrufen #######
115
endlos:
116
  jr endlos    ; Sicher ist sicher
117
    
118
  
119
  ;; Ordering of segments for the linker.
120
121
  .area  _CODE
122
  .area  _INITIALIZER
123
  .area  _HOME
124
  .area  _GSINIT
125
  .area  _GSFINAL
126
  .area  _DATA
127
  .area  _INITIALIZED
128
  .area  _BSEG
129
  .area  _BSS
130
  
131
  .area   _GSINIT
132
  ; Explicitly initialized global variables.
133
  ld  bc, #l__INITIALIZER
134
  ld  a, b
135
  or  a, c
136
  jr  Z, gsinit_static
137
  ld  de, #s__INITIALIZED
138
  ld  hl, #s__INITIALIZER
139
  ldir
140
  
141
gsinit_static:
142
  ; Explicitly initialized static variables inserted by compiler here.
143
144
  .area   _GSFINAL
145
  ret  
146
147
  .area _HOME

von Philipp Klaus Krause (Gast)


Lesenswert?

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

und
1
gsinit::

Philipp

von Christian J. (Gast)


Angehängte Dateien:

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

von Christian J. (Gast)


Lesenswert?

PS: Ich kompiliere mit

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

Ok, Zahnarzt wartet...

von Philipp Klaus Krause (Gast)


Lesenswert?

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

Philipp

von Christian J. (Gast)


Lesenswert?

Philipp Klaus Krause schrieb:
> Was passiert, wenn Du crt0.rel zuerst aufführtst?
>
>
1
> sdcc -mz80 --no-std-crt0 --code-loc 0x100 --data-loc 0x2000 crt0.rel 
2
> main.rel
3
>
>
> 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.

von Christian J. (Gast)


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:
>
>
1
>   .area  _CODE
2
>   .area  _INITIALIZER
3
>   .area  _HOME
4
>   .area  _GSINIT
5
>   .area  _DATA
6
>   .area  _INITIALIZED
7
>
>
> _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

von Christian J. (Gast)


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.
1
Area                                    Addr        Size        Decimal Bytes (Attributes)
2
--------------------------------        ----        ----        ------- ----- ------------
3
_INITIALIZER                        00000307    00000007 =           7. bytes (REL,CON)
1
                             82   .area _CODE
2
                             83   .area _INITIALIZER
3
   0000                      84 __xinit__myvar:
4
   0000 06                   85   .db #0x06  ; 6
5
   0001                      86 __xinit__arr:
6
   0001 55                   87   .db #0x55  ;  85  'U'
7
   0002 AA                   88   .db #0xAA  ; -86
8
   0003 55                   89   .db #0x55  ;  85  'U'
9
   0004 AA                   90   .db #0xAA  ; -86
10
   0005 55                   91   .db #0x55  ;  85  'U'
11
   0006 AA                   92   .db #0xAA  ; -86
12
                             93   .area _CABS (ABS)

Die Kopieroutine wird bei -data-loc 0x300 zu
1
  ; Explicitly initialized global variables.
2
  ld  bc, #07
3
  ld  a, b
4
  or  a, c
5
  jr  Z, gs1
6
  ld  de, #0321
7
  ld  hl, #0307
8
  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.

von Philipp Klaus Krause (Gast)


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

von Christian J. (Gast)


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.

von Christian J. (Gast)


Lesenswert?

Das Problem wir auch hier näher beschrieben:

http://dirk-hobbyblog.blogspot.de/2012/12/sdcc-crt0-ersetzen.html

von Philipp Klaus Krause (Gast)


Lesenswert?

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

Man muß dazu sdld selbst aufrufen, statt das sdcc zu überlassen. Zur 
Dokumentation:
1
>sdld
2
3
sdld Linker V03.00 + NoICE + sdld
4
5
Usage: [-Options] [-Option with arg] file
6
Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]
7
Startup:
8
  -p   Echo commands to stdout (default)
9
  -n   No echo of commands to stdout
10
Alternates to Command Line Input:
11
  -c                   ASlink >> prompt input
12
  -f   file[.lk]       Command File input
13
Libraries:
14
  -k   Library path specification, one per -k
15
  -l   Library file specification, one per -l
16
Relocation:
17
  -b   area base address = expression
18
  -g   global symbol = expression
19
Map format:
20
  -m   Map output generated as (out)file[.map]
21
  -w   Wide listing format for map file
22
  -x   Hexadecimal (default)
23
  -d   Decimal
24
  -q   Octal
25
Output:
26
  -i   Intel Hex as (out)file[.ihx]
27
  -s   Motorola S Record as (out)file[.s19]
28
  -j   NoICE Debug output as (out)file[.noi]
29
  -y   SDCDB Debug output as (out)file[.cdb]
30
List:
31
  -u   Update listing file(s) with link data as file(s)[.rst]
32
Case Sensitivity:
33
  -z   Disable Case Sensitivity for Symbols
34
Miscellaneous:
35
  -I   [iram-size] Check for internal RAM overflow
36
  -X   [xram-size] Check for external RAM overflow
37
  -C   [code-size] Check for code overflow
38
  -M   Generate memory usage summary file[.mem]
39
  -Y   Pack internal ram
40
  -S   [stack-size] Allocate space for stack
41
End:
42
  -e   or null line terminates input

von Christian J. (Gast)


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.

von Philipp Klaus Krause (Gast)


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

von Philipp Klaus Krause (Gast)


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

von Philipp Klaus Krause (Gast)


Lesenswert?

Hier ein Bespiel mit Deine Angaben:

test.c:
1
char ca[5] = "test";
2
char c;
3
4
void main(void)
5
{
6
}

crt0.s:
1
;--------------------------------------------------------------------------
2
; crt0.s - Generic crt0.s for a Z80
3
;
4
;
5
; with Mostek 3801 Multi I/O Chip
6
;--------------------------------------------------------------------------
7
8
    .module crt0            ; Modul Name für den Linker
9
10
    ; Memory Map Adressen der Zeropage (vom Benutzer definierbar)
11
    ; 0x00                     Reset Vector und Aufruf Hauptprogramm
12
    ; 0x38                    Mode 1 Int Vektor
13
    ; 0x40                    Mode 2 Vektor Tabelle für STI Mostek Multi I/O
14
    ; 0x66                    NMI Reset Vektor
15
    ; 0x80                    Copyright String
16
    ; 0x100                    User Programm
17
18
    ; Definitions
19
    stack                  = 0xffff    ; fix
20
    adr_vec_table        = 0x40        ; frei
21
    adr_copyright       = 0x80        ; frei
22
    adr_nmi                = 0x66        ; fix
23
24
    ; Globale Funktionen und Variablen für das C-Programm
25
26
    .globl    _main
27
    .globl  _nmi_vint         ; Funktion des NMI Handlers
28
29
    ; Interruptroutinen für den Mostek MK3801 Multi I/O Baustein
30
    ; Manual STI Baustein MK3801 Figure 7
31
    .globl  _int_sti_gpi_0    ; General Purpose Interrupt 0
32
    .globl  _int_sti_gpi_1    ; General Purpose Interrupt 1
33
    .globl  _int_sti_gpi_2     ; General Purpose Interrupt 2
34
    .globl  _int_sti_gpi_3    ; General Purpose Interrupt 3
35
    .globl  _int_sti_timer_d
36
    .globl  _int_sti_timer_c
37
    .globl  _int_sti_gpi_4    ; General Purpose Interrupt 4
38
    .globl  _int_sti_gpi_5    ; General Purpose Interrupt 5
39
    .globl  _int_sti_timer_b
40
    .globl  _int_sti_transmit_error
41
    .globl  _int_sti_transmit_buffer_empty
42
    .globl  _int_sti_receive_error
43
    .globl  _int_sti_receive_buffer_full
44
    .globl  _int_sti_timer_a
45
    .globl  _int_sti_gpi_6    ; General Purpose Interrupt 6
46
    .globl  _int_sti_gpi_7    ; General Purpose Interrupt 7
47
    ; Mode 1, alles auf eine Routine umleiten
48
    .globl  _int_sti_all
49
    
50
    
51
    .globl l__INITIALIZER
52
    .globl s__INITIALIZER
53
    .globl s__INITIALIZED
54
55
56
    ;///////////////////////////////////////////////////////////
57
    ; Reset vector bei Kaltstart und Sprung ins User Programm
58
    .area _HEADER(ABS)
59
    .org     0
60
61
     jp init
62
    
63
    ;///////////////////////////////////////////////////////////
64
    ;// Mode 1 Interrupt
65
    .org 0x38
66
    jp _int_sti_all
67
68
69
    ;///////////////////////////////////////////////////////////
70
    ; Tabelle der Mode 2 Int Vektoren auf die Handler Funktionen im C Modul
71
    ; Reihenfolge beachten !!! Siehe Manual Mostek 3801, Interrupt Tabelle
72
    .org 0x40
73
    .dw (_int_sti_gpi_0)
74
    .dw (_int_sti_gpi_1)
75
    .dw (_int_sti_gpi_2)
76
    .dw (_int_sti_gpi_3)
77
    .dw (_int_sti_timer_d)
78
    .dw (_int_sti_timer_c)
79
    .dw (_int_sti_gpi_4)
80
    .dw (_int_sti_gpi_5)
81
    .dw    (_int_sti_timer_b)
82
    .dw    (_int_sti_transmit_error)
83
    .dw    (_int_sti_transmit_buffer_empty)
84
    .dw    (_int_sti_receive_error)
85
    .dw    (_int_sti_receive_buffer_full)
86
    .dw    (_int_sti_timer_a)
87
    .dw    (_int_sti_gpi_6)
88
    .dw    (_int_sti_gpi_7)
89
90
    ;///////////////////////////////////////////////////////////
91
    ; NMI Interrupt 0x66, muss mit retn abgeschlossen werden
92
    .org  0x66
93
    jp _nmi_vint        ; Aufruf Handler im C Modul main.c
94
    
95
  ; Ordering of segments for the linker - copied from sdcc crt0.s
96
  .area  _CODE
97
  .area  _INITIALIZER
98
  .area  _HOME
99
  .area  _GSINIT
100
  .area  _GSFINAL
101
  .area  _DATA
102
  .area  _INITIALIZED
103
  .area  _BSEG
104
  .area  _BSS
105
  .area  _HEAP
106
107
  .area  _CODE
108
    
109
init:
110
    
111
    ld    sp,#stack    ;; Stack an Spitze des RAM legen
112
    
113
    ; Ram ausnullen
114
    xor     a             ; clear a and carry
115
    ld      bc,#0xdfff    ; ram size left
116
    ld      hl,#0x2000    ; starting from 2000
117
    ld      de,#0x2001
118
    ld      (hl),a          ; 0 -> (2000)   
119
    ldir                  ; (HL) -> (DE)
120
    
121
  call gsinit
122
    jp     _main        ; ###### Hauptprogramm aufrufen #######
123
124
endlos:
125
    jr endlos        ; Sicher ist sicher
126
       
127
    
128
gsinit::
129
130
  ; Explicitly initialized global variables.
131
  ld  bc, #l__INITIALIZER
132
  ld  a, b
133
  or  a, c
134
  jr  Z, gsinit_static
135
  ld  de, #s__INITIALIZED
136
  ld  hl, #s__INITIALIZER
137
  ldir
138
139
gsinit_static:
140
  ; Explicitly initialized static variables inserted by compiler here.
141
142
  .area   _GSFINAL
143
  ret
144
145
  .area _HOME

Kompilieren mit:
1
sdasz80 -plosgff crt0.s
2
sdcc -mz80 test.c -c
3
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

von Philipp Klaus Krause (Gast)


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

von Christian J. (Gast)


Angehängte Dateien:

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 .....

von Philipp Klaus Krause (Gast)


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

von Philipp Klaus Krause (Gast)


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:
1
  ;; Ordering of segments for the linker.
2
  .area  _CODE
3
  .area   _HEADER
4
  .area   _HEADER0
5
  .area   _HEADER1
6
  .area   _HEADER2
7
  .area   _HEADER3
8
  .area   _HEADER4
9
  .area   _HOME
10
  .area  _INITIAL
11
  .area   _INITILIZER
12
  .area  _GSINIT
13
  .area  _GSFINAL
14
  .area  _DATA
15
  .area  _BSEG
16
  .area  _BSS
17
  .area   _HEAP

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

Richtig wäre z.B.:
1
  ;; Ordering of segments for the linker.
2
  .area  _CODE
3
  .area  _INITIALIZER
4
  .area  _HOME
5
  .area  _GSINIT
6
  .area  _GSFINAL
7
  .area  _DATA
8
  .area  _INITIALIZED
9
  .area  _BSEG
10
  .area  _BSS
11
  .area  _HEAP

2) Der Aufruf von sdcc zum Linken

Aus compile.sh:
1
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.:
1
sdcc -mz80 --no-std-crt0 --vc --code-loc 0x0100 --data-loc 0x3000 crt0.rel main.rel

von Christian J. (Gast)


Angehängte Dateien:

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
1
char abc = 5;
2
3
int main() {
4
5
    InitHardware();
6
    SetDigit(abc);
7
    while(1);
8
    return(0);
9
}

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

von Christian J. (Gast)


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?

von Christian J. (Gast)


Angehängte Dateien:

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

von Christian J. (Gast)


Angehängte Dateien:

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.

von Christian J. (Gast)


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.....

1
sdasz80 -plosgff -o -l crt0.rel crt0.s
2
sdcc -mz80 main.c -c
3
echo "Linke beide Dateien...."
4
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.
1
; NMI Interrupt 0x66, muss mit retn abgeschlossen werden
2
  .org  0x66
3
  jp _nmi_vint    ; Aufruf Handler im C Modul main.c
4
5
  ; Ordering of segments for the linker - copied from sdcc crt0.s
6
    ;; Ordering of segments for the linker.
7
    .area  _CODE
8
    .area  _INITIALIZER
9
    .area  _HOME
10
    .area  _GSINIT
11
    .area  _GSFINAL
12
    .area  _DATA
13
    .area  _INITIALIZED
14
    .area  _BSEG
15
    .area  _BSS
16
    .area  _HEAP
17
18
    .area  _CODE
19
  
20
  ;; ------- Start des Hauptprogramms nach der Zeropage  -----------
21
  
22
  init:
23
  
24
  ld  sp,#stack  ;; Stack an Spitze des RAM legen
25
  
26
  ; Ram ausnullen
27
  xor     a             ; clear a and carry
28
  ld      bc,#0xdfff    ; ram size left
29
  ld      hl,#0x2000    ; starting from 2000
30
  ld      de,#0x2001
31
  ld      (hl),a      ; 0 -> (2000)  
32
  ldir                  ; (HL) -> (DE)
33
34
  ; Explicitly initialized global variables.
35
  ld  bc, #l__INITIALIZER
36
  ld  a, b
37
  or  a, c
38
  jr  Z, weiter
39
  ld  de, #s__INITIALIZED
40
  ld  hl, #s__INITIALIZER
41
  ldir
42
43
weiter:  
44
  jp   _main    ; ###### Hauptprogramm aufrufen #######
45
endlos:
46
  jr endlos    ; Sicher ist sicher
47
    halt
48
  ret

von Philipp Klaus Krause (Gast)


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
1
sdasz80 -plosgff -o -l crt0.rel crt0.s
2
sdcc -mz80 main.c
3
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

von Philipp Klaus Krause (Gast)


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

von Christian J. (Gast)


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.

von Christian J. (Gast)


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

von Philipp Klaus Krause (Gast)


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

von Philipp Klaus Krause (Gast)


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.
1
.area _TEST1(ABS)
2
.org     23

ist ok, aber

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

nicht.

Philipp

von Philipp Klaus Krause (Gast)


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

von Philipp Klaus Krause (Gast)


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

von Christian J. (Gast)


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

von Jens (Gast)


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:
1
    .area   _GSINIT
2
gsinit::
3
    ; copy initialized variables to 'RAM'
4
    ld  bc, #l__INITIALIZER
5
    ld  a, b
6
    or  a, c
7
    jr  Z, gsinit_zero
8
    ld  de, #s__INITIALIZED
9
    ld  hl, #s__INITIALIZER
10
    ldir
11
12
gsinit_zero:
13
    ; did we have data to zero out?
14
    ld  bc, #l__DATA
15
    ld  a, b
16
    or  a, c
17
    jr  Z, gsinit_next
18
19
    ; zero uninitialized stuff
20
    xor     a             ; clear a and carry
21
    ld      bc,#l__DATA   ; ram size left
22
    ld      hl,#s__DATA
23
    ld      de,#s__DATA+1
24
    ld      (hl),a        
25
    ldir
26
27
gsinit_next:
28
29
    .area   _GSFINAL
30
    ret

Jens

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