Forum: Mikrocontroller und Digitale Elektronik rcall <-> call


von Stevko (Gast)


Lesenswert?

Guten Tag,

mein Programm für die Fernrohrsteuerung ist jetzt schon >2k und in ASM
geschrieben. Obwohl das AVR-Studio keine Fehlermeldung ausgibt, springt
der Programmcounter beim Aufrufen von bestimmten Funktionen immer auf
Reset. Durch umschichten der Include-Dateien konnte ich zwar das
Problem beheben, aber das war wohl keine Lösung. So habe ich mir die
Funktion RCALL genau angesehen und siehe da die Reichweite ist +/-2k.
Also gut nehme ich CALL. Und da liegt meine Frage:
Kann ich ohne Probleme das RCALL durch CALL ersetzen oder muß ich noch
etwas beachten.
Bis jetzt weiß ich aus der Hilfe das CALL nur nach vorwärts hüpfen kann
(0 &#8804; k < 64K ). Wenn das so ist, wie löse ich dann Sprünge zurück?
Ich meine nicht "ret" sondern den Aufruf einer Routine XXXXXX (im
liegt Speicher z.B. bei 3k). Innerhalb der Routine XXXXX wird die
Routine YYYYY aufgerufen. Diese liegt im Speicher ganz am Anfang. ->
Größer 2k zurück.
Geht das überhaupt mit Call?

Gruß
  Stevko

von Rufus T. Firefly (Gast)


Lesenswert?

Wird denn nicht bei CALL eine absolute Adresse angegeben?

von Stevko (Gast)


Lesenswert?

Rufus, das habe ich auch gedacht aber er springt mit Call in die
Routine.
z.B. Call Temp_Messung , funktioniert aber das ist vorwärts. Ich möchte
nicht alle Rcall's tauschen ohne es genau zu wissen.

Gruß
  Stevko

von Bri (Gast)


Lesenswert?

Da der Speicher bei 0 beginnt und das Ziel absolut ist, gibt es beim
call keine Unterscheidung zwischen vorwärts und rückwärts. Wie Rufus
Frage impliziert, spring er einfach an jede beliebige Stelle im RAM,
egal ob die vor oder nach deinem call Aufruf liegt.

von Thomas Burkhardt (Gast)


Lesenswert?

Hi,

CALL verlangt als Operand die absolute Zieladresse. Das bedeutet, dass
0 <= k <= 64K am Anfang des Speichers loszählt und nicht an deiner
aktuellen Position. Somit geht es damit vor und zurück.

von mmerten (Gast)


Lesenswert?

RCALL deckt beim AVR den Adressraum +- 2k Worte ab. Bei Controllern mit
<= 8k Flash ist der gesamte Adressraum mit RCALL erreichbar. Daher ist
die Int-Tabelle auch nur single word orientiert. Bei >8K Flash muß für
RCALL die Zieladresse innerhalb von +-2K Worten liegen, sonst ist der
Befehl CALL zu verwenden.

von Stevko (Gast)


Lesenswert?

Achso habe ich vergessen ATMega 32 ist der Proz.
Da das Call bei mir vorwärts funktioniert und der Aufruf nach
ca.20Bytes erfolgt(nicht bei Null), nehme ich an das der Kompiler
automatisch die absolute Adresse in den Code einfügt.
Sehe ich das richtig so?

Gruß
  Stevko

von Stefan Widmann (Gast)


Lesenswert?

Hallo alle zusammen!

Genau dieses Problem hat mich auch schon mal mächtig Nerven gekostet:

Absolut nicht zu erklärende Resets beim Aufruf bestimmter
Unterfunktionen bei einem Assemblerprogramm. Auch hier wurde das
AVR-Studio benutzt.

Eine nähere Betrachtung mit dem Simulator brachte zu Tage, dass der
liebe Assembler beim "rcall" nicht prüft, ob das Ziel ausserhalb der
Reichweite liegt. Die im Befehl codierte Adresse war schlichtweg falsch
(der höherwertige Teil wurde einfach abgeschnitten), ohne das jemals
eine entsprechende Fehlermeldung ausgegeben wurde.

Ich weiß leider die genaue Versionsnummer des Assemblers nicht mehr,
eventuell mal eine neuere Version des AVR-Studios probieren.

@Stevko: Schau Dir einfach mal im simulator an, wohin die einzelnen
Funktionsaufrufe springen. Da könnte die Überraschung warten.

Bei uns wurden jedenfalls aus Sicherheitsgründen alle "rcall"-Befehle
gegen "call" ausgetauscht.

MfG

Stefan Widmann

von Peter Dannegger (Gast)


Lesenswert?

Alle AVRs bis 8kB (Mega8, Mega8515 usw.) können mit rjmp / rcall
vollständig adressiert werden.

Erst ab Mega16 muß man call / jmp nehmen.


Peter

von plitzi (Gast)


Lesenswert?

Der AVR-Assembler prüft schon, ob ein rcall reicht, man muss ihn aber
auch lassen. Bei den Assembler-Options gibt es schon seit langem ein
Kästchen mit der Bezeichnung "wrap relative jumps". Wenn dort ein
Hacken drinn ist, springt der assembler bei langen Sprüngen ausserhalb
seiner 2kWorte Reichweite einfach -Sprungweite zurück. Bei AVRs bis zu
8kB Flash funktioniert das auch problemlos. Nur für die größeren MUSS
man den Hacken rausnehmen, will man nicht auf die Nase fallen.

Jörg

von Stevko (Gast)


Lesenswert?

Ok, Danke an alle.
Und wenn es der Peter sogar bestätigt, werde ich heute Abend alle
RCALL's gegen CALL austauschen und kann hoffentlich ruhig schlafen.

Gruß
  Stevko

von Stevko (Gast)


Lesenswert?

@plitzi

Na das ist doch ein guter Tip. Werde es auch auprobieren. Denn bei mir
war offensichtlich der Hacken drin, da ich keine Fehlermeldung bekam.

Gruß
  Stevko

von Till X. (till_n)


Lesenswert?

Wieso ist bei rcall und Sprungadressen von +-2k bei 4k (Word) 
Programmspeicher IMMER der gesamte Programmspeicher adressierbar?
Wenn mein rcall bei Adresse 4000 steht und ich auf Adresse 1000 springen 
will, dann sind dies mehr als 2048 Adressen und es ist trotzdem nicht 
mehr als 4096 Programmspeicheradressen verbraucht worden.

von avr (Gast)


Lesenswert?

Der Überlauf machts möglich.

von Jobst M. (jobstens-de)


Lesenswert?

Till Xxx schrieb:
> Wenn mein rcall bei Adresse 4000 steht und ich auf Adresse 1000 springen
> will, dann sind dies mehr als 2048 Adressen und es ist trotzdem nicht
> mehr als 4096 Programmspeicheradressen verbraucht worden.

4000 + 1096 = 1000

    4000      1111 1010 0000
 +  1096      0100 0100 1000

 =  1000  (1) 0011 1110 1000


Gruß

Jobst

von c-hater (Gast)


Lesenswert?

Till Xxx schrieb:
> Wieso ist bei rcall und Sprungadressen von +-2k bei 4k (Word)
> Programmspeicher IMMER der gesamte Programmspeicher adressierbar?

Weil die Mathematik des Zweierkomplements zusammen mit dem Wraparound am 
Programmspeicherende das halt hergibt.

> Wenn mein rcall bei Adresse 4000 steht und ich auf Adresse 1000 springen
> will, dann sind dies mehr als 2048 Adressen

4000d= FA0
1000d= 3E8

Die nötige Sprungdistanz:
 3E8
-FA0
----
F448 = -3000d

modulo Prgrammspeichergröße
 F448
&07FF
-----
  448 = +1096d

gesprungen wird als 1096 Adressen nach vorn statt 3000 nach hinten.

Probe:

 FA0
+448
----
13E8

modulo Programmspeichergröße

 13E8
&07FF
-----
  3E8 = 1000d

Voilá, wir sind da, wo wir hinwollten.

von oldmax (Gast)


Lesenswert?

Hi
Ich habe ein wenig mitgelesen und wenn ich eine bereits gegebene Antwort 
gebe, hab ich sie einfach überlesen. Der Befehl "RCALL" ist ein 
relativer Befehl und sollte vom Compiler auch als solcher berechnet 
werden. Verschiebt sich der Speicher aus irgendeinem Grund, so ist die 
Distanz immer noch vorhanden. Bei einem Absoluten Sprung ist dies 
natürlich nicht der Fall.
Also, ein Programm ruft an Adresse 1000 einen RJmp zu 1200. Demnach 
setzt das Programm an der Speicherstelle aktuelle Adresse+200, also der 
Distanz, fort. Aus irgendwelchen Gründen wird nun das gesamte Programm 
um 1000 Speicherzellen verschoben, ohne neu übersetzt zu werden. Dann 
steht der Aufruf an der Adresse 2000. Der relative Sprung erfolgt nun 
zur Adresse 2200. Wäre es ein einfacher JMP gewesen, würde immer noch 
die Adresse 1200 angesprungen. In der Regel ist das auf einem AVR mit 
Flash-Speicher nicht so relevant, aber bei Controllern mit Programm in 
einem RAM gibt es schon dahingehend Unterschiede. So werden 
Programmblöcke vom Programmierer gar nicht erkennbar mal nach x, mal 
nach y geladen. Dein absoluter Sprung im Programm ist dann das AUS.
Ich glaube, dein Programmfehler liegt woanders, denn eine 
Bereichsüberschreitung meldet der Compiler. Grad wenn man in ASM 
programmiert, übersieht man schon ganz gern mal ein Register, welches in 
einer ISR verändert wird und auf den Stack gehört. So zum Beispiel ein 
Unterprogramm, aufgerufen aus einer ISR. Die Register innerhalb der 
Subroutine müssen auch gesichert werden!
Gruß oldmax

von Jobst M. (jobstens-de)


Lesenswert?

oldmax schrieb:
> aber bei Controllern mit Programm in
> einem RAM gibt es schon dahingehend Unterschiede. So werden
> Programmblöcke vom Programmierer gar nicht erkennbar mal nach x, mal
> nach y geladen. Dein absoluter Sprung im Programm ist dann das AUS.

Deshalb gibt es bei solchen Systemen ja auch Mechanismen, die für 
absolute Sprünge die Adresse korrigieren, bevor das Programm ausgeführt 
wird.
Dafür gibt es Tabellen, in denen steht, an welchen Positionen die 
Startadresse hinzuaddiert werden muss.


Gruß

Jobst

von Rolf Magnus (Gast)


Lesenswert?

oldmax schrieb:
> So werden
> Programmblöcke vom Programmierer gar nicht erkennbar mal nach x, mal
> nach y geladen.

Warum sollte das so sein? Zufallsgenerator im Startup-Code? Wo das z.B. 
vorkommen kann, sind Programme, die dynamisch gelinkt sind.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jobst M. schrieb:
> oldmax schrieb:
>> aber bei Controllern mit Programm in
>> einem RAM gibt es schon dahingehend Unterschiede. So werden
>> Programmblöcke vom Programmierer gar nicht erkennbar mal nach x, mal
>> nach y geladen. Dein absoluter Sprung im Programm ist dann das AUS.
>
> Deshalb gibt es bei solchen Systemen ja auch Mechanismen, die für
> absolute Sprünge die Adresse korrigieren, bevor das Programm ausgeführt
> wird.

Das geschieht aber nicht dadurch, daß absolute Sprünge vom 
(dynamischen) Linker korrigiert werden.  Stattdessen wird bereits beim 
Compilieren des Codes und Erstellen der .dll / .so dafür Sorge getragen, 
daß entsprechender Code erzeugt wird. Beim GCC z.B. mittels -fpic oder 
-fpie.  Beides wird z.B. vom avr-gcc nicht unterstützt.

von Jobst M. (jobstens-de)


Lesenswert?

Johann L. schrieb:
> Das geschieht aber nicht dadurch, daß absolute Sprünge vom
> (dynamischen) Linker korrigiert werden.

Doch, gibt es auch.


Gruß

Jobst

von oldmax (Gast)


Lesenswert?

Hi
Wenn man euch so zuhört, dann fragt man sich, wofür die Erbauer der 
Befehlscodes den RCALL und RJMP-Befehl erfunden haben. Weil relativ 
adressieren schneller ist? Na ja, RCALL = 3Takte, CALL = 4Takte. Bei JMP 
und RJMP ist ebenfalls 1 Takt weniger beim relativen Aufruf, aber ist 
das wirklich der Grund?
Na ja, mir ist es egal. Relativ heißt für mich immer noch, das mein Code 
ab jeder beliebigen Stelle im Speicher laufen kann, solange kein 
direkter Sprung innerhalb des Blocks programmiert ist. Ist zum Beispiel 
auch gegeben, wenn eine bereits compilierte Subroutine in das Programm 
eingegliedert wird.
Ok, ich bin kein Profi, also werd ich mich jetzt dem WE widmen.
Gruß oldmax

von (prx) A. K. (prx)


Lesenswert?

Verschieblichkeit des fertig erzeugten Binärcodes ist bei der Konzeption 
solcher Mikrocontroller völlig irrelevant. Das betrifft nur Systeme, die 
Programme dynamisch laden, nicht solche, in denen das Programm aus dem 
Flash-ROM ausgeführt wird.

RCALL ist aber kürzer als CALL, spart also neben einem Takt auch Platz. 
Über kurze Distanzen kann man RCALL statt CALL verwenden. Darum geht es.

Manche Mikrocontroller verwende(te)n statt PC-relativer kurzer Sprünge 
solche innerhalb der aktuellen Codeseite. Das ist zwar technisch etwas 
einfacher, sorgt aber für geharnischte Flüche bei Programmierern und 
Compiler-Autoren, also ist man davon abgekommen.

: Bearbeitet durch User
von Rolf Magnus (Gast)


Lesenswert?

oldmax schrieb:
> i
> Wenn man euch so zuhört, dann fragt man sich, wofür die Erbauer der
> Befehlscodes den RCALL und RJMP-Befehl erfunden haben.

Weil mehr nicht in eine Standard-16-Bit-Instruktion reingepaßt hat. JMP 
ist dann einer der wenigen besonderen Ausnahme-Befehle, die 32 Bit breit 
sind. Den gibt's dann auch nur auf Prozessoren, die ihn wirklich 
brauchen.

> Na ja, mir ist es egal. Relativ heißt für mich immer noch, das mein Code
> ab jeder beliebigen Stelle im Speicher laufen kann, solange kein
> direkter Sprung innerhalb des Blocks programmiert ist.

Beim RCALL heißt das aber auch, daß alle Funktionen, die dein Code 
aufruft, sich gemeinsam mit diesem auch immer mitverschieben müssen.

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.