Forum: Compiler & IDEs AVR-ISR Assembler ohne Flags zu benutzen


von N. G. (newgeneration) Benutzerseite


Lesenswert?

Hallo Forum,

im Nachbar-Thread (siehe 
Beitrag "Re: Unnütze Registersicherungen in ISR" ) wurde folgendes 
geschrieben:
1
Carl D. schrieb:
2
> Richtige Interrupts, die auch was sinnvolles tun, brauchen mehr als 0
3
> Register und verbiegen mit Sicherheit auch Flags.
4
5
Bei Avrs ist es durchaus möglich Interrupts zu schreiben, die die Flags 
6
nicht ändern. Ein FIFO kann beispielsweise so realisiert werden. Dabei 
7
spielt besonders die "cpse"-Instruktion eine Rolle, mit der Vergleiche 
8
durchgeführt werden können, ohne die Flags zu ändern (so schlau ist der 
9
avrgcc allerdings bei Weitem nicht, um solche Interrupts zu generieren).

Meine Frage ist nun: wie müsste eine konkrete Implementierung aussehen?
Es hängt jetzt kein direkter Nutzen dran, es ist eher eine akademische 
Frage ;-)

Meine Rahmenbedingungen wären (meiner jetzigen Implementierung folgend):
1
- ein 2^n Ringpuffer
2
  -> ein uint8_t Lese-Index
3
  -> ein uint8_t Schreib-Index 
4
  -> ein uint8_t[2^n]-Array für die Daten
5
- die ISR, die den FIFO-Teil enthält (z.B.: ein UART-RX-Interrupt)
6
- von C aus auf die Variablen zugreifen können (am besten sind die Variablen direkt in deklariert)
7
- andere Funktionen in C oder Assembler (dann aber mit avr-gcc-ABI)
8
- ISR in Inline-ASM oder separatem Assembler-File

Beispiel für die Implementierung in C:
1
/* schnell runtergeschrieben; Funktion nicht getestet */
2
#define RX_BUFFER_SIZE 32
3
4
#if RX_BUFFER_SIZE & (RX_BUFFER_SIZE - 1)
5
#error "RX Buffer size has to be a power of two"
6
#endif
7
static volatile uint8_t rx_write_index;
8
static volatile uint8_t rx_read_index;
9
static volatile uint8_t rx_buffer[RX_BUFFER_SIZE];
10
11
uint8_t uart0_hasData(void) {
12
  return rx_read_index ^ rx_write_index;
13
}
14
15
uint8_t uart0_getc(void) {
16
  uint8_t data;
17
18
  while (!uart0_hasData())
19
    ;
20
  data = rx_buffer[rx_read_index];
21
  rx_read_index = (rx_read_index + 1) & (RX_BUFFER_SIZE - 1);
22
  return data;
23
}
24
25
ISR(USART0_RX_vect) {
26
  uint8_t i = rx_write_index;
27
  i = (i + 1) & (RX_BUFFER_SIZE - 1);
28
  /* kein overflow-check fuer maximale Geschwindigkeit */
29
  rx_buffer[rx_write_index] = UDR0;
30
  rx_write_index = i;
31
}
Die Herausforderung wäre nun, das ganze in der ISR in ASM zu schreiben, 
ohne Flags zu verändern.

Ich bin auf eure Vorschläge gespannt!

N.G.

von Karl M. (Gast)


Lesenswert?

Hi N. G.,

ich verstehe nicht, warum man das in der Realität machen sollte.

Ich schreibe viel AVR Assembler Code in meinen Libs, wenn ich das SREG 
in einer Interrupt-Service-Routine sichern und wieder herstellen kann, 
dann mache ich das.
Nur künstlich würde ich mich selbst einschränken wollen.
Es mag Sonderfälle geben, da kann es sinnvoll sein seinen etwas anders 
aufzuschreiben.

Hochsprache Anweisungen kann man mit etwas Überlegen, fast 1:1 in 
Assembler mit einer Macro-Implementierung übersetzen.

von Karl M. (Gast)


Lesenswert?

Alleine Anweisung
1
rx_buffer[rx_write_index] = UDR0;
beinhaltet schon eine 16Bit Addition.
1
lds  ZL,dVar_rx_write_index ; 8bit
2
ldi  ZH,0                   ; 16bit offset
3
subi ZL,lo8(dVar_rx_buffer) ; rx_buffer addr
4
sbci ZH,hi8(dVar_rx_buffer) ; <-- with carry
5
xIn  R16,UDR0
6
st   Z,R16

