Forum: Mikrocontroller und Digitale Elektronik ARM Assembler - String an serielle Schnittstelle ausgeben


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Peter W. (ja_wasser)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,
wir sollen eine Funktion in ARM Assembler programmieren die einen 
gegebenen string an die serielle schnittstelle ausgibt.

Eine put character Funktion haben wir gegeben und wir sollen eine put 
String Funktion schreiben. Das Zeichen bzw. der String der ausgegeben 
werden soll steht in r0 (nehm ich an). Der String terminiert mit '\0'.

Das hier ist die put String Funktion:
1
puts:
2
  stmfd sp!,{lr}  @ Retten der Register
3
  mov r4, r0     @ start-adresse von string (r0) in r4 laden
4
loop1:
5
  ldrb r0, [r4]  @ aktuelle adresse von string in r0 laden
6
  cmp r0, #0    @ ueberpruefen ob der string mit 0 terminiert
7
  beq fertig    @ falls ja sind wir fertig
8
  bl  putc    @ ansonsten putc aufrufen und zeichen an serielle schnittstelle uebertragen
9
  # cmp r0, #0    @ ????
10
  # beq loop1
11
  add r4, #1    @ adresse des strings um eins erhoehen um nächstes zeichen zu bekommen
12
  b loop1      @ zum anfang der loop springen
13
fertig
14
  ldmfd sp!,{pc}  @ Rücksprung

Problem ist, dass ich beim kompilieren die Fehlermeldung "bad 
instruction 'fertig'" bekomme. Also der bezieht sich dann auf diese
  ldmfd sp!,{pc}  @ Rücksprung
Zeile, aber ich weiß nicht was da falsch ist? Dieses ldmfd war auch 
schon vorgegeben und ich hab davor halt nur ein Marker "fertig" gesetzt, 
damit ich da hinspringen kann wenn der string endet.

: Verschoben durch Moderator
von Nop (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Peter W. schrieb:

> fertig
>   ldmfd sp!,{pc}  @ Rücksprung

Sonst hast Du nach den Labels ja nen Doppelpunkt, bei dem nicht.

von Peter W. (ja_wasser)


Bewertung
0 lesenswert
nicht lesenswert
ah danke, ja jetzt kompiliert er es.

Stimmt die funktion denn ansonsten? Kann es momentan nicht testen weil 
ich den mikrocontroller hier nicht hab. Ich hab die lösung ehrlich 
gesagt von jemanden übernommen aber so wirklich sinn macht das ganze für 
mich nicht. die kommentare hab ich selber geschrieben aber zum beispiel 
diese zwei zeilen machen für mich keinen sinn:

  # cmp r0, #0    @ ?????
  # beq loop1

hab ich deswegen auch auskommentiert.
Weiß nicht wieso ich r0 nochmal auf 0 überprüfen soll nachdem ich putc 
aufgerufen hab.

Und ich weiß auch ohnehin nicht wie genau das funktionieren soll mit dem 
auf 0 überprüfen. laut aufgabenstellung:

void puts(char *) Ausgabe eines nullterminierten Strings und Ersetzung 
von Newline durch Carriage Return (0x0D) und Linefeed (0x0A).

Ok der string ist also nullterminierend, aber mit cmp r0, #0 überprüf 
ich doch nur ob da eine 0 drin steht aber ich überprüf doch nicht ob ein 
'\0' drin steht (falls da ein unterschied besteht und das sollte es ja 
sonst dürfte im string keine 0 vorkommen)? Und rein laut 
aufgabenstellung muss ich ja noch wenn in dem string am ende ein '\n' 
steht das durch 0x0D und 0x0A ersetzen, aber ich weiß nicht welcher wert 
in r0 stehen soll damit ich weiß das da '\n' drin steht?

: Bearbeitet durch User
von Nop (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Peter W. schrieb:

> Weiß nicht wieso ich r0 nochmal auf 0 überprüfen soll nachdem ich putc
> aufgerufen hab.

Das wird wohl der Rückgabewert der Funktion sein - 0 steht üblicherweise 
für OK. Die Ausgabe soll also abgebrochen werden, wenn putc() einen 
Fehler meldet.

> Ok der string ist also nullterminierend, aber mit cmp r0, #0 überprüf
> ich doch nur ob da eine 0 drin steht aber ich überprüf doch nicht ob ein
> '\0' drin steht

Das ist dasselbe.

> (falls da ein unterschied besteht und das sollte es ja
> sonst dürfte im string keine 0 vorkommen)?

Richtig, C-Strings dürfen keine 0 enthalten.

> aber ich weiß nicht welcher wert
> in r0 stehen soll damit ich weiß das da '\n' drin steht?

In C ist '\n' eine sog. Escape-Sequenz, und die hat einen ASCII-Wert:

https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences

von Nop (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Nop schrieb:
> Richtig, C-Strings dürfen keine 0 enthalten.

Ach ja, das Zeichen '0' hat den ASCII-Wert dezimal 48, siehe hier:

https://www.torsten-horn.de/techdocs/ascii.htm

Also '\0' und dezimal/hex 0 ist dasselbe, aber '0' nicht. Ein C-String 
mit dem Inhalt "A20" besteht also aus den dezimalen Bytes 65, 50, 48, 0. 
Das Letzte ist die terminierende 0.

von Michael E. (cuby)


Bewertung
0 lesenswert
nicht lesenswert
Ein Problem in deinem Code ist noch, dass du Register r4 verwendest, 
ohne es zu sichern (dein stmfd sichert nur das link register auf dem 
Stack).

Laut Procedure Call Standard for the ARM Architecture 
(http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf) 
ist r4 ein "callee saved"-Register, also von der aufgerufenen Funktion 
(dein puts) zu sichern.

Abhilfe:

* Entweder ein anderes Register nehmen, z.B. r1, r2 oder r3, die sind 
Parameter bzw. scratch register
* oder r4 bei stmfd mitsichern und bei ldmfd wiederherstellen

-- Michael

von S. R. (svenska)


Bewertung
0 lesenswert
nicht lesenswert
Das Problem stinkt nach Uni, und da spielt die ABI keine Rolle.
Der Assembler-Code muss nicht mit C-Code zusammenarbeiten.

Aufrufkonventionen u.ä. habe ich in der Vorlesung angesprochen, aber 
sonst außer Acht gelassen. Relevant wird sowas erst in einer höheren 
Vorlesung.

von Nop (Gast)


Bewertung
1 lesenswert
nicht lesenswert
S. R. schrieb:
> Das Problem stinkt nach Uni, und da spielt die ABI keine Rolle.

Wenn r0 als Rückgabewert einer Funktion dient, wird zumindest dieser 
ABI-Teil offensichtlich ja schon verwendet.

von Carl D. (jcw2)


Bewertung
0 lesenswert
nicht lesenswert
Nop schrieb:
> S. R. schrieb:
>> Das Problem stinkt nach Uni, und da spielt die ABI keine Rolle.
>
> Wenn r0 als Rückgabewert einer Funktion dient, wird zumindest dieser
> ABI-Teil offensichtlich ja schon verwendet.

R0 ist auch der erste Parameter und wenn man als Assembler-Programmierer 
auf Cortex-M mit Interrupts in Berührung kommt, müssen diese eh von 
C-Style-Funktionen behandelt werden. Da kann man ja dann gleich bei 
bleiben.

Antwort schreiben

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

Wichtige Regeln - erst lesen, dann posten!

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

Formatierung (mehr Informationen...)

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




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

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