von Peter D. (peda)


Lesenswert?

Karl M. schrieb:
> ich verstehe nicht, warum man das in der Realität machen sollte.

Sehe ich auch so.
Selbst mit doppelter Baudrate hast Du mindestens 80 Zyklen je Interrupt. 
Das reicht dicke, um das SREG zu sichern.
Es wäre eine rein akademische Spielerei, sich da unnötig einzuschränken.

Beitrag #5041359 wurde vom Autor gelöscht.
von Wilhelm M. (wimalopaan)


Lesenswert?

N. G. schrieb:
> Beispiel für die Implementierung in C:
>
1
> /* schnell runtergeschrieben; Funktion nicht getestet */
2
> #define RX_BUFFER_SIZE 32
3
> 
4
> #if RX_BUFFER_SIZE & (RX_BUFFER_SIZE - 1)
5
> #error "RX Buffer size has to be a power of two"
6
> #endif
7
> static volatile uint8_t rx_write_index;
8
> static volatile uint8_t rx_read_index;
9
> static volatile uint8_t rx_buffer[RX_BUFFER_SIZE];
10
> 
11
> uint8_t uart0_hasData(void) {
12
>   return rx_read_index ^ rx_write_index;
13
> }

Du darfst ruhig hier (rx_read_index == rx_write_index) verwenden, der 
Compiler wird sicher dasselbe / etwas mindest gleich performantes daraus 
machen.
1
> 
2
> uint8_t uart0_getc(void) {
3
>   uint8_t data;
4
> 
5
>   while (!uart0_hasData())
6
>     ;
7
>   data = rx_buffer[rx_read_index];
8
>   rx_read_index = (rx_read_index + 1) & (RX_BUFFER_SIZE - 1);
9
>

Auch hier darfst Du ruhig
1
rx_read_index = (rx_read_index + 1) % RX_BUFFER_SIZE;
schreiben. Der Compiler wird sicher dasselbe / etwas mindest gleich 
performantes daraus machen. Aber Vorteil: sollte RX_BUFFER_SIZE mal 
keine 2er Potenz sein (implizite Annahme hier), stimmt der Code 
trotzdem.

Du schreibst oben: Implementierung in C.

In C++ könnte man mit static_asserts sicherstellen, dass man es nicht 
compilieren kann, wenn das keine 2'er Potenz ist. Oder man schafft sich 
einen Datentyp, der nur 2er Potenzen als Werte annehmen kann, oder ...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
>> uint8_t uart0_hasData(void) {
>>   return rx_read_index ^ rx_write_index;
>> }
>
> Du darfst ruhig hier (rx_read_index == rx_write_index) verwenden,

Eher (rx_read_index != rx_write_index)

von Karl M. (Gast)


Lesenswert?

Hallo !

Peter Dannegger hat in seiner Uart Fifo Implementierung schon das Beste 
in C verfasst, welches eine sehr gute Optimierung zulässt.

Beitrag "AVR-GCC: UART mit FIFO"

Also Software Uart mit Fifo:
Beitrag "Software UART mit FIFO"

Wilhelm M. schrieb:
> In C++ könnte man mit static_asserts sicherstellen, dass man es nicht
> compilieren kann, wenn das keine 2'er Potenz ist. Oder man schafft sich
> einen Datentyp, der nur 2er Potenzen als Werte annehmen kann, oder ...

Dies ist ein Test, ober die Puffergröße der Regel 2^n genügt:
1
#define buffersize (16) // 2^4 Beispiel
2
if ( (buffersize & (buffersize - 1)) == 0 ) { // (16 and 15) == 0
3
  // 2^n ok
4
}
5
else {
6
  // 2^n fail
7
}

von N. G. (newgeneration) Benutzerseite


Lesenswert?

Hallo an alle,

ihr hab mich wohl missverstanden:
Ich brauche keine Implementierung in C/C++ oder sonst was
Ich habe kein Zeitproblem oder Ähnliches

Es ging lediglich um die Überprüfung der Aussage aus dem verlinkten 
Beitrag.

Wie kann man in Assembler eine Funktion schreiben, die einen Ringpuffer 
implementiert, ohne das SREG zu verändern?

Ja, diese Frage ist, wie im Eingangsposting auch schon geschrieben, rein 
akademisch!

Aber mich würde halt interessieren, ob es überhaupt möglich wäre.

N.G.

von Karl M. (Gast)


Lesenswert?

Hallo N. G.,

danke für die Klarstellung, ich hatte gestern Nacht dies versucht, 
scheitere aber an der Addition, die als 9Bit immer das Carry beinhaltet.

Ein entrollen einer 8Bit Addition auf 256 Abfragen werden ich nicht 
machen.

von (prx) A. K. (prx)


Lesenswert?

Karl M. schrieb:
> Ein entrollen einer 8Bit Addition auf 256 Abfragen werden ich nicht
> machen.

Braucht man eine volle Addition?

Inkrementierung über LD r,rr+ / ST rr+,r, oder Tabelle.
Begrenzung über CPSE oder wrap-around.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Karl M. schrieb:

> Dies ist ein Test, ober die Puffergröße der Regel 2^n genügt:
>
1
> #define buffersize (16) // 2^4 Beispiel
2
> if ( (buffersize & (buffersize - 1)) == 0 ) { // (16 and 15) == 0
3
>   // 2^n ok
4
> }
5
> else {
6
>   // 2^n fail
7
> }
8
>


Ja super: ein Laufzeittest! Das ist nicht besonder elegant!!! Und was 
mache ich, wenn der fehlschlägt? Die rote LED an?

Besser ist, dass das Programm nicht compiliert!

von Wilhelm M. (wimalopaan)


Lesenswert?

Frank M. schrieb:
> Wilhelm M. schrieb:
>>> uint8_t uart0_hasData(void) {
>>>   return rx_read_index ^ rx_write_index;
>>> }
>>
>> Du darfst ruhig hier (rx_read_index == rx_write_index) verwenden,
>
> Eher (rx_read_index != rx_write_index)

Ups, ja klar. Danke!

Man schreibt ja auch auch nicht:
1
x = x ^ x;

sondern einfach
1
x = 0;

und es ist Aufgabe des Compilers, optimalen Code zur die Zielplattform 
zu erzeugen.

von (prx) A. K. (prx)


Lesenswert?

#define buffersize (16)
#if (buffersize & (buffersize - 1)) != 0
  #error
#endif

von N. G. (newgeneration) Benutzerseite


Lesenswert?

N. G. schrieb:
> #define RX_BUFFER_SIZE 32
>
> #if RX_BUFFER_SIZE & (RX_BUFFER_SIZE - 1)
> #error "RX Buffer size has to be a power of two"
> #endif

War ja schon da, und sollte eigentlich nicht Teil der Diskussion sein

N.G.

von Karl M. (Gast)


Lesenswert?

Wilhelm M.,

wir schreiben doch hier nur exemplarisch Code.
Ich hätte eine Pseudosprache wählen sollen - Fortran ?

Weiter unten steht es dann auch nochmals anders formuliert.

Wilhelm M. schrieb:
> Karl M. schrieb:
>
>> Dies ist ein Test, ober die Puffergröße der Regel 2^n genügt:
>>> #define buffersize (16) // 2^4 Beispiel
>> if ( (buffersize & (buffersize - 1)) == 0 ) { // (16 and 15) == 0
>>   // 2^n ok
>> }
>> else {
>>   // 2^n fail
>> }
>>
>
> Ja super: ein Laufzeittest! Das ist nicht besonder elegant!!! Und was
> mache ich, wenn der fehlschlägt? Die rote LED an?
>
> Besser ist, dass das Programm nicht compiliert!

von Wilhelm M. (wimalopaan)


Lesenswert?

N. G. schrieb:
> N. G. schrieb:
>> #define RX_BUFFER_SIZE 32
>>
>> #if RX_BUFFER_SIZE & (RX_BUFFER_SIZE - 1)
>> #error "RX Buffer size has to be a power of two"
>> #endif
>
> War ja schon da, und sollte eigentlich nicht Teil der Diskussion sein

Ah ja, stimmt! Hatte ich übersehen ... danke für den Hinweis.

Allerdings könnte man nach(!) diesem Macro das auch wieder umdefinieren, 
z.B. durch eine andere #include-Anweisung ... das ist das Problem von 
solchen, un-scoped Textersetzungen ...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Allerdings könnte man nach(!) diesem Macro das auch wieder umdefinieren,

Ja, theroretisch kann man viel böse Sachen machen. Aber:

Ich finde, Du übertreibst Deinen missionarischen Eifer etwas. Lass doch 
den Leuten, die sich bei C statt C++ wohler fühlen, ihre eigene 
Entscheidung für das Tool, das sie möchten.

Du kannst ja gern Beispiele hier und da für die Überlegenheit von C++ 
gegenüber C anbringen. Aber muss das so weit gehen, dass ich mich immer 
an Kreuzzüge erinnert fühle?

Man kann sich sowohl mit C als auch mit C++ in den Fuß schießen. Das ist 
wohl unbestritten.

von Wilhelm M. (wimalopaan)


Lesenswert?

Frank M. schrieb:

> Du kannst ja gern Beispiele hier und da für die Überlegenheit von C++
> gegenüber C anbringen. Aber muss das so weit gehen, dass ich mich immer
> an Kreuzzüge erinnert fühle?

Dann erklär mir mal bitte, was diese Anmerkung von mir

> In C++ könnte man mit static_asserts sicherstellen, dass man es nicht
> compilieren kann, wenn das keine 2'er Potenz ist. Oder man schafft sich
> einen Datentyp, der nur 2er Potenzen als Werte annehmen kann, oder ...

mit Kreuzzügen zu tun hat.

von Oliver S. (oliverso)


Lesenswert?

N. G. schrieb:
> Meine Rahmenbedingungen wären (meiner jetzigen Implementierung
> folgend):- ein 2^n Ringpuffer
>   -> ein uint8_t Lese-Index
>   -> ein uint8_t Schreib-Index
>   -> ein uint8_t[2^n]-Array für die Daten
> - die ISR, die den FIFO-Teil enthält (z.B.: ein UART-RX-Interrupt)
> - von C aus auf die Variablen zugreifen können (am besten sind die
> Variablen direkt in deklariert)
> - andere Funktionen in C oder Assembler (dann aber mit avr-gcc-ABI)
> - ISR in Inline-ASM oder separatem Assembler-File

Meiner unmaßgeblichen Meinng nach geht das überhaupt nur mit einem 
256Byt großen Buffer, und 8-Bit Index-Zeigern, die halt am Ende 
automatisch überlaufen.

Sämtliche Vergleichs- und Logischen Verknüpfungsoperationen sowie alle 
Rechenoperationen verändern das SREG, und sind daher nicht einsetzbar.

Oliver

von (prx) A. K. (prx)


Lesenswert?

Oliver S. schrieb:
> Sämtliche Vergleichs- und Logischen Verknüpfungsoperationen sowie alle
> Rechenoperationen verändern das SREG, und sind daher nicht einsetzbar.

Wie schon erwähnt kann man sowohl Inkrementieren als auch auf Gleichheit 
testen, ohne Flags in Anspruch nehmen zu müssen.

von Horst M. (horst)


Lesenswert?

Ich ignoriere mal Deine ganzen Anforderungen aus dem obersten Posting 
und orientiere mich erstmal an

N. G. schrieb:
> Die Herausforderung wäre nun, das ganze in der ISR in ASM zu schreiben,
> ohne Flags zu verändern.

Wenn's richtig schnell sein soll, dann vielleicht so:
1
  .include "m1284pdef.inc"
2
3
  rjmp init
4
5
  .org URXC0addr
6
  rjmp rxint
7
8
init:
9
;setup of USART0 not shown here
10
11
  ldi XL,LOW(rxbuf)
12
  ldi XH,HIGH(rxbuf)
13
  movw YH:YL,XH:XL
14
  sei
15
wait:
16
  sleep
17
chk_buf:
18
  cp XL,YL
19
  breq wait
20
  ld r16,Y+
21
  ldi YH,HIGH(rxbuf)
22
;process received character
23
  rjmp chk_buf
24
25
rxint:
26
  lds r15,(UDR0)
27
  st X+,r15
28
  ldi XH,HIGH(rxbuf)
29
  reti
30
31
  .dseg
32
  .org (SRAM_START+$ff)&$100
33
rxbuf: .byte 256

R15 und X sind exklusiv für die ISR reserviert, es werden keine Flags 
verändert.
Der Empfangspuffer muß an einer 256-Byte-Grenze liegen, ein Überlauf 
wird nicht behandelt.
Je mehr in der ISR noch rumgerödelt werden soll (Überlaufprüfung, 
Empfangspuffer kleiner/größer als 256 Byte etc.), desto weniger 
wahrscheinlich läßt sich eine Lösung finden, die ohne Einfluß auf die 
Flags auskommt.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Dann erklär mir mal bitte, was diese Anmerkung von mir
>
> In C++ könnte man mit static_asserts sicherstellen, dass man es nicht
> compilieren kann, wenn das keine 2'er Potenz ist. Oder man schafft sich
> einen Datentyp, der nur 2er Potenzen als Werte annehmen kann, oder ...
>
> mit Kreuzzügen zu tun hat.

Dann erklär mit bitte, warum Du obiges Zitat aufführst, wenn ich mich 
doch tatsächlich auf dieses

Wilhelm M. schrieb:
> Allerdings könnte man nach(!) diesem Macro das auch wieder umdefinieren,
> z.B. durch eine andere #include-Anweisung ... das ist das Problem von
> solchen, un-scoped Textersetzungen ...

in meinem Beitrag bezogen habe.

Du suggerierst mit beiden Aussagen zusammen:

 - C++ ist gut, denn mit static_asserts kann man sicherstellen,
   dass auch dümmste Programmierer darauf hingewiesen werden, dass
   die 42 doch keine Zweierpotenz ist.

 - C ist böse, denn durch Umdefinition von Macros (dummer Programmierer
   wird zum bösen Programmierer) kann der Programmierer nicht vor
   seinem Irrglauben geschützt werden, die 42 wäre tatsächlich
   eine Zweierpotenz.

Ist ja alles schön und gut. Ich verstehe ja auch Deine Intention. Aber 
wenn man suggeriert bekommt, C++ müsse mich vor meinen eigenen 
Dummheiten schützen, dann ist es nicht sehr angenehm, dass ich als Leser 
Deiner Beiträge pauschal als zu beschützendes Dummchen abgestempelt 
werden, nur weil ich mich mit C wohler als mit C++ fühle.

Es ging mir auch nicht konkret um diesen Beitrag, sondern eher um den 
allgemeinen Eindruck, den ich während der letzten Tage/Wochen bekam. 
Dein geschickt eingefädelter "Programmierwettbewerb", der von vornherein 
nur deshalb veranstaltet wurde, um die Überlegenheit von C++ zu 
demonstrieren, obwohl er unter dem Vorwand eines real existierenden 
Zeitproblems gepostet wurde, ist mir da noch unangenehm in Erinnerung.

Ich mag solche Spielchen einfach nicht. Aber das ist meine persönliche 
Meinung.

P.S.
Es gibt auch effiziente Ringbuffer-Implementationen, die solche 
Optimierungen bzgl. Bufferlänge = Zweierpotenz gar nicht brauchen.

: Bearbeitet durch Moderator
von Wilhelm M. (wimalopaan)


Lesenswert?

Frank M. schrieb:
> Wilhelm M. schrieb:
>> Dann erklär mir mal bitte, was diese Anmerkung von mir
>>
>> In C++ könnte man mit static_asserts sicherstellen, dass man es nicht
>> compilieren kann, wenn das keine 2'er Potenz ist. Oder man schafft sich
>> einen Datentyp, der nur 2er Potenzen als Werte annehmen kann, oder ...
>>
>> mit Kreuzzügen zu tun hat.
>
> Dann erklär mit bitte, warum Du obiges Zitat aufführst, wenn ich mich
> doch tatsächlich auf dieses
>
> Wilhelm M. schrieb:
>> Allerdings könnte man nach(!) diesem Macro das auch wieder umdefinieren,
>> z.B. durch eine andere #include-Anweisung ... das ist das Problem von
>> solchen, un-scoped Textersetzungen ...

Auch hier kann ich keinen Kreuzzug erkennen. Wie hättest Du denn gerne 
so einen Hinweis formuliert? Verzeihung Hochwürden, ich bitte 
untertänigst um Redeerlaubnis?

Deine Wortwahl ist absolut unpassend. Es ist ja schon sehr erschreckend, 
welche Wortwahl hier manche andere an den Tat legen, aber das so etwas 
von einem Moderator kommt, ist wirklich vollkommen unpassend.

> Du suggerierst mit beiden Aussagen zusammen:
>
>  - C++ ist gut, denn mit static_asserts kann man sicherstellen,
>    dass auch dümmste Programmierer darauf hingewiesen werden, dass
>    die 42 doch keine Zweierpotenz ist.

Nein, C++ ist in diesem(!) Fall besser.

>  - C ist böse, denn durch Umdefinition von Macros (dummer Programmierer
>    wird zum bösen Programmierer) kann der Programmierer nicht vor
>    seinem Irrglauben geschützt werden, die 42 wäre tatsächlich
>    eine Zweierpotenz.

Nein, C ist in diesem(!) Fall schlechter.

> Aber
> wenn man suggeriert bekommt, C++ müsse mich vor meinen eigenen
> Dummheiten schützen,

Genau das ist es. Als erfahrener Programmierer wirst Du das wissen.

> dann ist es nicht sehr angenehm, dass ich als Leser
> Deiner Beiträge pauschal als zu beschützendes Dummchen abgestempelt
> werden, nur weil ich mich mit C wohler als mit C++ fühle.

Wenn Du meine Beiträge lesen würdest als das, was sie sind, würdest Du 
bemerken, dass ich Leuten, die ihr C mögen, den Spaß lasse. Allerdings 
darf man in einer aufgeklärten Welt auf Alternativen hinweisen.

Zudem weise ich sehr oft darauf hin, dass m.E. eine gute Strategie auch 
für die C-affinen ist, sich einige Rosinen aus dem C++ Kuchen heraus zu 
picken.

Leider muss ich sehr oft feststellen, dass man als jemand, der 
Alternativen aufzeigt, hier oftmals direkt schimpft wird.

> Es ging mir auch nicht konkret um diesen Beitrag, sondern eher um den
> allgemeinen Eindruck, den ich während der letzten Tage/Wochen bekam.
> Dein geschickt eingefädelter "Programmierwettbewerb", der von vornherein
> nur deshalb veranstaltet wurde, um die Überlegenheit von C++ zu
> demonstrieren, obwohl er unter dem Vorwand eines real existierenden
> Zeitproblems gepostet wurde, ist mir da noch unangenehm in Erinnerung.

Wenn Du das so meinst, dann solltest Du diesen Programmierwettbewerb 
hier auch als solchen bezeichnen!!!

von Klaus (Gast)


Lesenswert?

N. G. schrieb:
> Die Herausforderung wäre nun, das ganze in der ISR in ASM zu schreiben,
> ohne Flags zu verändern.

Eine der unvermeidlichen Nebenwirkungen ist, das der nächste 
Programmierer, der den Code bearbeitet (z.B. du selbst im nächsten 
Jahr), sich auch daran halten muß, sonst gehts schief. Ich würde mir da 
nicht trauen.

MfG Klaus

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Deine Wortwahl ist absolut unpassend. Es ist ja schon sehr erschreckend,
> welche Wortwahl hier manche andere an den Tat legen, aber das so etwas
> von einem Moderator kommt, ist wirklich vollkommen unpassend.

Auch ich bewege mich in diesem Forum vornehmlich als normaler 
Forumsanwender. Den Titel "Moderator" kann ich bei dem Verfassen eines 
Beitrags leider nicht von Fall zu Fall einfach löschen oder erscheinen 
lassen.

> Wenn Du das so meinst, dann solltest Du diesen Programmierwettbewerb
> hier auch als solchen bezeichnen!!!

Um Missverständnissen vorzubeugen: Es ging mir dabei um diesen Thread:

  Beitrag "Assembler (AVR) Freaks bitte: der schnellste Weg, einen ganzzahligen Wert zu skalieren?"

und nicht um diesen hier. Und damit ist für mich nun EOD.

von Wilhelm M. (wimalopaan)


Lesenswert?

Frank M. schrieb:
> Wilhelm M. schrieb:
>> Deine Wortwahl ist absolut unpassend. Es ist ja schon sehr erschreckend,
>> welche Wortwahl hier manche andere an den Tat legen, aber das so etwas
>> von einem Moderator kommt, ist wirklich vollkommen unpassend.
>
> Auch ich bewege mich in diesem Forum vornehmlich als normaler
> Forumsanwender. Den Titel "Moderator" kann ich bei dem Verfassen eines
> Beitrags leider nicht von Fall zu Fall einfach löschen oder erscheinen
> lassen.

Was heißt hier leider!?! Auch von einem Moderator erwarte ich 
Aufrichtigkeit!

>
>> Wenn Du das so meinst, dann solltest Du diesen Programmierwettbewerb
>> hier auch als solchen bezeichnen!!!
>
> Um Missverständnissen vorzubeugen: Es ging mir dabei um diesen Thread:
>
>   Beitrag "Assembler (AVR) Freaks bitte: der schnellste Weg, einen ganzzahligen Wert zu skalieren?"
>
> und nicht um diesen hier.

Das weiß ich schon, und dieser Thread hier, den ich auch sehr 
interessant finde und gar nicht anstößig, ist in seiner Qualität 
dasselbe mit einer anderen Fragestellung: die Bitte, um eine möglichst 
gute Lösung eines Problems ausserhalb des persönlichen 
Erfahrungshorizonts.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ziemlich akademischen Problem das...

Man hat folgende Instruktionen zur Verdügung:

== Load Store ==

LD*, ST*, LPM, IN, OUT, SBI, CBI, PUSH, POP

== Arithmetik ==

LDI, SWAP

== Vergleiche ==

CPSE, SBRC, SBRS

== Sprung ==

[R]JMP, [R]CALL, [E]IJMP, [E]ICALL, RET

* Branches sind witzlos, da die vorheriges Setzen von SREG erfordern.

* BLD ist witzlos da es vorheriges BST erfordert.

* Addition von 1 könnte man per LPM Z+ realisieren falls unterstützt.

Viel Spaß...

von Peter D. (peda)


Lesenswert?

Für solche Spielereien ist der 8051 viel besser geeignet. Der hat nur 
wenige Instruktionen, die das PSW ändern:
ADD, ADDC, DA, SUBB, MUL, DIV, RRC, RLC, CJNE und die Bitoperationen mit 
C als Ziel.

von N. G. (newgeneration) Benutzerseite


Lesenswert?

Hallo @all,


ich habe mich nochmal ein- bis zwei Stunden hingehockt und es probiert, 
aber ich bin auf keinen grünen Zweig gekommen. Ich muss aber zugeben, 
dass ich absolut schlecht in ASM bin.

Aber danke für eure Beiträge!

Mit freundlichen Grüßen,
N.G.

von Oliver S. (oliverso)


Lesenswert?

Das geht schon ohne Veränderung des SREG, allerdings ist das halt 
insofern dann doch völlig sinnlos, als daß es nicht ohne Nutzung und 
damit Sicherung einiger Register geht.

Oliver

von c-hater (Gast)


Lesenswert?

Oliver S. schrieb:

> Das geht schon ohne Veränderung des SREG, allerdings ist das halt
> insofern dann doch völlig sinnlos, als daß es nicht ohne Nutzung und
> damit Sicherung einiger Register geht.

Genau das ist der idiotische Trugschluss, dem C-Programmierer immer 
wieder unterliegen. Nein, die Benutzung von Registern in ISRs impliziert 
natürlich nicht automatisch, dass sie in jeder ISR-Instanz gerettet und 
restauriert werden müssen. Man muß einfach nur (durch Konvention) diese 
Register exklusiv für diesen Job freistellen (und ggf. mit geeigneten 
Defaultwerten belegen, bevor das Interruptmassaker beginnt).

Das hört sich nach performancemindernder Registerverschwendung an, ist 
aber in der Praxis in aller Regel das genaue Gegenteil, nämlich die 
performancefördernste Maßnahme überhaupt, das gilt mit zunehmender 
Interruptrate natürlich in immer größerem Maße...

Nur leider kommen C-Nutzer kaum in die Verlegenheit, die Vorteile so 
eines Konzeptes zu nutzen, weil ihre grenzdebilen Compiler das nur sehr 
eingeschränkt bis garnicht unterstützen, jedenfalls für die 
AVR-Architektur...

In anderen Architekturen ist das absoluter Usus, wenn auch auf einem 
anderen Weg, der es den Compilerfricklern etwas einfacher macht: Es gibt 
dort einfach alle Register in mehrfacher Ausführung und es wird bei 
einem Interrupt zwischen diesen Registersätzen umgeschaltet. Oder eine 
Variante dieses Grundprinzips...

Wichtig scheint irgendwie nur zu sein, den zur masslosen Überschätzung 
der Bedeutung ihrer Programmiersprache neigenden Compilerprogrammierern 
das Gefühl zu geben, sie hätten alle Register der Maschine im 
ausschließlichen Besitz ihrer Runtime, denn darauf scheinen sie 
irgendwie Wert zu legen. Dabei sind die Engines in aller Regel durchaus 
so konstruiert, dass sie problemlos auf ein paar Register verzichten 
könnten (klar: natürlich mit Performanceverlust in speicherlastigen 
Programmteilen), aber irgendwie wollen diese Wichser es nicht, dass der 
User ihrer Werke daraus Vorteile ziehen darf. Selbst wenn die 
Möglichkeit prinzipiell bis in's Frontend hinein besteht, ist sie 
zumindest nur lausig bis garnicht dokumentiert, so dass sie wirklich nur 
für absolute Insider nutzbar wird...

Da kann man dann besser gleich komplett in Assembler programmieren. Da 
hat man die Freiheit, die Register sinnvoll einzusetzen, von 
vornherein...

von avr (Gast)


Lesenswert?

Den Thread hab ich erst jetzt gesehen. Die Aussage kommt noch aus meiner 
AVR-Assemblerzeit, in der ich tatsächlich ähnlichen Code hatte. Ohne 
diesen zu suchen, kann man das Problem folgermaßen lösen:
1
; load fifo pointer
2
lds XH, hi8(fifo_ptr)
3
lds HL, lo8(fifo_ptr)
4
5
; read byte
6
ld temp, X+
7
8
; bound checking
9
ldi temp, lo8(fifo_end)
10
cpse XL, temp
11
rjmp store
12
13
; reset fifo pointer
14
ldi XL, lo8(fifo_start)
15
ldi XH, hi8(fifo_start)
16
17
store:
18
sts hi8(fifo_ptr), XH
19
sts lo8(fifo_ptr), XL
20
21
reti
Das ganze funktioniert bis Puffergrößen von 256 Byte, wobei 256 Byte wie 
oben schon angemerkt einfacher zu realisieren sind. Die drei benutzten 
Register müssen natürlich gesichert werden, aber das muss man sowieso.

Wenn das FIFO im Speichern an bestimmte Adressen gelegt werden kann, 
kann soagr noch etwas optimiert werden. Ob das Sinn macht oder nicht, 
darf jeder selbst für sich entscheiden. Ich hatte damals meinen Spaß 
daran.

von Oliver S. (oliverso)


Lesenswert?

c-hater schrieb:
> Man muß einfach nur (durch Konvention) diese
> Register exklusiv für diesen Job freistellen (und ggf. mit geeigneten
> Defaultwerten belegen, bevor das Interruptmassaker beginnt).

Selbst der größte c-hater sollte allerdings verstehen, das das im Fall 
der x- und y-Register auf dem AVR, um den es hier geht, praktisch nicht 
möglich ist.

Oliver

von Markus F. (mfro)


Lesenswert?

c-hater schrieb:
> Wichtig scheint irgendwie nur zu sein, den zur masslosen Überschätzung
> der Bedeutung ihrer Programmiersprache neigenden Compilerprogrammierern
> das Gefühl zu geben, sie hätten alle Register der Maschine im
> ausschließlichen Besitz ihrer Runtime, denn darauf scheinen sie
> irgendwie Wert zu legen. Dabei sind die Engines in aller Regel durchaus
> so konstruiert, dass sie problemlos auf ein paar Register verzichten
> könnten

warum haben "die Wichser" beim gcc dann -ffixed-<register> erfunden?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

c-hater schrieb:
> ...

ha ha

Unser c-hater ist auch schon wach, sitzt wieder mit puterrotem Kopf, 
geplatzem Kragen und 220 Blutdruck vor'm Rechner und kloppt seine c-hate 
rein.

Ein Tag ohne c-hate ist ein verlorener Tag!  Armer Wicht.

Vielleicht ersma zur nächsten Apotheke um die Blutdruck-Pillen 
aufzustocken...  die sind beim c-hater schneller zu Ende als er denkt.

von (prx) A. K. (prx)


Lesenswert?

c-hater hat insoweit recht, als nicht jeder µC und nicht jede Sprache 
für jeden Zweck taugt. Wenn man also extreme Anforderungen in 
Reaktionszeit auf Ereignisse hat, dann ist nicht jede Plattform 
geeignet.

Vielleicht helfen dann seine µCs mit umschaltbaren Registersätzen 
weiter, aber im Grunde ist das auch nur eine Zwischenlösung, die ein 
Bisschen was bringt. Denn jenseits davon lauert die konfigurierbare 
Hardware, die noch viel viel reaktionsfähiger ist als jeder µC.

Also müsste er in diesem Sinn nicht nur C hassen, und mangels adäquater 
Registerstruktur die AVRs gleich mit, sondern auch interruptfreudigere 
Prozessoren und sowieso sämtliche sequentielle Programmierung in Form 
von Prozessoren. Und alles ausser FPGAs schon vorneweg ablehnen.

Apropos: Kann man mit FPGAs eigentlich auf Bitebene entwickeln? Denn 
VHDL ist doch auch bloss eine fürchterliche und bestimmt verlustreiche 
Hochsprache. ;-)

: Bearbeitet durch User
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.