Forum: Offtopic C versus Assembler->Performance


von Horst S. (Gast)


Angehängte Dateien:

Lesenswert?

Hallihallo,

folgende Sachlage: Ich habe ein Programmchen für einen ATMega168 zuerst 
auf Assemblerbasis erstellt und anschließend auf gcc portiert. Das 
funktioniert auch alles (zumindest nicht schlechter als in Assembler), 
was mich aber zur Zeit etwas die Augenbrauen hochziehen lässt:
Warum benötige ich im Assembler-Projekt "nur" 2910 Bytes, in C aber 
"satte" 3278 Bytes?
Ich bin jetzt nicht unbedingt davon ausgegangen, dass ein (nicht 
optimiertes) Assemblerprogramm in C portiert um 10% größer (und damit 
auch langsamer) werden muss. Ist das so?


Was ich bisher gemacht habe:
- Ich habe mal alle Optimierungen durchprobiert. Die 3278 Bytes sind das 
Beste, was ich mit meinem AVRStudio 4.10 herauskitzeln kann.
- Ich hab mir die eingebundenen Header mal angeschaut. Dabei habe ich 
viele #defines, aber kein Grund für das absonderliche Wachstum gefunden.



Ich häng mal die Projekte als Zip an.
Zur Info:
- Die Projekte kommunizieren über zwei PortPins per PS/2 mit einem 
Maussensor (SPCP168A). Empfangene Werte werden in DataRead.MouseBuffer 
geschrieben. Der Wert von DataWrite.MouseCommand wird über PS/2 an den 
Sensor übergeben.

DataRead und DataWrite werden mit einem PC über UART ausgetauscht. Zum 
Austausch von Datenblöcken habe ich in UARTTelegramm.c für das C-Projekt 
und rs232Telegram.asm für das Assemblerprojekt ein unverfängliches 
Protokoll aufgesetzt. (Der PC liest zuerst die implementierte 
Peripherie-Tabelle, um die Adressen der Datenblöcke zu lesen. 
Anschließend kann er direkt auf Datenblöcke (hier DataRead und 
DataWrite) über die vier implementierten Read-/Write-/-Device/-Mem 
zugreifen.

Prinzipiell funktionieren sowohl der PS/2- als auch das UART-Protokoll 
als Statemachines über Funktionspointer. In Assembler regeln das im 
wesentlichen die Macros "PrepareJump" und "Jump".

Etwas Eigenartig vielleicht für den Außenstehenden das Mapping der 
Register r16..r23 auf d0..d7 im Assembler(ich war mal 
68000er-Fetischist).

Vielleicht fällt Euch ja ein, was ich in C noch optimieren könnte.
(und reißt mir nicht den Kopf ab, das ist mein Erstlingswerk mit gcc).

: Gesperrt durch Moderator
von Falk B. (falk)


Lesenswert?

@ Horst S. (hdc)

>was mich aber zur Zeit etwas die Augenbrauen hochziehen lässt:
>Warum benötige ich im Assembler-Projekt "nur" 2910 Bytes, in C aber
>"satte" 3278 Bytes?

Wen interessieren diese läppischen 10% im Jahr 2015, wo selbst 32 Bit 
CPUs für wenige Euros verkauft werden?

>Ich bin jetzt nicht unbedingt davon ausgegangen, dass ein (nicht
>optimiertes) Assemblerprogramm in C portiert um 10% größer (und damit
>auch langsamer) werden muss. Ist das so?

Nö, es ist erstmal nur 10% größer. Ob es auch 10% langsamer ist, ist 
damit noch lange nicht gesagt. Du kämpfst gegen Windmühlen.

https://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Prinzipien_der_Optimierung

von Peter II (Gast)


Lesenswert?

Horst S. schrieb:
> Vielleicht fällt Euch ja ein, was ich in C noch optimieren könnte.

ich finde du hast zu viele Funktionen.
1
void RxDCommandWriteMemGetFirstTargetByte(uint8_t receivedByte);
2
void RxDCommandWriteMemGetSecondTargetByte(uint8_t receivedByte);
3
void RxDCommandWriteMemGetFirstLengthByte(uint8_t receivedByte);
4
void RxDCommandWriteMemGetSecondLengthByte(uint8_t receivedByte);
kannst man das nicht eine packen und mitgeben welches Byte man haben 
will?
1
void PS2ReceiveBit0();
2
void PS2ReceiveBit1();
3
void PS2ReceiveBit2();
4
void PS2ReceiveBit3();
5
void PS2ReceiveBit4();
6
void PS2ReceiveBit5();
7
void PS2ReceiveBit6();
8
void PS2ReceiveBit7();

auch das sollte sich doch wohl über eine Funktion abbilden lassen.

Auch kommt mir volatile viel zu oft vor. sicher das die ganzen Variablen 
in einer ISR und dem Hauptprogramm verwendet werden?
1
void SetLED1()
2
{
3
  asm ("sbi _SFR_IO_ADDR(PORTB), LED1" "\t\n");
4
  //asm ("sbi PORTB, LED1" "\t\n");
5
}
warum hier noch asm? Das sollte sich mit Makros ohne Funktion machen 
lassen.
1
  for (int i =0; i<=255;i++)
2
    DataRead.MouseBuffer[i] = 0;
konstanten im code sind böse, was ist wenn die größe vom Puffer sich mal 
ändert?
1
memset( &DataRead, 0, sizeof(DataRead) );
würde ich hier vorschlagen.

: Bearbeitet durch Moderator
von Horst S. (Gast)


Lesenswert?

Peter II schrieb:
> auch das sollte sich doch wohl über eine Funktion abbilden lassen.
>
> Auch kommt mir volatile viel zu oft vor. sicher das die ganzen Variablen
> in einer ISR und dem Hauptprogramm verwendet werden?

Ich hab's so 1:1 aus Assembler umgesetzt. Wie gesagt, der 
Funktionpointer wird aus der letzten aufgerufenen Funktion für den 
nächsten Interrupt umgesetzt. Das war in Assembler eine super Sache, da 
ich keinen Schleifenzähler zwischen den Interrupts puffern musste.
Wenn ich's ändere, wird der C-Code zwar kleiner, die Vergleichbarkeit 
zum Assembler ist allerdings dann wech.

Die volatile-Variablen puffern Zustände für folgende ISR-Aufrufe. Wenn 
ein Datenblock über WriteDevice beschrieben wird, bemisst das Protokoll 
z.B. über den Zähler RxDDataLength, wann der PC fertig ist und wann das 
Quittierungstelegramm zu starten ist.



Peter II schrieb:
> konstanten im code sind böse, was ist wenn die größe vom Puffer sich mal
> ändert?
> memset( &DataRead, 0, sizeof(DataRead) );
> würde ich hier vorschlagen.

guter Plan, das!

Peter II schrieb:
> warum hier noch asm? Das sollte sich mit Makros ohne Funktion machen
> lassen.

Das ist allerdings auch noch eine offene Frage für mich: Wie ist die 
Umsetzung des sbi/cbi-Befehls in C?
Ist ein "PORTB |= 0x01" wirklich dann ein "sbi PORTB, 1"?
Oder baut mir der Compiler daraus ein:
in r16, PORTB
ori r16, 0x01
out PORPB, r16
Das wäre mir unangenehm!

von Tom (Gast)


Lesenswert?

Horst S. schrieb:
> Das wäre mir unangenehm!

Weil die LED dann 1µs später angeht?

von Peter II (Gast)


Lesenswert?

Horst S. schrieb:
> Ich hab's so 1:1 aus Assembler umgesetzt. Wie gesagt, der
> Funktionpointer wird aus der letzten aufgerufenen Funktion für den
> nächsten Interrupt umgesetzt. Das war in Assembler eine super Sache, da
> ich keinen Schleifenzähler zwischen den Interrupts puffern musste.
> Wenn ich's ändere, wird der C-Code zwar kleiner, die Vergleichbarkeit
> zum Assembler ist allerdings dann wech.

macht für mich wenig sinn. C schreibt man um sich weniger arbeit zu 
machen. Da überlässt man einige Details dem Compiler. So wie du es 
gemacht hast, verhinderst du zum teil Optimierungen.

> Die volatile-Variablen puffern Zustände für folgende ISR-Aufrufe. Wenn
> ein Datenblock über WriteDevice beschrieben wird, bemisst das Protokoll
> z.B. über den Zähler RxDDataLength, wann der PC fertig ist und wann das
> Quittierungstelegramm zu starten ist.
wenn sie NUR in der ISR genutzt werden, braucht man kein volatile.

> Das ist allerdings auch noch eine offene Frage für mich: Wie ist die
> Umsetzung des sbi/cbi-Befehls in C?
> Ist ein "PORTB |= 0x01" wirklich dann ein "sbi PORTB, 1"?
ja, zur Sicherheit schaut man einfach mal in den ASM code.

von Peter D. (peda)


Lesenswert?

Das "PS2.c" ist aber wirklich von hinten durch die Brust ins Auge.
Funktionspointer sind da viel zu umständlich.
Alle Bit0..7-Funktionen machen doch dasselbe. Also wäre es viel 
bequemer, eine Zählvariable zu benutzen, wann ein Byte um ist. Nimm 
einfach ein switch/case, das ist dann auch viel besser lesbar.

von Horst S. (Gast)


Lesenswert?

Tom schrieb:
> Weil die LED dann 1µs später angeht?
Eher, weil aus dem Vordergrund aufgerufen, ein zwischendurch im 
Interrupt umgesetzter Pin auf dem gleichen Port im Zweifelsfall wieder 
zurückgesetzt wird?

Peter II schrieb:
> wenn sie NUR in der ISR genutzt werden, braucht man kein volatile.
Oh, ich seh's:
Umdeklariert zu static, kompiliert und siehe da, 3210 Bytes.
Nicht schlecht.
Nach Einfügen der String.h und dem MemSet-Aufruf wieder 3220 Bytes, aber 
so viel Komfort muss wohl sein.

von (prx) A. K. (prx)


Lesenswert?

Horst S. schrieb:
> Ist ein "PORTB |= 0x01" wirklich dann ein "sbi PORTB, 1"?

Nein, glücklicherweise nicht. Daraus wird
  sbi PORTB, 0
Vorausgesetzt der PORT ist bitadressierbar. Andernfalls geht es in 
Assembler auch nicht.

von Moby A. (moby-project) Benutzerseite


Lesenswert?

Falk B. schrieb:

> Wen interessieren diese läppischen 10% im Jahr 2015

Interessant und gefragt war woher diese 10% stammen.

> wo selbst 32 Bit CPUs für wenige Euros verkauft werden?

Wen interessiert das wenn ein Easy AVR und kein 32-Bit Monstrum 
Verwendung finden soll

Horst S. schrieb:
> Warum benötige ich im Assembler-Projekt "nur" 2910 Bytes, in C aber
> "satte" 3278 Bytes?

Weil eine Hochsprache ein Programm quasi aus Fertigbausteinen 
zusammensetzt und die Aufgabenstellung damit nur unter Verlusten an 
Platz und Performance gegenüber der feiner an die Gegebenheiten 
anpassbaren Asm-Programmierung lösen kann.

Peter II schrieb:
> So wie du es gemacht hast, verhinderst du zum teil Optimierungen.

Rücksichtnahmen, die sich mit Asm generell erübrigen.

von Sebastian V. (sebi_s)


Lesenswert?

War ja nur eine Frage der Zeit bis Moby hier auftaucht... Jegliche 
Argumente für Hochsprachen sind damit hinfällig.

: Bearbeitet durch User
von Hans (Gast)


Lesenswert?

Moby du hast keine Ahnung also lass gut sein!

Horst S. schrieb:
> Peter II schrieb:
>> auch das sollte sich doch wohl über eine Funktion abbilden lassen.
>>
>> Auch kommt mir volatile viel zu oft vor. sicher das die ganzen Variablen
>> in einer ISR und dem Hauptprogramm verwendet werden?
>
> Ich hab's so 1:1 aus Assembler umgesetzt. Wie gesagt, der
> Funktionpointer wird aus der letzten aufgerufenen Funktion für den
> nächsten Interrupt umgesetzt. Das war in Assembler eine super Sache, da
> ich keinen Schleifenzähler zwischen den Interrupts puffern musste.
> Wenn ich's ändere, wird der C-Code zwar kleiner, die Vergleichbarkeit
> zum Assembler ist allerdings dann wech.

Naja so must du einen Funktionspointer "puffern"

Mach doch einen static oder einen globalen counter, dann brauchst du 
garnix puffern...

Damit sparst du dir dann nebenbei auch 1 byte ram weil aus dem 16-bit 
pointer ein 8bit int wird :)

Wenn du nur 1:1 "übersetztst", dann wird C niemal kleiner als dein ASM 
code werden.

Wenn du den compiler machen lasst und sauberen code schreibst, dann 
sollte der compiler schon noch was rausholen.

73

von Moby A. (moby-project) Benutzerseite


Lesenswert?

Hans schrieb:
> Wenn du nur 1:1 "übersetztst", dann wird C niemal kleiner als dein ASM
> code werden.

Kleiner? Wie soll denn das passieren? Da muss sich ein Asm-Programmierer 
aber schon selten dämlich anstellen :-)

Sebastian V. schrieb:
> War ja nur eine Frage der Zeit bis Moby hier auftaucht... Jegliche
> Argumente für Hochsprachen sind damit hinfällig.

Solche Untersuchungen sollte es hier noch viel häufiger geben, bis allen 
Beteiligten die immergleichen Ergebnisse in Fleisch und Blut 
übergegangen sind ;-)

von Peter II (Gast)


Lesenswert?

Wegen deinem Aufruf in ISR(PCINT1_vect)
1
PS2JumpAddress();

müssen alle Register auf dem Stack gesichert werden, das man schon ein 
paar Byte + performace aus. Da ist es viel sinnvoll darin auch gleich 
den code auszuführen.

von Peter D. (peda)


Lesenswert?

Horst S. schrieb:
> Ich hab's so 1:1 aus Assembler umgesetzt. Wie gesagt, der
> Funktionpointer wird aus der letzten aufgerufenen Funktion für den
> nächsten Interrupt umgesetzt.

In Assembler kannst Du Dir Register reservieren, das ist in C tabu.
D.h. der Compiler spart für Funktionspointer in Interrupts nichts, 
sondern das Gegenteil ist der Fall.
Obendrein weiß er nicht, was Du damit aufrufst, muß also alle 
zerstörbaren Register sichern.
Hast Du Dir mal im Assemblerlisting angesehen, was für ein riesen Bohei 
da generiert wird.
Und dazu noch der Mehrverbauch für 8 einzelne Funtionen statt für 0.

von Hans (Gast)


Lesenswert?

Naja lieber moby, ein geübter Hochsprachenprogrammierer wird versuchen 
möglichst wenig code zu kopieren.

Daher wäre in dem Fall eine Zählervariable und keine Funktionspointer 
die folge gewesen was schonmal 1 Byte weniger Ram bedeutet hätte.

Ganz nebenbei würde es auch kein copy-paste in den PS2 Files geben und 
das würde nochmal einiges bringen (was oben ja schon steht).

73

von Peter II (Gast)


Lesenswert?

kannst ja mal mit dem code testen:
1
//++++++++++++++++++++++++++++++++++++++++++
2
//External PCINT PinChange Interrupt
3
//++++++++++++++++++++++++++++++++++++++++++
4
ISR(PCINT1_vect)
5
{
6
7
  SetLED3();
8
  if ((PINC & (1<<PS2Clock)) == 0) {
9
      static state = 0;
10
      switch(state) {
11
         case 0:
12
            SetLED2();
13
            PS2ReceivedByte = 0;
14
            break;
15
         case 1:
16
         case 2:
17
         case 3:
18
         case 4:
19
         case 5:
20
         case 6:
21
         case 7:
22
            if (PINC & (1<<PS2Data)) {
23
               PS2ReceivedByte |= 0x80;
24
            }
25
            PS2ReceivedByte = (PS2ReceivedByte >> 1);
26
         case 8:
27
            //todo PS2ReceiveParity
28
            break;
29
         case 9:
30
            //todo Stop - jetzt muss doch bestimmt jemand benachrichtig werden?
31
            break;
32
      }
33
      
34
      state++;
35
      if ( state > 9 ) {
36
         state = 0;
37
      }
38
   }
39
}

von Peter II (Gast)


Lesenswert?

hier ist noch das vergessenen break
1
break

von Horst S. (Gast)


Lesenswert?

Peter II schrieb:
> Wegen deinem Aufruf in ISR(PCINT1_vect)
> PS2JumpAddress();
>
> müssen alle Register auf dem Stack gesichert werden, das man schon ein
> paar Byte + performace aus. Da ist es viel sinnvoll darin auch gleich
> den code auszuführen.

Oh mann, ich seh's: Da ist das Assembler-Konzept nu' wirklich schlecht 
übertragbar (obwohl ich auch im Assembler-Projekt nicht immer mit 
Register--Pushen und -Poppen gegeizt habe).
- Was ich noch finde: Der Optimizer kotzt mir immer wieder in der 
lss-Datei Fragmente der TxDSendByte-Routine vor die Füße. Mag der keine 
call-Befehle?

von Peter II (Gast)


Lesenswert?

Horst S. schrieb:
> Was ich noch finde: Der Optimizer kotzt mir immer wieder in der
> lss-Datei Fragmente der TxDSendByte-Routine vor die Füße. Mag der keine
> call-Befehle?

vermutlich macht er den code inline, damit ist es etwas unüberschaubar.
gehe erst mal davon aus, das er es richtig macht.

von Hans (Gast)


Lesenswert?

Nachdem der switch sehr "unbefüllt" ist würde ich das sogar so machen:
1
//++++++++++++++++++++++++++++++++++++++++++
2
//External PCINT PinChange Interrupt
3
//++++++++++++++++++++++++++++++++++++++++++
4
ISR(PCINT1_vect)
5
{
6
7
  SetLED3();
8
  if ((PINC & (1<<PS2Clock)) == 0) {
9
      static int8_t state = 0;
10
11
      if (state==0) {
12
            SetLED2();
13
            PS2ReceivedByte = 0;
14
      } else if (state<8) {
15
            if (PINC & (1<<PS2Data)) {
16
               PS2ReceivedByte |= 0x80;
17
            }
18
            PS2ReceivedByte = (PS2ReceivedByte >> 1);
19
      } else if ( state == 9 ) {
20
         state = -1;
21
      }
22
23
      state++;
24
25
   }
26
}


Ich hoffe ich hab' mich nirgends vertippt... ging nicht durch einen 
compiler...

73

von Horst S. (Gast)


Lesenswert?

Ja, ganz so einfach war's nicht, (ich wollte im ISR ja auch senden), 
aber ich sehe schon, welche Richtung das einschlägt...
1
#include "structs.h"
2
#include "Ports.h"
3
#include "LED.h"
4
#include <inttypes.h> 
5
#include <avr/interrupt.h>
6
#include <string.h>
7
8
9
static uint8_t PS2ReceivedByte;
10
static uint8_t PS2SendByte;
11
static uint8_t PS2SendByteChecksum;
12
static uint8_t PS2SendState = 0;
13
14
15
16
void PS2Init()
17
{
18
  PCMSK1 = (1<<PCINT11); //Enable Pin change inerrupt on PC3 ()PCINT11)
19
  PCICR = (1<<PCIE1);   //Enable external interrupt for PCINT14:8
20
21
  //Reset variables
22
  DataRead.LastOffset =0;
23
  DataWrite.MouseCommand = 0;
24
  PS2ReceivedByte =0;
25
  memset( &DataRead, 0, sizeof(DataRead) );
26
}
27
28
29
void PS2Send(uint8_t bt)
30
{
31
  PS2SendByte = bt;
32
33
  //Prepare checksum
34
  PS2SendByteChecksum= MakeChecksumOfByte(PS2SendByte);
35
36
  // pull down Clock for 100u
37
  PS2SendState=1;
38
  PS2PullDownClock();
39
  Wait100u();
40
41
  
42
  // pulldown data and release clock
43
  PS2PullDownData();
44
  PS2ReleaseClock();
45
  PS2SendState=2;
46
47
}
48
49
50
//++++++++++++++++++++++++++++++++++++++++++
51
//External PCINT PinChange Interrupt
52
//++++++++++++++++++++++++++++++++++++++++++
53
ISR(PCINT1_vect)
54
{
55
    if (PS2SendState == 1) return; //Ignore clocks from device while wait100u
56
57
  SetLED3();
58
  if ((PINC & (1<<PS2Clock)) == 0) 
59
  {
60
    static state = 0;
61
    if (PS2SendState==0) //RECEIVE
62
    {  
63
      switch(state) 
64
      {
65
       case 0: //Startbit
66
          SetLED2();
67
          PS2ReceivedByte = 0;
68
        state++;
69
          break;
70
       case 1:
71
       case 2:
72
       case 3:
73
       case 4:
74
       case 5:
75
       case 6:
76
       case 7:
77
       case 8:
78
          PS2ReceivedByte = (PS2ReceivedByte >> 1);
79
          if (PINC & (1<<PS2Data)) {
80
             PS2ReceivedByte |= 0x80;
81
          }
82
          state++;
83
        break;
84
       case 9:
85
          //todo PS2ReceiveParity
86
          state++;
87
          break;
88
       case 10:
89
          DataRead.MouseBuffer[DataRead.LastOffset] = PS2ReceivedByte;
90
        DataRead.LastOffset++;
91
        state = 0;
92
        break;
93
      }
94
95
96
    }
97
98
    else //SEND
99
    {
100
      switch(state) 
101
      {
102
       case 0:
103
       case 1:
104
       case 2:
105
       case 3:
106
       case 4:
107
       case 5:
108
       case 6:
109
       case 7:
110
         if ((PS2SendByte & 0x01) != 0)
111
          PS2ReleaseData();
112
        else
113
          PS2PullDownData();
114
115
        PS2SendByte = (PS2SendByte>>1);
116
        state++;
117
        break;
118
119
       case 8: //Parity
120
        if((PS2SendByteChecksum & 0x01) !=0)
121
          PS2PullDownData();
122
        else
123
          PS2ReleaseData();
124
          state++;
125
        break;
126
127
       case 9: //Stopbit
128
        PS2ReleaseData();
129
        state++;
130
          break;
131
132
       case 10: //Ack from device
133
        if ((PINC & (1<<PS2Data)) != 0)
134
          SetLED2();
135
        else
136
          ClearLED2();
137
        state =0;              
138
        //Fallback to listen
139
        PS2SendState = 0;
140
        break;
141
142
      }
143
144
    }    
145
     }
146
  ClearLED3();
147
}

Einzig interessant noch, wie lange der Code jetzt in der ISR "steht".
Zumindest bin ich jetzt im Verbrauch des Speichers mit 2648 Bytes klar 
unterhalb der Assemblerversion.

von Hans (Gast)


Lesenswert?

Du kannst gefahrlos 2 Funktionen dafür machen:
1
if (...) {
2
  Receive();
3
} else {
4
  Send();
5
}

Eigentich müsste der Compiler die beiden Funktionen automatisch inlinen.

Beim Switch/Case müsstest du im listing schaun was der compiler daraus 
macht. Teilweise ist ein if-else-if kleiner... das hängt aber von der 
architekur und dem jeweiligen anwendungsfall ab.

73

von Horst S. (Gast)


Lesenswert?

Oberflächlich mit dem Oszilloskop betrachtet (Messung der Länge von 
PCInt1), sieht die Sache nicht soooo schlecht aus.
Bei laufend sendender Maus (da hängt ja der Maussensor an der 
PS/2-Schnittstelle) habe ich während der Übertragung eine 
Interruptauslastung von ca. 12..15%, und zwar in beiden Fällen, also 
Assembler und C. (Bei C ist etwas mehr Jitter, was wohl die Switch 
Sprunghierarchie als Ursache hat).
Etwas länger als gemessen, müsste der C-Interrupt noch dauern, da noch 
der Push-Pop-Kram reinkompiliert wird, da kam ich mit dem Setzen des 
Messpins im C-Code nicht zwischen (in Assembler kein Problem), aber ich 
denke mal, nach den 16 Takten kräht der Hahn auch nicht mehr.

von Peter II (Gast)


Lesenswert?

> static state = 0;

mach mal uint8_t draus. Sonst hast du ein int (16bit) was sinnlos seit 
kostet.

von Peter II (Gast)


Lesenswert?

Horst S. schrieb:
> Etwas länger als gemessen, müsste der C-Interrupt noch dauern, da noch
> der Push-Pop-Kram reinkompiliert wird,

sollte aber nicht für alles Register sein, wenn es doch so ist stimmt 
etwas nicht. Dann inlined er bestimmt eine Funktion nicht. Prüfe ob alle 
Funktion in der ISR static sind.

Poste mal den ASM code

von Peter D. (peda)


Lesenswert?

Hans schrieb:
> Ich hoffe ich hab' mich nirgends vertippt

Ja, ich mag if-else Ketten nicht, das wird schnell unübersichtlich.
Der AVR-GCC mag switch-case und optimiert es recht gut.

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


Lesenswert?

Hans schrieb:
> Eigentich müsste der Compiler die beiden Funktionen automatisch inlinen.

Macht er, wenn man sie ordentlich als "static" deklariert.  Dann
weiß er, dass sie ohnehin niemand mehr von außerhalb aufrufen kann.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Oder einfach -flto.

Was auch kleineren Code machen kann sind: -fno-caller-saves sowie 
-fno-tree-loop-optimize und / oder -fno-move-loop-invariants.  Und 
natürlich -mrelax --gc-sections und -ffunction-sections nicht vergessen.

von Hans W. (Firma: Wilhelm.Consulting) (hans-)


Lesenswert?

Peter D. schrieb:
> Hans schrieb:
>> Ich hoffe ich hab' mich nirgends vertippt
>
> Ja, ich mag if-else Ketten nicht, das wird schnell unübersichtlich.
> Der AVR-GCC mag switch-case und optimiert es recht gut.

stand ja noch ein "Nachdem der switch sehr "unbefüllt" ist würde ich das 
sogar so machen:" drüber ;)

Hast aber natürlich recht. Von Fall zu Fall sollte man sich das trotzdem 
anschauen was schneller/kleiner ist...

73

von Rolf M. (rmagnus)


Lesenswert?

Horst S. schrieb:
> - Was ich noch finde: Der Optimizer kotzt mir immer wieder in der
> lss-Datei Fragmente der TxDSendByte-Routine vor die Füße. Mag der keine
> call-Befehle?

Er versucht, kurze Funktionen inline umzusetzen, um damit den zeitlichen 
Overhead der Calls zu sparen und den Inhalt der Funktion im Kontext 
ihres Aufrufs besser zu optimieren.

Hans schrieb:
> Beim Switch/Case müsstest du im listing schaun was der compiler daraus
> macht. Teilweise ist ein if-else-if kleiner... das hängt aber von der
> architekur und dem jeweiligen anwendungsfall ab.

Sollte an sich nicht passieren. Der Compiler ist normalerweise schon so 
clever, bei einem switch/case zu erkennen, ob eine Sprungtabelle oder 
eine Reihe von Vergleichen effizienter ist.

von Carl D. (jcw2)


Lesenswert?

Johann L. schrieb:
> Oder einfach -flto.
>
> Was auch kleineren Code machen kann sind: -fno-caller-saves sowie
> -fno-tree-loop-optimize und / oder -fno-move-loop-invariants.  Und
> natürlich -mrelax --gc-sections und -ffunction-sections nicht vergessen.

Nicht zu vergessen -mcall_prologues, falls man viele (grössere) 
Funktionen hat. Dann werden die Push-Pop-Orgien "an einer Stelle 
gebündelt". Das hat beim Transistor-Tester schon mal geholfen rund 20% 
Flash einzusparen.
Bei -flto ist zu beachten, daß fur bestes Ergebnis Compiler UND Linker 
dieses Option brauchen UND beide die selbe Optimierungs-Option. z.B. -Os 
haben sollten.

von (prx) A. K. (prx)


Lesenswert?

Hans schrieb:
> Beim Switch/Case müsstest du im listing schaun was der compiler daraus
> macht. Teilweise ist ein if-else-if kleiner... das hängt aber von der
> architekur und dem jeweiligen anwendungsfall ab.

Überlass das ruhig dem Compiler. Der analysiert die Datenverteilung und 
sucht sich dann unter den implementierten Varianten eine passende aus. 
Darunter sind auch einfache aufeinander folgende Vergleiche oder 
sukzessive Subtraktionen (bei AVR bringt das nichts, anderswo schon).

Bei einer nicht zu kleinen Anzahl numerisch verstreuter Fälle 
implementiert er auch gerne einen Vergleichsbaum. Das ist eine Technik, 
die praktisch nur ein Compiler zustande bringt.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

A. K. schrieb:
> Bei einer nicht zu kleinen Anzahl numerisch verstreuter Fälle
> implementiert er auch gerne einen Vergleichsbaum. Das ist eine Technik,
> die praktisch nur ein Compiler zustande bringt.

Und das macht avr-gcc besser als früher: https://gcc.gnu.org/PR49903

von Horst S. (Gast)


Lesenswert?

Ich hab's jetzt mal mit einem Watchdog versehen, der bei fehlenden 
Flanken den State zurücksetzt. Dazu habe ich den leidigen state aus der 
Funktion allerdings zur Modulvariable deklarieren müssen.
Zum Switch fiel mir dann noch ein: "Wozu gibt's den Default-Zweig?"
(Hilft gegen Augenkrebs).
Nachdem ich die LED-Funktionen als "extern Inline" im Header-File habe, 
sieht auch die Rettungsaktion auf dem Stack wieder übersichtlich aus:
Listing .lss:
1
//++++++++++++++++++++++++++++++++++++++++++
2
//External PCINT PinChange Interrupt
3
//++++++++++++++++++++++++++++++++++++++++++
4
ISR(PCINT1_vect)
5
{
6
 866:  1f 92         push  r1
7
 868:  0f 92         push  r0
8
 86a:  0f b6         in  r0, 0x3f  ; 63
9
 86c:  0f 92         push  r0
10
 86e:  11 24         eor  r1, r1
11
 870:  2f 93         push  r18
12
 872:  8f 93         push  r24
13
 874:  9f 93         push  r25
14
 876:  ef 93         push  r30
15
 878:  ff 93         push  r31
16
}
17
18
19
extern inline void SetLED3()
20
{
21
  PORTD |= (1<<LED3);
22
 87a:  5e 9a         sbi  0x0b, 6  ; 11 
23
.
24
.
25
.
26
.



Modul PS2 (V3)
1
#include "structs.h"
2
#include "Ports.h"
3
#include "LED.h"
4
#include <inttypes.h> 
5
#include <avr/interrupt.h>
6
#include <string.h>
7
8
9
static uint8_t PS2Byte;
10
static uint8_t PS2Checksum;
11
static uint8_t PS2Watchdog = 0;
12
static uint8_t PS2State = 0; //Listen
13
#define MSK_PS2Listen 0x00
14
#define MSK_PS2BitCounter 0x0F
15
#define MSK_PS2SendStart 0x10
16
#define MSK_PS2Send 0x30
17
18
19
20
21
void PS2Init()
22
{
23
  PCMSK1 = (1<<PCINT11); //Enable Pin change inerrupt on PC3 ()PCINT11)
24
  PCICR = (1<<PCIE1);   //Enable external interrupt for PCINT14:8
25
26
  //Reset variables
27
  DataRead.LastOffset =0;
28
  DataWrite.MouseCommand = 0;
29
  PS2Byte =0;
30
  memset( &DataRead, 0, sizeof(DataRead) );
31
}
32
33
34
35
void PS2TestWatchdog()
36
{
37
  if (PS2Watchdog == 0) return;
38
39
  PS2Watchdog--;
40
  if (PS2Watchdog == 0) 
41
    PS2State = 0;
42
}
43
44
static void RetriggerPS2Watchdog()
45
{
46
  PS2Watchdog = 4;
47
}
48
49
//Basic Port functions
50
static void PS2PullDownClock()
51
{
52
  PORTC &= ~(1<<PS2Clock);
53
  DDRC |= (1<<PS2Clock);
54
}
55
56
static void PS2ReleaseClock()
57
{
58
  DDRC &= ~(1<<PS2Clock);
59
}
60
61
static void PS2PullDownData()
62
{
63
  PORTC &= ~(1<<PS2Data);
64
  DDRC |= (1<<PS2Data);
65
}
66
67
68
static void PS2ReleaseData()
69
{
70
  DDRC &= ~(1<<PS2Data);
71
}
72
73
74
75
76
void PS2Send(uint8_t bt)
77
{
78
79
  // set a save state
80
  PS2State = MSK_PS2SendStart;
81
  //Prepare checksum
82
83
  PS2Checksum= MakeChecksumOfByte(bt);
84
85
  // pull down Clock for 100u
86
  PS2PullDownClock();
87
  Wait100u();
88
  PS2Byte = bt;
89
  
90
91
  
92
  // pulldown data and release clock
93
  PS2PullDownData();
94
  PS2ReleaseClock();
95
  PS2State= MSK_PS2Send;
96
}
97
98
99
//++++++++++++++++++++++++++++++++++++++++++
100
//External PCINT PinChange Interrupt
101
//++++++++++++++++++++++++++++++++++++++++++
102
ISR(PCINT1_vect)
103
{
104
  SetLED3();
105
  if ((PINC & (1<<PS2Clock)) == 0)  // Do something,while clock is low
106
  {
107
    switch(PS2State) 
108
    {
109
       case 0: //Receive Startbit 
110
          SetLED2();
111
          PS2Byte = 0;
112
        PS2State++;
113
          break;
114
115
      case 0x09: //Recieve PS2ReceiveParity
116
        PS2State++;
117
          break;
118
119
      case 0x0A: //Receive complete-> Transfer byte to target
120
          DataRead.MouseBuffer[DataRead.LastOffset] = PS2Byte;
121
        DataRead.LastOffset++;
122
        PS2State = MSK_PS2Listen;
123
        break;
124
125
       case 0x38: //Send Parity
126
         if((PS2Checksum & 0x01) !=0)
127
          PS2PullDownData();
128
        else
129
          PS2ReleaseData();
130
          PS2State++;
131
        break;
132
133
       case 0x39: //Send Stopbit
134
        PS2ReleaseData();
135
        PS2State++;
136
          break;
137
138
       case 0x3A: //Ack from device
139
        if ((PINC & (1<<PS2Data)) != 0)
140
          SetLED2();
141
        else
142
          ClearLED2();
143
        PS2State = 0; //Fallback to listen
144
        break;
145
146
147
       case MSK_PS2SendStart: // In 100us pause
148
         break; //Nothing to do
149
150
151
152
       default:
153
         if ((PS2State & MSK_PS2Send) == MSK_PS2Send) //Send bit 0..7
154
        {
155
           if ((PS2Byte & 0x01) != 0)
156
            PS2ReleaseData();
157
          else
158
            PS2PullDownData();
159
160
          PS2Byte = (PS2Byte>>1);
161
          PS2State++;
162
          break;
163
        }            
164
        else  //Receive Bit 0..7
165
        {
166
            PS2Byte = (PS2Byte >> 1);
167
            if (PINC & (1<<PS2Data)) 
168
          {
169
               PS2Byte |= 0x80;
170
            }
171
          PS2State++;
172
        }              
173
      }
174
     }
175
  RetriggerPS2Watchdog();
176
  ClearLED3();
177
178
179
}

von Peter II (Gast)


Lesenswert?

Horst S. schrieb:
> "Wozu gibt's den Default-Zweig?"
> (Hilft gegen Augenkrebs).

naja, übersichtlicher finde ich das nicht wirklich. So mal dann dort 
wieder nach senden und empfangen unterschieden wird.

von Horst S. (Gast)


Lesenswert?

Peter II schrieb:
> naja, übersichtlicher finde ich das nicht wirklich. So mal dann dort
> wieder nach senden und empfangen unterschieden wird.

Hehe, da hat Basic die Nase vorn. Da kann man auch
1
Select bla
2
  case 16 to 64:
3
  . 
4
  . 
5
  . 
6
end select

schreiben.

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


Lesenswert?

Kannste beim GCC auch, ist aber nicht portabel:

https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html

von Horst S. (Gast)


Lesenswert?

Jörg W. schrieb:
> Kannste beim GCC auch, ist aber nicht portabel:
>
> https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html

Das ist ja lustig:
Mit dem Default-Zweig bin ich bei 2528 Bytes.
Wenn ich die case-Bereiche verwende, spare ich noch 4 Bytes.

von Falk B. (falk)


Lesenswert?

@ Horst S. (hdc)

>Das ist ja lustig:
>Mit dem Default-Zweig bin ich bei 2528 Bytes.
>Wenn ich die case-Bereiche verwende, spare ich noch 4 Bytes.

Damit wirst du die Welt retten . . .

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


Lesenswert?

Falk B. schrieb:
> Damit wirst du die Welt retten . . .

Zumindest nicht Mobys Welt, denn sein C-Programm ist ja nun schon
mehr als 10 % kleiner als sein altes Assemblerprogramm. :)

von Peter II (Gast)


Lesenswert?

Jörg W. schrieb:
> Zumindest nicht Mobys Welt, denn sein C-Programm ist ja nun schon
> mehr als 10 % kleiner als sein altes Assemblerprogramm. :)

und wir sind erst in der ps2 quelle - das ist noch einige zu machen.

von Karl H. (kbuchegg)


Lesenswert?

Kleiner Hinweis an den C-Lernenden.

Wenn du versucht bist, solche Kommentare zu schreiben
1
    switch(PS2State) 
2
    {
3
       case 0: //Receive Startbit

dann solltest du dir überlegen, ob du nicht für deine magischen 
Konstanten benannte Bezeichner einführen willst. Im einfachsten Fall 
sind das einfach nur ein paar #define, mit denen du den Zahlen im Code 
'einen Namen' gibst. Für den Compiler kommt das auf dasselbe heraus, 
denn der sieht letzt Endes ohnehin wieder die Zahl, nachdem der 
Präprozessor die Textersetzung durchgeführt hat. Aber für dich als 
Programmierer macht es einen Unterschied. Vor allen Dingen in ein paar 
Wochen bzw. Monaten, wenn du noch Erweiterungen am Programm vornehmen 
willst. Denn irgendwas willst du ja jetzt mit dem freigespielten 
Speicher machen :-)

Ein
1
        PS2State = WAIT_FOR_STARTBIT;
liest sich viel besser und erzählt mir in der Anweisung alles was ich 
wissen muss. Auf jeden Fall mehr als ein
1
        PS2State = 0; //Fallback to listen

Zudem hab ich durch die Bezeichnung einen Begriff, nach dem ich im Code 
suchen kann und der mich dann eben direkt zu
1
    switch(PS2State) 
2
    {
3
       case WAIT_FOR_STARTBIT:
4
...
bringt, ohne dass ich erst mal alle Stellen, an denen 0 vorkommt beim 
Suchen überspringen muss.
Alles was du dazu brauchst, ist ein
1
#define WAIT_FOR_STARTBIT     0
und die Sache ist geritzt (selbiges natürlich auch für die anderen 
States bzw. die anderen magischen Konstanten).

Darauf solltest du dein Augenmerk legen und nicht darauf, ob du deinen 
Prozessor nun zu 17.6% oder doch zu 18.5% ausnutzt. Das interessiert 
nämlich niemanden. Was aber interessiert, das ist dass dein Programm 
auch in Zukunft noch wartbar bleibt.
Du setzt im Moment die falschen Prioritäten. Hast du ein Problem damit, 
dass dein Programm zu groß werden würde um ins Flash zu passen? Nein? 
Dann interessiert das momentan auch nicht. Kümmere dich lieber erst mal 
um die wirklich wichtigen Dinge und nicht um solche Kinkerlitzchen.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Alternativ: einen enum einführen.  Ist für Zustandsautomaten fast
immer sinnvoll.  Man muss auch nicht zwanghaft alle Zustände
benennen, auch sowas geht:
1
enum ps2_state {
2
  PS2ReceiveStartBit = 0,
3
  PS2ReceiveParity = 9,
4
  PS2ReceiveComplete = 10,
5
};

Ein enum ist in C nichts anderes als ein paar Namen für einen "int"
(in C++ ist es viel stärker ein eigenständiger Datentyp als in C).

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
          SetLED2();
ist auch schlecht. Wähle Bezeichnungen nach ihrer Funktion und nicht 
nach technischen Begebenheiten (zumindest nicht im Normalfall). Die LED 
erfüllt eine Funktion. Das mag zb die LED sein, die einen Fehler 
anzeigt. Dann nenn das auch so. Ein
1
          TurnOnErrorLED();
erzählt mir an dieser Stelle im Code viel mehr als dein profanes 
SetLED2. Heute magst du noch wissen, dass die LED 2 die Fehlerled ist. 
Aber in 3 Monaten sieht das alles ganz anders aus. Denn da muss ich erst 
mal in der Funktion nachsehen, ob
* mit 'Set' gemeint ist, dass die LED eingeschaltet wird. Oder doch 
ausgeschaltet?
* ich nachsehen muss, was denn die Bedeutung der LED 2 war. Denn genau 
die interessiert mich, wenn ich nachvollziehen will oder muss, was denn 
eigentlich hier
1
        if ((PINC & (1<<PS2Data)) != 0)
2
          SetLED2();
3
        else
4
          ClearLED2();
passiert.
(Und nein, du brauchst mir jetzt nicht erklären was hier passiert. Darum 
geht es nicht. Es geht darum, dass ich als Code-Lesender hier mir die 
Dinge zusammensuchen muss und das man das mit den richtigen Bezeichnern 
auch vermeiden kann. Zudem sinkt die Fehlerchance, weil einem der Code 
schon beim Durchlesen seltsam vorkommt, weil das Niedergeschriebene 
keinen Sinn ergibt.
Ein
1
      x = x1 + x2;
kann richtig oder falsch sein. Mann weiss es nicht. Aber das bei
1
      NrCars = PriceBrutto + TimeToPack;
irgendwas nicht stimmen kann, ist unmmittelbar ersichtlich. Die 3 
Begriffe, die hier verwendet werden, können in keinen irgendwie 
sinnvollen Zusammenhang gebracht werden. Dass die alle gemeinsam in 
einer Anweisung in dieser Form auftauchen ist sehr wahrscheinlich 
falsch. Dazu brauch ich vom Rest des Programms nichts wissen.

Und noch was: In 3 Monaten ist dein Vorteil des Entwicklers fast auf 0 
zusammengeschmolzen. Wenn du in 3 Monaten wieder an den Code rann gehst, 
dann geht es dir nicht besser als jemandem, der von diesem Code noch nie 
etwas gesehen hat. D.h. du musst heute den Code so schreiben, dass du 
ihn in 3 Monaten auch noch nachvollziehen kannst. Das ist eine der 
Bedeutungen von 'wartbarem Code'.
Das ist auch einer der Gründe warum man überhaupt 'Hochsprachen' 
verwendet. Weil man sich auf die Verfahren konzentrieren kann ohne sich 
um den technischen Kleinkram kümmern zu müssen.
)

: Bearbeitet durch User
von Hans (Gast)


Lesenswert?

was ganz gerne auch was bringt, sind structs statt globale.

Damit "erzwingt" man quasi indirekten zugriff und spart sich das 16-bit 
pointer-laden hin und wieder.

also aus
1
static uint8_t PS2Byte;
2
static uint8_t PS2Checksum;
3
static uint8_t PS2Watchdog = 0;
4
static uint8_t PS2State = 0; //Listen
1
struct PS2VariableStruct {
2
    uint8_t PS2Byte;
3
    uint8_t PS2Checksum;
4
    uint8_t PS2Watchdog = 0;
5
    uint8_t PS2State = 0; //Listen
6
}
7
8
static PS2VariableStruct PS2Variables;

Wobei ehrlich gesagt du eigentlich schon quasi objekt orientiert 
unterwegs bist und sich C++ schon anbieten würde...

von Dumdi D. (dumdidum)


Lesenswert?

Hans schrieb:
> und spart sich das 16-bit
> pointer-laden hin und wieder.

Kannst Du näher ausführen was Du damit meinst?

von Hans (Gast)


Lesenswert?

Naja X mit der Basis-Adresse vom Struct laden und dann
1
LD r0, X+
2
LD r1, X+
3
LD r2, X+
4
LD r3, X

Würde alle 4 Variablen in einem Rutsch laden...

Am ARM macht der GCC sowas, am AVR muss ich gestehen weiß ich das nicht.

73

von Horst S. (Gast)


Lesenswert?

Karl H. schrieb:
> Kleiner Hinweis an den C-Lernenden.

Der C-Lernende ist in diesem Fall äußerst verwöhnt (fast schon versaut, 
weil ich kann mir Namen mittlerweile wirklich nur noch so lange merken, 
bis sie aus dem Bildschirm raus sind)

In C# hätte ich's wegen IntelliSense benamt. Hier bin ich ehrlich gesagt 
unentschlossen. Ich bin auch kein Fan von dem Gedanken, ein Protokoll 
anhand von Quellcode zu studieren, da bin ich eher Dokumentöse:
1
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2
// Further PS2 protocol informations:
3
// http://www.computer-engineering.org/ps2protocol/
4
// http://www.computer-engineering.org/ps2mouse/
5
//
6
// PS2 Protocol is executed by Pin change interrupt PCINT1 and controlled via PS2State variable.
7
// RECEIVING A BYTE
8
// PS2State | State
9
// 0x00     | listening, wait for start bit from device
10
// 0x01     | wait for first data bit (LSB)
11
// ...      | ...(wait for data bits 1..6)
12
// 0x08     | wait for last data bit (MSB)
13
// 0x09     | wait for parity from device
14
// 0x0A     | wait for stop bit from device. 
15
//          | Successful received stop bit:
16
//          |  - Reading completed
17
//          |  - transfer byte to next level
18
//          |  - Reset PS2State to listen state
19
//
20
// SENDING A BYTE
21
// PS2State | State
22
// 0x10     | Set by PS2Send function. Prepare send by pulldown clock line for 100us
23
//          | At this time transfer from device will be interrupted
24
// 0x30     | Set by PS2Send function. Clock has been released and was pulled down by device
25
//          |  -> Set first data bit (LSB)
26
// ...      | ...(set data bits 1..6)
27
// 0x37     | Set last data bit (MSB)
28
// 0x38     | Set parity bit (odd)
29
// 0x39     | Set stop bit
30
// 0x3A     | Get ack from device. Transfer complete, go back to Listen (PS2State=0x00)
31
//
32
// Remark: PS2State is incremended each step, if not otherwise noted.   
33
//
34
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aber in der Realität hätte ich wahrscheinlich nur notiert, welche 
State-Bereiche Empfang und Senden regeln und wo/warum das Sperren des 
Empfangs über die 100us-Pause erfolgt.

von 900ss (900ss)


Lesenswert?

Jörg W. schrieb:
> Zumindest nicht Mobys Welt

Nun wart doch mal ab, das ist nur die Ruhe vor dem Sturm. Moby optimiert 
noch den Assemblercode ;-)

von Ingo (Gast)


Lesenswert?

Ich kann mich täuschen, aber ich habe noch nirgends ne Zeile ASM von 
Moby gesehn...

von Moby (Gast)


Lesenswert?

Jörg W. schrieb:
> Zumindest nicht Mobys Welt, denn sein C-Programm ist ja nun schon
> mehr als 10 % kleiner als sein altes Assemblerprogramm. :)

Eine uC-Softwarewelt braucht niemand retten, wenn sie mit pure Asm schon 
im Klartext mit allen seinen Möglichkeiten, Transparenzen und Freiheiten 
formuliert ist . Immer wieder schön, wenn dann der nächstkleinere 
Controller genügt ;-)

Aber nicht, daß ich die ehrlichen Optimierbemühungen hier ohne Sympathie 
verfolgen würde. Ist nur blöd, wenn der Fehler am System liegt- zur 
eigentlichen zu entwickelnden Programmlogik immer noch zusätzlich die 
Suche nach dem besten der groben C-Bausteine samt passender 
Verkettungsausdrücke
hinzukommt. Und als besonderes Extra schließlich die Code-Optimierung 
anhand der Befindlichkeiten des verwendeten Compiler-Werkzeugs.

Schreibts im Klartext, dann brauchts keine Disassemblierung zum 
Klarwerden darüber, was nun klarerweise geschieht.

Ingo schrieb:
> Ich kann mich täuschen, aber ich habe noch nirgends ne Zeile ASM von
> Moby gesehn...

Du täuscht Dich ;-)

von Horst S. (Gast)


Lesenswert?

Moby schrieb:
> Aber nicht, daß ich die ehrlichen Optimierbemühungen hier ohne Sympathie
> verfolgen würde. Ist nur blöd, wenn der Fehler am System liegt- zur
> eigentlichen zu entwickelnden Programmlogik immer noch zusätzlich die
> Suche nach dem besten der groben C-Bausteine samt passender
> Verkettungsausdrücke
> hinzukommt.

Ich schau hier auch nur das erste mal über meinen Tellerrand, allerdings 
kann ich jetzt nach zwei Tagen Arbeit mit dem C-Gedöns sagen:
Den Kram, den der Optimierer da zusammenbaut, den hätte ich in Assembler 
weder so optimiert hinbiegen können, noch hätte ich danach eine Chance 
zu verstehen, was ich da warum programmiert habe.

Nachteil (ganz klar): Du lieferst Dich der Stabilität des Compilers aus. 
Und wehe Dir, der baut Mist.

Aber so weit bin ich noch nicht gekommen...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter II schrieb:
> ISR(PCINT1_vect)

oder sogar
1
ISR (PCINT1_vect, __attribute__((__flatten__)))

von Carl D. (jcw2)


Lesenswert?

@Horst S.:
Glückwunsch daß du den Tellerrand übersprungen hast. Ganz ehrlich 
gemeint. Leider zeigen sich hier immer nur die, die den Tellerrand 
nichtmal erahnen können.

von Klaus (Gast)


Lesenswert?

Moby schrieb:
> Immer wieder schön, wenn dann der nächstkleinere
> Controller genügt ;-)

Den es in Wirklichkeit gar nicht gibt. Heutzutage ist die Diegröße und 
damit der wirkliche Preis nur durch die Anzahl der IO-Pads bestimmt. Da 
leere Flächen auf dem Die nicht wirklich Sinn machen, wird er mit Flash 
und RAM gefüllt. Da manche Spezialisten immer noch glauben, größer 
kostet mehr, kann man durch einfache Bondoptionen den Kleinkunden für 
den gleichen Chip mit freigeschaltetem Speicher mehr abnehmen. Den 
Einkäufern von Großabnehmern kann man das natürlich nicht erzählen, die 
zahlen für den (in Wirklichkeit gar nicht) größeren Chip das Selbe.

Ist wie mit der Bandbreite bei manchen Scopes, die kleinere gibt es 
technisch nicht wirklich. Und die Preisdifferenz verhandelt ein 
erfahrener Einkäufer schnell weg.

Horst S. schrieb:
> Nachteil (ganz klar): Du lieferst Dich der Stabilität des Compilers aus.
> Und wehe Dir, der baut Mist.

Und der Vorteil, du lieferst dich der Qualität vieler Compilerentwickler 
aus und bist nicht dem einen Assemblernerd ausgeliefert, der mit der 
nächsten Chipgeneration schon nichts mehr anfangen kann. Und wehe, der 
hat Mist gebaut.

MfG Klaus

von qwerty (Gast)


Lesenswert?

Moby schrieb:
> Immer wieder schön, wenn dann der nächstkleinere
> Controller genügt ;-)
War das C-Programm hier nicht kleiner oder hab ich was verpasst?


> nächstkleinere Controller
Zu welchem Preis? Wenn ich für sagen wir mal 1€ mehr den µC mit Speicher 
bekommen kann nutze ich gerne den Komfort einer Hochsprache. 
(ASM-)Handoptimierung zahlt sich -wenn überhaupt- erst bei hohen 
Stückzahlen aus..

von Moby (Gast)


Lesenswert?

Klaus schrieb:
> Assemblernerd ... der mit der
> nächsten Chipgeneration schon nichts mehr anfangen kann.

Und auch nicht muß, weil die AVRs schon lange Zeit und noch für lange 
Zeit dicke reichen. C-Code bedeutet für eine neue Chipgeneration (z.B. 
ARM) im übrigen auch nicht, unverändert übernommen werden zu können.

qwerty schrieb:
> (ASM-)Handoptimierung

Die optimale Ausnutzung der Hardware ist aber gerade das was den Vorteil 
von Asm ausmacht- ansonsten ist es auch nicht mehr als gewöhnliches 
(zuweilen wesentlich weniger textlastiges) Codeschreiben.

Man kann drüber streiten, welche Programmierung im Bereich kleiner 
Controller bequemer und zeitsparender ist (eine entsprechende 
Softwarebasis vorausgesetzt). Man kann nicht darüber streiten, daß es 
subjektive Vorlieben für das eine oder andere gibt.
Aber Hand aufs Herz- alles hat irgendwo seinen Preis. Der bedeutet im 
Fall der (bequemeren?) Hochsprachenverwendung immer Platz-und 
Performancenachteile. Ganz gleich, wie gut ein Compiler sein mag. Der 
kann weder schlechte Programmierung ausgleichen noch überhaupt jede 
konkrete Absicht des Programmierers erahnen. Erfordert um halbwegs 
effizient zu werden viel Herumkonfiguriererei.

Ich möchte mir von keinem Compiler irgendwas vorschreiben und 
verschleiern lassen, sondern das Heft des Handelns 100%ig selbst in der 
Hand behalten. Wo überall geht das heute noch so einfach wie bei den 
kleinen 8-Bittern? Dazu braucht es nur ein paar Dutzend 
Asm-Anweisungen und das Datenblatt des Controllers seines Vertrauens.

von Carl D. (jcw2)


Lesenswert?

> Dazu braucht es nur ein paar Dutzend
Asm-Anweisungen ...

Womit die Größenverhältnisse klar dargelegt wurden. Ja, auch so kleine 
Programme kann man auf einem AVR laufen lassen. Sollte man aber keine 
Sub-μs-Timing-Anforderungen haben und wo braucht man das schon, dann ist 
Handoptimierung pure Verschwendung. Selbst wenn ich statt ein paar 
Dutzend aller 256 Befehlsworte eines Tiny4 brauchen sollte, who cares. 
Kleiner wird der nimmer. Und eins ist bei mir sehr knapp: Lebenszeit! 
Die will ich nicht mit Register-Allokieren verbringen.
Aber das wird Troll-by wieder ganz anders sehen. Sein Erkenntnisgewinn 
aus dem Thread, der die "entscheidende Frage" mal wirklich untersucht 
und feststellt, daß die vermeintlichen Geisterfahrer doch in die 
richtige Richtung fahren: exakt NULL!

: Bearbeitet durch User
von Moby (Gast)


Lesenswert?

Carl D. schrieb:
> Sollte man aber keine
> Sub-μs-Timinganforderungen haben und wo braucht man das schon, dann
> Handoptimierung pure Verschwendung.

Ob nun ein konkretes Projekt von Asm-Platz- und Performanceersparnis 
profitiert steht sicher auf einem anderen Blatt. Aber es könnte doch 
größer werden (müssen). Es ist da sehr beruhigend mehr Reserven, wie 
überhaupt die totale Kontrolle in der Hinterhand zu wissen und seinen 
Controller im ungünstigen Falle nicht "auslöten" sprich wechseln zu 
müssen...
Die wenigen dutzend simplen Asm-Instruktionen bedeuten aber auch, man 
braucht nicht mehr zu seinem Glück, es vereinfacht und macht die Sache 
transparent.

> Und eins ist bei mir sehr knapp: Lebenszeit!
> Die will ich nicht

... mit Programmierung von Code und Werkzeug verschwenden und auch 
nicht mit unnützen Controllerwechseln und mit stetig neuen Architekturen 
und stetig neuen Werkzeugen und und und...

> Geisterfahrer

gibts nicht, solange man erfolgreich programmiert. Das allerdings geht 
mehr oder weniger effizient und vorausschauend ;-)

von qwerty (Gast)


Lesenswert?

Moby schrieb:
> immer Platz- und Performancenachteile.
War das C-Programm hier nicht kleiner oder hab ich was verpasst?

> Ganz gleich, wie gut ein Compiler sein mag. Der
> kann weder schlechte Programmierung ausgleichen noch überhaupt jede
> konkrete Absicht des Programmierers erahnen.
Das kann ein Assembler noch weniger, der überetzt 1:1 ohne jegliche 
Optimierung.

von Marvin M (Gast)


Lesenswert?

In Zeiten, in denen 32-Bitter inzwischen weniger kosten als 8-Bitter ist 
es müßig, über die "bessere" Ausnutzung durch ASM zu reden.
Bei der Portierung 8-Bit zu 32-Bit macht es durchaus einen Unterschied, 
ob man bei ASM 100% des Codes überarbeiten muss oder bei C nur die I/O 
Bereiche - die in meinem Fall vielleicht 5-10% ausmachten.
Beispiel: Der STM32F030 kostet bei Farnell aktuell 1,10 Eur bei 
Einzelabnahme. TSSOP20, 16KFlash, 4KRam, 12-Bit A/D, SPI/I2C/Uart, DMA, 
16-Bit Timer. AVRs sind bei mir ausgelistet....

von Markus (Gast)


Lesenswert?

Moby schrieb:
> Und auch nicht muß, weil die AVRs schon lange Zeit und noch für lange
> Zeit dicke reichen.
Für dich vielleicht, es soll aber auch Leute geben die größeres vorhaben 
als
> ein paar Dutzend Asm-Anweisungen

> C-Code bedeutet für eine neue Chipgeneration (z.B.
> ARM) im übrigen auch nicht, unverändert übernommen werden zu können.
Mit einer guten Abstraktion geht das. Arduino Code z.B. läuft 
unverändert auf einem UNO (ATmega328) und einem DUE (SAM3X8E ARM 
Cortex-M3).

> Die optimale Ausnutzung der Hardware ist aber gerade das was den
> Vorteil von Asm ausmacht
Wozu einen alten AVR optimal ausnutzen wenn man für 1,10€ schon einen 
STM32 haben kann?

von Christian F (Gast)


Lesenswert?

Ich kann Mobys Freude am Register schieben und asm programmieren 
verstehen. Total. Es ist ja anscheinend auch definitiv Hobby. Da kann 
ich voll nachvollziehen, dass es ihm Spaß macht den alten dil Atmel in 
der Lochrasterplatine ans Laufen zu bekommen. Das ist weder zynisch noch 
sarkastisch gemeint.
Ebenso halte ich nicht besonders viel davon im Hobby aus Prinzip den 
32-bitter zu benutzen. Das fordern jetzt Leute, die der Arduino Fraktion 
im nächsten Thread vorwerfen planlos und resourcenverschwendend drauf 
los zu programmieren.

Ich kann sogar Moby's Angst vorm Unbekannten und neuen Sachen in 
gewisser Weise nachvollziehen.

Aber das bornierte Auftreten und völlige ignorieren von Argumenten und 
Einwänden kann ich nicht nachvollziehen und auch nicht akzeptieren. So 
disqualifiziert man sich für mich. Das kann ich mir allenfalls im 
Alteheim in der Demenzabteilung vorstellen. Erschreckend, dass auch hier 
die Leute nur und ausschließlich schwarz weiß denken können.

Was ist denn jetzt mit der Codegröße???

von Rolf M. (rmagnus)


Lesenswert?

Christian F schrieb:
> Ich kann Mobys Freude am Register schieben und asm programmieren
> verstehen. Total. Es ist ja anscheinend auch definitiv Hobby.

Klar kann das Spaß machen. Ich hatte auch mal Spaß daran, Assemblercode 
auf Papier zu schreiben, von Hand zu Assemblieren und das Ergebnis dann 
in eine Hex-Tastatur einzutipppen. Ist doch vollkommen ok.
Aber Moby stellt es als das einzig wahre Allheilmittel dar, mit dem man 
mit geringstem Aufwand µC-Projekte beliebigen Umfangs auf einem AVR ans 
laufen bekommt und daß alles andere vollkommener Unsinn ist.
Das einzige Beispiel, das ich bisher mal von ihm gesehen habe - im 
Rahmen eines Threads über C++ auf µC - war eine blinkende LED. Zu viel 
mehr reicht die Vorstellungskraft offenbar nicht. Ich warte ja immer 
noch auf seine FAT-Implementation oder den TCP/IP-Stack in Assembler.

> Ebenso halte ich nicht besonders viel davon im Hobby aus Prinzip den
> 32-bitter zu benutzen.

Es kommt drauf an, was das Ziel ist. Wenn man Lust dazu hat, in ASM 
jeden Taktzyklus einzeln rauszukitzeln und eine bestimmte Aufgabe auf 
einem möglichst kleinen µC umzusetzen, ist es ja legitim, den AVR zu 
nutzen.
Es gibt ja auch heute noch Leute, die Spiele für den C64 entwickeln, und 
das finde ich duraus cool.

Wenn man dagegen ein größeres Projekt umsetzen und sich mehr auf die 
eigentliche Funktion konzentrieren will, dann ist die Effizienz beim 
Schreiben des Programms wichtiger als bei dessen Ausführung. Und wenn 
man merkt, daß man doch noch eine größere Zusatzfunktion haben will, ist 
auch die Option, mit vertretbarem Aufwand auf einen ganz anderen 
Controller wechseln zu können, wichtig.

In beiden Fällen ist es unerheblich, ob der Controller nun einen Euro 
mehr oder weniger kostet.

> Ich kann sogar Moby's Angst vorm Unbekannten und neuen Sachen in
> gewisser Weise nachvollziehen.

Wenn man aber so die Klappe darüber aufreißt, wie er, sollte man es 
zumindest mal richtig verstanden haben.

> Aber das bornierte Auftreten und völlige ignorieren von Argumenten und
> Einwänden kann ich nicht nachvollziehen und auch nicht akzeptieren.

Moby kommt halt in jedem Thread, in dem es um [beliebige Hochsprache] 
geht, zu irgendeinem Zeitpunkt daher und bringt dann immer und immer 
wieder das gleiche an. In den meisten dieser Threads wurde nicht mal 
nach Assembler gefragt. Das ist so, als ob im Heimwerker-Forum zu jedem 
beliebigen Thread über Akkuschrauber (z.B. zum Vergleich zwischen 
Hersteller X und Hersteller Y) einer reinkommt und empfielt, doch lieber 
den klassischen Schraubenzieher zu nehmen, weil der die Fitness 
verbessert und viel mehr Leistung hat (wenn man denn stark genug ist).
Diese übertriebene Vehemenz, die offenbar auch keinerlei Nutzen für 
irgendwen bringt, hat dazu geführt, daß Moby von den meisten hier 
belächelt und nicht mehr ernst genommen wird.

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


Lesenswert?

Rolf M. schrieb:
> Diese übertriebene Vehemenz, die offenbar auch keinerlei Nutzen für
> irgendwen bringt, hat dazu geführt, daß Moby von den meisten hier
> belächelt und nicht mehr ernst genommen wird.

Früher™, im Usenet, hätte man bei Antwortbeiträgen auf ihn dann
entsprechend ein
1
Followup-To: de.alt.gruppenkasper

gesetzt. ;-)

von Hans W. (Firma: Wilhelm.Consulting) (hans-)


Lesenswert?

Interessanterweise habe ich übrigens noch keinen Thread gesehen wo Moby 
ein ASM ergebnis geliefert hat das tatsächlich wesentlich kleiner ist...


73

von Horst S. (Gast)


Lesenswert?

Hans W. schrieb:
> 73

Jetzt hab ich Dich: Was ist das? Dein Alter? Die Anzahl Deiner 
Nachfahren?
Hat sich der Supercomputer doch mit 42 verrechnet?

(Wollte ich doch letztens schon fragen.)

von Chris D. (myfairtux) (Moderator) Benutzerseite


Lesenswert?

Kennst Du nicht?

Das sind Abkürzungen in der Amateurfunk-Telegrafie (oder auch 
woanders?).

Siehe: https://de.wikipedia.org/wiki/Betriebstechnik_%28Amateurfunk%29

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Also ein Vorgänger der Smiley- und Emoji-Seuche.

von Horst S. (Gast)


Lesenswert?

Na, dann:
1
ISR_OT_73:
2
 push r16
3
 in r16, SREG
4
 push r16
5
 call WinkeWinke
6
 pop r16
7
 out SREG, r16
8
 pop r16
9
ISR_OT_73_End:
10
 reti
11
//OT-Ende: Ich widme mich mal meiner UART.

von Karl Käfer (Gast)


Lesenswert?

Hallo Rolf,

Rolf M. schrieb:
> Aber Moby stellt es als das einzig wahre Allheilmittel dar, mit dem man
> mit geringstem Aufwand µC-Projekte beliebigen Umfangs auf einem AVR ans
> laufen bekommt und daß alles andere vollkommener Unsinn ist.
> Das einzige Beispiel, das ich bisher mal von ihm gesehen habe - im
> Rahmen eines Threads über C++ auf µC - war eine blinkende LED. Zu viel
> mehr reicht die Vorstellungskraft offenbar nicht.

Er kann eben einfach nicht mehr als eine LEDs blinken lassen, zu mehr 
reicht es bei ihm mit seinem geliebten Assembler nicht. Deswegen faselt 
er ja auch immer von "ein paar Dutzend Instruktionen", die angeblich 
einfacher seien als die 32 Schlüsselworte in C, weil er von den ~ 130 
Instruktionen, die so ein AVR kennt, eben nur gerade mal zwei Dutzend 
beherrscht. Das ist schade, aber zum Glück ja nur für ihn. ;-)

Liebe Grüße,
Karl

von Ralf G. (ralg)


Lesenswert?

Diese Entwicklung habe ich auch durchgemacht :-)
Horst S. schrieb:
> Ich schau hier auch nur das erste mal über meinen Tellerrand, allerdings
> kann ich jetzt nach zwei Tagen Arbeit mit dem C-Gedöns sagen:
> Den Kram, den der Optimierer da zusammenbaut, den hätte ich in Assembler
> weder so optimiert hinbiegen können, noch hätte ich danach eine Chance
> zu verstehen, was ich da warum programmiert habe.

Ab einem gewissen Projektumfang muss man eben auch in Assembler 'ein 
bisschen Struktur' reinbringen, um die Übersicht zu behalten. Allerdings 
muss das den Compiler nicht interessieren...

von Kenner (Gast)


Lesenswert?

Ganz normal, Compiler produziert immer mehr code als assembler.

von Carl D. (jcw2)


Lesenswert?

> Ab einem gewissen Projektumfang muss man eben auch in Assembler 'ein
bisschen Struktur' reinbringen, um die Übersicht zu behalten.

Ich bevorzuge da eben eine Problembeschreibungssprache mit höherem 
Abstraktionsgrad. Und überlasse die Transformation in HW-Befehle der 
dafür spezialisierten Software. Diese optimiert im Übrigen nicht nur für 
die Zielplattform, sondern schon vorher auf einem abstrakteren Level. 
Programme werden nicht lesbarer, wenn man z.B. (ganz simples) bei 
Schleifen die gemeinsamen Ausdrücke herauszieht. Man muß diese 
(Knuth-Eval-)Optimierungschritte beim Lesen/Verstehen immer wieder 
rückgängig machen. Schön wenn da welche ein Programm geschrieben habe, 
das sowas kann. Und denen morgen ein noch besserer Kniff einfällt. Dann 
einfach nochmal "Build". Die Abhängigkeit vom OS-Projekt GCC kann ich 
verschmerzen, verglichen mit so Dingen wie BASCOM, AvrLuna, ... wo gerne 
auch mal Einzelpersonen dahinterstehen.

von Moby (Gast)


Lesenswert?

qwerty schrieb:
> War das C-Programm hier nicht kleiner oder hab ich was verpasst?

Na ja, wer aufmerksam gelesen hat wird diesen Umstand von mir schon mit 
klaren Worten, aber ohne persönlich zu werden kommentiert sehen ;-)

qwerty schrieb:
> Das kann ein Assembler noch weniger, der überetzt 1:1 ohne jegliche
> Optimierung.

Die Unzulänglichkeiten grober C-Bausteine müssen hier auch nicht 
optimiert werden. Vor der Aufgabe, ein gutes Programm zu schreiben 
stehen Asm- und C- Programmierer gleichermaßen. Asm allein ist nun 
leider keine Garantie für guten Code, wie man beim TO-Programm schön 
sehen kann ;-)

Hans W. schrieb:
> Interessanterweise habe ich übrigens noch keinen Thread gesehen wo Moby
> ein ASM ergebnis geliefert hat das tatsächlich wesentlich kleiner ist...

Gelegenheiten gab es schon, mit C gegenzuhalten...
Aber natürlich ist es das keinem Hochsprachler wert.
Könnte ja dumm ausgehen. Es wird von mir weiter Code in der 
Projekte-Abteilung geben. Versprochen. Jeder sei dann herzlichst 
eingeladen, kürzere, schnellere C-Lösungen zu präsentieren! Passieren 
wird aber nix vermute ich.

Marvin M schrieb:
> In Zeiten, in denen 32-Bitter inzwischen weniger kosten als 8-Bitter ist
> es müßig, über die "bessere" Ausnutzung durch ASM zu reden.

Markus schrieb:
> Wozu einen alten AVR optimal ausnutzen wenn man für 1,10€ schon einen
> STM32 haben kann?

In Zeiten, in denen 8-Bitter sehr viele Aufgaben einfacher lösen sind 
noch lang nicht vorbei. Das kann einem durchaus sogar der eine oder 
andere Cent mehr wert sein.

Markus schrieb:
> Für dich vielleicht, es soll aber auch Leute geben die größeres vorhaben

Absolut einverstanden. Den Code des TO würde ich aber noch lange nicht 
dazuzählen.

Christian F schrieb:
> dass es ihm Spaß macht den alten dil Atmel in
> der Lochrasterplatine

Lochrasterplatine?
Na dann wär ein großer Vorteil kleinster AVRs aber hinfällig: Die 
Baugröße! So eine winzige Platine wie ein kleines 
Beitrag "Kleines Tiny13 Sensorboard"
zum Beispiel.

Christian F schrieb:
> Ich kann sogar Moby's Angst vorm Unbekannten und neuen Sachen in
> gewisser Weise nachvollziehen.

Warum den Angst? Die Dinge für Projekte möglichst einfach zu halten ist 
kühle rationale Abwägung. Diese sollen möglichst schnell, möglichst 
simpel ihren Zweck erfüllen. Es braucht diesbezüglich kein 
zeitvernichtendes Hinterherhecheln hinter den neuesten Technologien und 
Programmiermethoden- da würde man ja nie fertig. Wenn das jemand als 
Schwarz-Weiß Denken bezeichnet kann ich damit leben. Ich nenn es 
Konzentration auf das Wesentliche.

von Moby (Gast)


Lesenswert?

Jörg W. schrieb:
> Followup-To: de.alt.gruppenkasper

Das mache ein User hier mal mit einem Mod.
Der wird dann aber sowas von schnell zum Lösch-Mod und verweist auf 
Forenregeln ;-)

Karl Käfer schrieb:
> Er kann eben einfach nicht mehr als eine LEDs blinken lassen, zu mehr
> reicht es bei ihm mit seinem geliebten Assembler nicht.

Nun ja, ein Karl Käfer kennt sich da eben aus.
Für Dich steht da allerdings auch noch eine Aufgabe an:
Dem SerialComInstruments wirklich Paroli zu bieten ;-)

von Christian F (Gast)


Lesenswert?

...Und wenn dein Projekt ebenfalls in c problemlos auf dem Tiny 
umzusetzen wäre?
Der code ist händisch so optimiert, dass jedes Bit gesetzt ist und kein 
Platz mehr da ist? Ram ist voll? Dann wäre das Projekt fragwürdig: null 
Chance auf Erweiterung bzw. nötige Fehlerbehebung ist nicht unbedingt 
eine gute Basis.

von Dumdi D. (dumdidum)


Lesenswert?

Moby schrieb:
> Gelegenheiten gab es schon, mit C gegenzuhalten...
> Aber natürlich ist es das keinem Hochsprachler wert.
> Könnte ja dumm ausgehen. Es wird von mir weiter Code in der
> Projekte-Abteilung geben.

Vielleicht mal ein-zwei Links auf diese Projekte? (Vielleicht auch nicht 
gerade die kleinsten)

von Moby (Gast)


Lesenswert?

Christian F schrieb:
> Der code ist händisch so optimiert, dass jedes Bit gesetzt ist und kein
> Platz mehr da ist? Ram ist voll? Dann wäre das Projekt fragwürdig: null
> Chance auf Erweiterung bzw. nötige Fehlerbehebung ist nicht unbedingt
> eine gute Basis.

In dieser Situation wäre dann aber nicht Asm fragwürdig, sondern 
wirklich die Controller-Auswahl. Gewisse Reserven sollten schon vorrätig 
sein. Bei Asm mehr, bei Hochsprache noch viel mehr...

Dumdi D. schrieb:
> Vielleicht mal ein-zwei Links auf diese Projekte?

Ja, wie gesagt ich werde nicht untätig bleiben.

> Vielleicht auch nicht gerade die kleinsten

Natürlich nur kleine.
Oder meinst Du, daß größere die Chance erhöhen, daß sich ein C-ler die 
Arbeit macht?

von Peter D. (peda)


Lesenswert?

Wenn man wirklich den kleinsten Code haben will, dann sollte man einen 
8051 verwenden. Der hat einen so kompakten Befehlssatz, da kann der AVR 
lange nicht mithalten.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Moby schrieb:
> In dieser Situation wäre dann aber nicht Asm fragwürdig, sondern
> wirklich die Controller-Auswahl. Gewisse Reserven sollten schon vorrätig
> sein. Bei Asm mehr, bei Hochsprache noch viel mehr...

Bei Hochsprache eher weniger. Basisfunktionen sind ja schon mit drin. 
Und wie Du siehst, ist das C-Programm jetzt schon kleiner als das 
Assembler-Programm.

> Dumdi D. schrieb:
>> Vielleicht mal ein-zwei Links auf diese Projekte?
>
> Ja, wie gesagt ich werde nicht untätig bleiben.

Und, wo sind sie? Ach, noch gar nicht veröffentlicht? Warum hast Du den 
Leser hier darüber so lange im Irrtum gelassen? Du hast es nämlich so 
dargestellt, als ob Deine Projekte schon seit einer Ewigkeit unter 
"Projekte & Code" zu finden seien.

Darf ich Dich in die Kategorie "Blender" stecken?

> Natürlich nur kleine.
> Oder meinst Du, daß größere die Chance erhöhen, daß sich ein C-ler die
> Arbeit macht?

LED-Blinken ist natürlich in Assembler kürzer. Das Projekt sollte schon 
anspruchsvoller sein. Dann wirst Du sehen, dass ein adäquates Programm 
in C insgesamt kürzer sein kann als in Assembler, wo der Programmierer 
wegen Übersichtsverlust gar nicht mehr weiter optimieren kann.

von Peter D. (peda)


Lesenswert?

Ich finde die Aufgabe hat sehr schön die Vorteile von C aufgezeigt.
Das Switch/Case ist nicht nur deutlich besser lesbar, als ein Wust von 
vielen fast gleichen Funktionen + ICALL, sondern erzeugt auch viel 
weniger Code.
Was will man mehr?

von TriHexagon (Gast)


Lesenswert?

Moby schrieb:
> Die wenigen dutzend simplen Asm-Instruktionen bedeuten aber auch, man
> braucht nicht mehr zu seinem Glück, es vereinfacht und macht die Sache
> transparent.

Tatsächlich? Vergleiche z.B. mal Assembler einer CISC und einer RISC 
CPU. Auf dem ersten Blick mag RISC einfacher und übersichtlicher sein, 
wenn man dann aber mal ein bisschen Code schreibt, merkt man schnell 
dass RISC den Code ganz schön aufbläst (die ständigen LOAD- und 
STORE-Instruktionen zum Beispiel). Die Übersicht leidet zunehmend auch 
darunter etc. . Also doch nur täuschende Einfachheit, die dann ins 
Gegenteil umschlägt?

von Moby (Gast)


Lesenswert?

Peter D. schrieb:
> Wenn man wirklich den kleinsten Code haben will, dann sollte man
> einen
> 8051 verwenden. Der hat einen so kompakten Befehlssatz, da kann der AVR
> lange nicht mithalten.

Mag ja sein. Der AVR ist aber ein Gesamtpaket vorteilhafter 
Eigenschaften. Die simple Asm-Programmierbarkeit ist da nur ein 
Argument.

Daß man im übrigen an der schönen Kombination AVR/ASM für einfache bis 
mittlere Projekte schon so lange festhalten kann ist einer einfachen 
Tatsache geschuldet: Größere 32-Bit (ARM) Chips machen es heute eben 
noch nicht viel anders, nur viel komplizierter...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Moby schrieb:
> Größere 32-Bit (ARM) Chips machen es heute eben
> noch nicht viel anders, nur viel komplizierter...

Andere Umschreibung für "Moby hat keine Ahnung". Du machst Dich gerade 
zum Brot, lass das lieber.

von Moby (Gast)


Lesenswert?

TriHexagon schrieb:
> Moby schrieb:
>> Die wenigen dutzend simplen Asm-Instruktionen bedeuten aber auch, man
>> braucht nicht mehr zu seinem Glück, es vereinfacht und macht die Sache
>> transparent.
>
> Tatsächlich? Vergleiche z.B. mal Assembler einer CISC und einer RISC
> CPU. Auf dem ersten Blick mag RISC einfacher und übersichtlicher sein,
> wenn man dann aber mal ein bisschen Code schreibt, merkt man schnell
> dass RISC den Code ganz schön aufbläst (die ständigen LOAD- und
> STORE-Instruktionen zum Beispiel). Die Übersicht leidet zunehmend auch
> darunter etc. . Also doch nur täuschende Einfachheit, die dann ins
> Gegenteil umschlägt?

Ja ich kann das nachvollziehen da ich wie viele auch aus der Z80-CISC 
Welt komme. RISC und CISC haben aber beide ihre Vor-und Nachteile. 
Load-Store Operationen im Speziellen kann man bei AVR aber recht 
speichersparend über die Index-Befehle abwickeln...

Die Übersicht tät ich bei vielen komplexen C-Ausdrücken verlieren;-)

von Moby (Gast)


Lesenswert?

Frank M. schrieb:
> Moby schrieb:
>> Größere 32-Bit (ARM) Chips machen es heute eben
>> noch nicht viel anders, nur viel komplizierter...
>
> Andere Umschreibung für "Moby hat keine Ahnung". Du machst Dich gerade
> zum Brot, lass das lieber.

Na was machen sie den groß anders? Lass mal Deine Ahnung sprechen.
Steckt da etwa mehr Intelligenz drin die mir tatsächlich Arbeit 
abnimmt oder läuft es nicht doch viel mehr nur auf eine Potenzierung von 
Konfigurationsarbeiten hinaus? Falls Du bestreiten möchtest daß diese 
Chips komplexer zu programmieren sind können wir an dieser Stelle gleich 
abbrechen...

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


Lesenswert?

Frank M. schrieb:
> Darf ich Dich in die Kategorie "Blender" stecken?

Ein Projekt lässt sich finden:

Beitrag "Re: Analoger Sensor (LM355) mit Operationsverstärker (+AVR Asm-Code)"

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Moby schrieb:
> Na was machen sie den groß anders?

Allein schon die 32-Bit lassen viele Barrieren fallen, mit denen Du auf 
einem 8-bittgem AVR zu kämpfen hast.

> Lass mal Deine Ahnung sprechen.

Nö, googlen kannst Du selber. Stell Dich nicht blöder an als Du bist.

> Steckt da etwa mehr Intelligenz drin die mir tatsächlich Arbeit
> abnimmt oder läuft es nicht doch viel mehr nur auf eine Potenzierung von
> Konfigurationsarbeiten hinaus?

Unter Assembler ist es natürlich ein erheblicher Aufwand, einen 
STM32-Pin auf Output zu programmieren. Kein Wunder, dass Du diese Arbeit 
scheust und Dich auf Deiner kleinen AVR-Insel verkriechst.

Wenn ich an Moby denke, denke ich immer an einen Einsiedler, der schon 
vor zwanzig Jahren auf einer einsamen Insel zusammen mit einem ATTiny 
gestrandet ist und seitdem die weitere Entwicklung komplett verschlafen 
hat.

> Falls Du bestreiten möchtest daß diese
> Chips komplexer zu programmieren sind können wir an dieser Stelle gleich
> abbrechen...

Da ist überhaupt nichts "komplexer". Man hat nur etwas mehr 
Schreibarbeit. Aber das macht Komplexität bestimmt überhaupt nicht aus!

Wie wärs mit der Portierung von IRMP und IRSND in Assembler?

Du hast die Wahl zwischen AVR (ATTiny, ATmega, Xmega), PIC, STM32 und 
diversen anderen ARM-Prozessoren. Da läuft nämlich ein und derselbe 
IRMP-C-Code drauf. Du musst ja nicht direkt auf alle portieren. 
ATTiny würde reichen.

Oder ist die Aufgabe für Dich zu "komplex"?

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jörg W. schrieb:
> Frank M. schrieb:
>> Darf ich Dich in die Kategorie "Blender" stecken?
>
> Ein Projekt lässt sich finden:
>
> Beitrag "Re: Analoger Sensor (LM355) mit Operationsverstärker (+AVR Asm-Code)"

Zu trivial. Mehr ist da nicht? Du als Moderator hast wahrscheinlich 
bessere Suchmöglichkeiten ;-)

von Moby (Gast)


Lesenswert?

Frank M. schrieb:
> Da ist überhaupt nichts "komplexer". Man hat nur etwas mehr
> Schreibarbeit. Aber das macht Komplexität bestimmt überhaupt nicht aus!

Schön, damit hast Du Deine Ahnung gerade nett demonstriert.
Du machst Dich gerade zum Brot, also lass das lieber.
Schade eigentlich, denn IRMP ist eine interessante Software, bei der 
auch mal wirklich der C-Portiervorteil zum Tragen kommt.

von X4U (Gast)


Lesenswert?

Horst S. schrieb:
> ISR_OT_73:
>  push r16
>  in r16, SREG
>  push r16
>  call WinkeWinke
>  pop r16
>  out SREG, r16
>  pop r16
> ISR_OT_73_End:
>  reti

Sagt mal, was ist an diesem Codeschnipsel eigentlich lesbar (für nicht 
AVRer), wartbar (für nicht Assemblerfreaks), oder gar portabel (was ja 
per Definition nur  bedeutet das ganze auf eine andere Plattform zu 
übertragen zu können)?

von Moby (Gast)


Lesenswert?

Frank M. schrieb:
> Du als Moderator hast wahrscheinlich
> bessere Suchmöglichkeiten ;-)

Hätte er.
Aber das wird er nicht wollen ;-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

X4U schrieb:

> Sagt mal, was ist an diesem Codeschnipsel eigentlich lesbar

  call WinkeWinke

> wartbar (für nicht Assemblerfreaks)

  call WinkeWinke

> oder gar portabel

  call WinkeWinke

Das wars aber auch schon.

von Matthias L. (Gast)


Lesenswert?

>merkt man schnell
>dass RISC den Code ganz schön aufbläst (die ständigen LOAD- und
>STORE-Instruktionen zum Beispiel).

Meine Erfahrung sagt genau das Gegenteil. Während des Studiums hatte ich 
mit einem SAB80C85 (oder so ähnlich) und einem Motorola-uC zu tun.
Da diese beiden CISC Vertreter nur einen Akku und paar Spezialregister 
hatten, musste dauernd gePUSHd und gePOPd werden. Denn alle Operationen 
(Addition, Prüfung auf irgendwas) konnten nur mit dem AKKU durchgeführt 
werden.

Bei einem AVR dagegen, hat man (fast) 32 gleichwertige Register. Da kann 
man Operationen von jedem Register zu jedem Register durchführen...

von Moby (Gast)


Lesenswert?

X4U schrieb:
> Sagt mal, was ist an diesem Codeschnipsel eigentlich lesbar

Alles, wenn Du das Datenblatt und die paar Instruktionen kennst.
Klartext- und jeder weiß was gespielt wird.
Was gibt es demgegenüber für herrlich komplexe C-Ausdrücke!
Um da durchzublicken brauchts schon etwas mehr.
Aber vermutlich ist es gerade das, auf das sich hier mancher C-Freak was 
einbildet?

von Ralf G. (ralg)


Lesenswert?

Moby schrieb:
> Hätte er.
Ich bin auch nur auf dieses eine Projekt gestoßen. Fand es aber nicht 
erwähnenswert.

> Aber das wird er nicht wollen ;-)
Aber du willst das doch nicht so stehenlassen? Mach' doch einfach mal 
eine Linkliste für die Unwissenden. Dürfte doch kein großer Aufwand 
sein.

von Matthias L. (Gast)


Lesenswert?

>Alles, wenn Du das Datenblatt und die paar Instruktionen kennst.
>Klartext- und jeder weiß was gespielt wird.
>Was gibt es demgegenüber für herrlich komplexe C-Ausdrücke!

[asm]
> ISR_OT_73:
>  push r16
>  in r16, SREG
>  push r16
>  call WinkeWinke
>  pop r16
>  out SREG, r16
>  pop r16
> ISR_OT_73_End:
>  reti
[/asm]

vs:
1
ISR_OT_73
2
{
3
  WinkeWinke();
4
}

von Moby (Gast)


Lesenswert?

Ralf G. schrieb:
> Moby schrieb:
>> Hätte er.
> Ich bin auch nur auf dieses eine Projekt gestoßen. Fand es aber nicht
> erwähnenswert.

Musst Du auch nicht. Um hier für Vergleiche herzuhalten ists ohnehin zu 
klein. Die Erwähnung durch den Mod folgte wahrscheinlich einer ganz 
anderen Absicht.

> Aber du willst das doch nicht so stehenlassen? Mach' doch einfach mal
> eine Linkliste für die Unwissenden. Dürfte doch kein großer Aufwand
> sein.

Schau mal, ich veröffentliche hier wann und genau das was mir passt 
und das wird auch weiter geschehen. Der Aufwand ist ja leider auch 
meine Sache. Das wird mich nicht davon abhalten, hier meine 
Meinung zu äußern auch wenn mancher, um diese ernstzunehmen, erst große 
Vorzeigeprojekte braucht. Die brauch ich aber -hier- nicht.

von Moby (Gast)


Lesenswert?

Matthias L. schrieb:
> [asm]
>> ISR_OT_73:
>>  push r16
>>  in r16, SREG
>>  push r16
>>  call WinkeWinke
>>  pop r16
>>  out SREG, r16
>>  pop r16
>> ISR_OT_73_End:
>>  reti
> [/asm]
>
> vs:
> ISR_OT_73
> {
>   WinkeWinke();
> }

Na sonderlich komplex ist der C-Ausdruck nun aber nicht gelungen.
Und was versteckt sich eigentlich hinter der C-Funktion???
Insofern ist das ein Vergleich von Äpfeln mit Birnen.
Das würde ich zum Punkt Hochsprachen-Intransparenz rechnen!

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Warum WUSSTE ich, dass das wieder mal so ausgeht? Der allwöchentliche 
"Assembler ist supertoll" Thread.
Ich verweise nur auf den nach dem selben Schema ebenfalls aus dem Ruder 
gelaufenen Beitrag "Re: C-Code optimieren (passt nicht in Attiny2313) :("

Dumdi D. schrieb:
> Vielleicht mal ein-zwei Links auf diese Projekte?
> (Vielleicht auch nicht gerade die kleinsten)
Würde mich auch interessieren. Ich hatte da im 
Beitrag "Re: C-Code optimieren (passt nicht in Attiny2313) :(" schon mal was 
angeregt...

Horst S. schrieb:
> Ich habe ein Programmchen für einen ATMega168 zuerst auf Assemblerbasis
> erstellt und anschließend auf gcc portiert. Das funktioniert auch alles
> (zumindest nicht schlechter als in Assembler), was mich aber zur Zeit
> etwas die Augenbrauen hochziehen lässt:
> Warum benötige ich im Assembler-Projekt "nur" 2910 Bytes, in C aber
> "satte" 3278 Bytes?
Dieser klitzekleine(!) Mehrpreis ist das, was du dafür bezahlst, dass du 
dein Programm auch in 1 Jahr noch verstehst, erweitern und warten 
kannst.

Oder andersrum: passt es noch in den Controller? Ist es schnell genug?
Gut. Fertig. Du bekommst die mit Assembler "eingesparten" 300 Bytes 
nicht ausgezahlt...

von X4U (Gast)


Lesenswert?

Moby schrieb:
> Alles, wenn Du das Datenblatt und die paar Instruktionen kennst.
> Klartext- und jeder weiß was gespielt wird.

Nachdem ich das ganze gelernt und diverse Datenblätter gewälzt habe sehe 
ich das ein paar Daten von Register X nach Speicher Y verschoben werden. 
Unter "Klartext" verstehe ich etwas ganz anderes.

> Was gibt es demgegenüber für herrlich komplexe C-Ausdrücke!
> Um da durchzublicken brauchts schon etwas mehr.

Man kann sich in jeder Sprache (auch einer natürlichen) so Ausdrücken 
das keiner was versteht ;-).


> Aber vermutlich ist es gerade das, auf das sich hier mancher C-Freak was
> einbildet?

Mir ist das egal. Hab mit Assembler, Basic Html C Pascal Lisp usw. 
gearbeitet.

Mich interessiert das Ergebnis (ganz schmerzfrei).

Der sieht so aus:
Die "C_Freaks" haben die Codegröße 10% unter die des Assemblers 
gedrückt, bei ähnlicher Performance. Dazu haben Sie nur wenige Postings 
gebraucht.Die Assembler-Freaks haben dem bisher nichts entgegen zu 
setzen.

von Ralf G. (ralg)


Lesenswert?

Moby schrieb:
> Na sonderlich komplex ist der C-Ausdruck nun aber nicht gelungen.
Da staunst du jetzt, was? So einfach ist 'C'!
> Und was versteckt sich eigentlich hinter der C-Funktion???
Gegenfrage(n):
Was versteckt sich eigentlich hinter der gleichnamigen ASM-Funktion? Das 
hast du gleich rausgefunden? Oder hast du die gar überlesen? ASM ist 
wohl doch nicht so übersichtlich... ^^

von Peter D. (peda)


Lesenswert?

Hans schrieb:
> was ganz gerne auch was bringt, sind structs statt globale.
>
> Damit "erzwingt" man quasi indirekten zugriff und spart sich das 16-bit
> pointer-laden hin und wieder.

Der AVR-GCC ist nicht blöd, ihm ist das schnurz.
Er erkennt, daß die Struct global liegt und nimmt trotzdem LDS/STS.
Ist zwar etwas mehr Code (2Wort-Befehle), dafür aber 2 Zyklen für das 
Pointer laden gespart.

Zum indirekten Zugriff kannst Du ihn nur zwingen, indem Du den Pointer 
übergibst und das Inlinen verbietest.

von TriHexagon (Gast)


Lesenswert?

Matthias L. schrieb:
> Meine Erfahrung sagt genau das Gegenteil. Während des Studiums hatte ich
> mit einem SAB80C85 (oder so ähnlich) und einem Motorola-uC zu tun.
> Da diese beiden CISC Vertreter nur einen Akku und paar Spezialregister
> hatten, musste dauernd gePUSHd und gePOPd werden. Denn alle Operationen
> (Addition, Prüfung auf irgendwas) konnten nur mit dem AKKU durchgeführt
> werden.
>
> Bei einem AVR dagegen, hat man (fast) 32 gleichwertige Register. Da kann
> man Operationen von jedem Register zu jedem Register durchführen...

Stimmt, aber moderne CISC haben heutzutage auch eine Menge Register. Die 
paar Transistoren mehr sind heute einfach kein Problem. Beim x86_64 
wurden zum Beispiel auch mehr Allzweckregister hinzugefügt.

von Horst S. (Gast)


Lesenswert?

Lothar M. schrieb:
> Dieser klitzekleine(!) Mehrpreis ist das, was du dafür bezahlst, dass du
> dein Programm auch in 1 Jahr noch verstehst, erweitern und warten
> kannst.
>
> Oder andersrum: passt es noch in den Controller? Ist es schnell genug?
> Gut. Fertig. Du bekommst die mit Assembler "eingesparten" 300 Bytes
> nicht ausgezahlt...

Nein, bekomme ich nicht. Allerdings war der Thread im ersten Drittel 
auch noch als sachlich zu betiteln (und ich hab was dabei gelernt).

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


Lesenswert?

Lothar M. schrieb:
> Dieser klitzekleine(!) Mehrpreis ist das, was du dafür bezahlst, dass du
> dein Programm auch in 1 Jahr noch verstehst, erweitern und warten
> kannst.

Nö, Lothar, inzwischen ist doch sein C-Programm sogar kleiner als die
ursprüngliche Assembler-Version.  Insofern war der Thread ja für Horst
durchaus nützlich.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Jörg W. schrieb:
> Nö, Lothar, inzwischen ist doch sein C-Programm sogar kleiner als die
> ursprüngliche Assembler-Version.
Ach Mann, das habe ich im ganzen Gebashe übersehen... :-/
Aber es ist doch prinzipiell so schon beeindruckend, dass auch ohne 
die ganzen Kniffe, Interna und Tricks der Code vom Compiler so klein 
ist. Ich ziehe meinen Hut (ich habe wirklich einen) vor den 
Compilerbauern.

Horst S. schrieb:
> Allerdings war der Thread im ersten Drittel auch noch als sachlich zu
> betiteln
Das ist der übliche Verlauf eines üblichen "C vs. Assembler" Threads.

> (und ich hab was dabei gelernt).
Na bitte, darum gehts.

von Horst S. (Gast)


Lesenswert?

Lothar M. schrieb:
> Ach Mann, das habe ich im ganzen Gebashe übersehen... :-/

Das ist schade, dass immer nur maximal der TE den Inhalt mitbekommt. Wer 
zu spät einsteigt, sieht immer zuerst die aufgestellten Stinkefinger und 
fängt lieber neu bei 0 an.

von (prx) A. K. (prx)


Lesenswert?

TriHexagon schrieb:
> Vergleiche z.B. mal Assembler einer CISC und einer RISC
> CPU. Auf dem ersten Blick mag RISC einfacher und übersichtlicher sein,

Die RISC Philosophie adressierte von Anfang an ausdrücklich die Nutzung 
von Compilern, nicht Assembler-Programmierung. Adressierung ist oft 
umständlicher, weil von der Distanz abhängig. Konstanten kann man 
abhängig vom Wert auf verschiedene Art laden, usw. Das ist zwar auch für 
den Compilerbauer zusätzlicher Aufwand - aber nur einmal.

von (prx) A. K. (prx)


Lesenswert?

TriHexagon schrieb:
> Stimmt, aber moderne CISC haben heutzutage auch eine Menge Register. Die
> paar Transistoren mehr sind heute einfach kein Problem.

Im Kontext der von dir genannten AMD/Intel Architekturen gibt es kaum 
noch einen Zusammenhang zwischen der Anzahl sichtbarer Register und der 
Anzahl real intern vorhandener Register. Intern haben heutige 
Implementierungen dank renaming eine dreistellige Anzahl Register.

So art viele moderne CISCs gibt es allerdings nicht, was die 
Befehlssatzarchitektur angeht. Die meisten, soweit es noch aktuelle 
Implementierungen gibt, stammen im Kern aus den 70/80ern und wurden 
allenfalls mal modernisiert wie x86 oder Coldfire.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Peter D. schrieb:
> Zum indirekten Zugriff kannst Du ihn nur zwingen, indem Du den Pointer
> übergibst und das Inlinen verbietest.

Meiner Erfahrung nach nimmt er mal LDS/STS und mal LD/ST R+. Eine 
einfach nachvollziehbare Regel habe ich noch nicht gefunden. Und nicht 
immer ist die Wahl optimal.

von TriHexagon (Gast)


Lesenswert?

A. K. schrieb:
> So art viele moderne CISCs gibt es allerdings nicht, was die
> Befehlssatzarchitektur angeht. Die meisten, soweit es noch aktuelle
> Implementierungen gibt, stammen im Kern aus den 70/80ern und wurden
> allenfalls mal modernisiert wie x86 oder Coldfire.

Mein Gefühl sagt mir ohnehin, dass heutzutage kaum noch reine CISC und 
RISC Prozessoren entwickelt werden. Das sind irgendwie alles Hybriden, 
welche versuchen die Vorteile beider Welten zu vereinen.

von (prx) A. K. (prx)


Lesenswert?

TriHexagon schrieb:
> Mein Gefühl sagt mir ohnehin, dass heutzutage kaum noch reine CISC und
> RISC Prozessoren entwickelt werden.

Eine der neuesten mir bekannten Architekturen ohne Vorgänger ist 
MaxQ2000. Die ist noch deutlich weiter reduziert als Load/Store-RISC, 
weil es noch nicht einmal klare Lade/Speicherbefehle gibt.

> Das sind irgendwie alles Hybriden,
> welche versuchen die Vorteile beider Welten zu vereinen.

Was die Befehlssatzarchitektur angeht, also das, was der Programmierer 
sieht? Was wären da solche neueren Entwicklungen?

: Bearbeitet durch User
von TriHexagon (Gast)


Lesenswert?

A. K. schrieb:
>> Das sind irgendwie alles Hybriden,
>> welche versuchen die Vorteile beider Welten zu vereinen.
>
> Was die Befehlssatzarchitektur angeht, also das, was der Programmierer
> sieht? Was wären da solche neueren Entwicklungen?

Das habe ich falsch formuliert, ganz vergessen dass sich RISC und CISC 
nur an die Befehlssatzarchitektur bezieht. An die RISC/CISC Architektur 
hält man sich heute noch strikt.

Was ich meinte war, dass Eigenschaften die früher RISC/CISC vorbehalten 
waren, heutzutage bei beiden Arten zu finden sind. Also z.B. hatten 
früher nur die RISC Prozessoren viele Register, im Gegensatz waren 
Pipelinening und Sprungvorhersage (evtl. auch Caching) den CISC 
Prozessoren vorbehalten. Heute muss man sich nur mal den ARM Cortex-M4 
oder noch besser den M7 anschauen, der hat so einiges eingebaut.

von TriHexagon (Gast)


Lesenswert?

Wobei das größtenteils die logische Konsequenz aus dem Verkleinern von 
Strukturen etc. ist. Aber warum hatten die CISC früher dann so wenig 
Register? Die paar Flip-Flops machen neben den vielen anderen 
Transistoren auch nicht mehr viel aus.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

A. K. schrieb:
> Peter D. schrieb:
>> Zum indirekten Zugriff kannst Du ihn nur zwingen, indem Du den Pointer
>> übergibst und das Inlinen verbietest.
>
> Meiner Erfahrung nach nimmt er mal LDS/STS und mal LD/ST R+. Eine
> einfach nachvollziehbare Regel habe ich noch nicht gefunden. Und nicht
> immer ist die Wahl optimal.

Wer ne Idee hat, wie das besser get, bitte vortreten und erklären :-)

Als Preis gibt's dann mindestens Lothars Hochachtung und die der avr-gcc 
Nutzer :-)

von (prx) A. K. (prx)


Lesenswert?

TriHexagon schrieb:
> Also z.B. hatten
> früher nur die RISC Prozessoren viele Register,

Immerhin 16 Stück bei VAX und IBM 360.

> im Gegensatz waren
> Pipelinening und Sprungvorhersage (evtl. auch Caching) den CISC
> Prozessoren vorbehalten.

Nein.

von Horst S. (Gast)


Lesenswert?

2208!
UART rennt jetzt mit zwei dicken Switches, allerdings wird's durch die 
eingestellte Baudrate auch nicht schneller.
Ich vergleiche morgen noch die Längen der ISR (wenn ich Muße hab).

von (prx) A. K. (prx)


Lesenswert?

TriHexagon schrieb:
> Aber warum hatten die CISC früher dann so wenig
> Register?

In der Anfangsphase der 8-Bitter war die Anzahl Transistoren nicht ganz 
so unerheblich. Der 6502 hatte grad mal 3500 Transistoren. Ausserdem war 
der Prozessor damals nicht wesentlich schneller als der Speicher. Als 
sich das änderte kamen Register auf.

> Die paar Flip-Flops machen neben den vielen anderen
> Transistoren auch nicht mehr viel aus.

Die 256 Bits der 16 16-Bit-Register des RCA 1802 machen einen nicht 
unerheblichen Teil des Dies aus. Ein statisches CMOS Flipflop hat 6-8 
Transistoren. 
http://www.visual6502.org/images/1802E/RCA_1802E_die_20x_top_p067152_1600w.jpg

von TriHexagon (Gast)


Lesenswert?

@A. K. danke für die ganzen Hintergrundinformationen. Ich bin wohl etwas 
zu jung um sowas zu wissen.

Wow gerade mal 3500 Transistoren, es hat sich einiges getan in der Zeit.

von (prx) A. K. (prx)


Lesenswert?

TriHexagon schrieb:
> Wow gerade mal 3500 Transistoren, es hat sich einiges getan in der Zeit.

Schöne Übersicht: https://en.wikipedia.org/wiki/Transistor_count

von Karl H. (kbuchegg)


Lesenswert?

Rolf M. schrieb:

> Ich warte ja immer
> noch auf seine FAT-Implementation oder den TCP/IP-Stack in Assembler.

Oh ja, bitte Moby!

Ich verspreche, dass ich mir dann auch die Mühe mache und das ganze für 
den gcc nutzbar zu machen, damit dann alle etwas von einer kleinen, 
weitgehend fehlerfreien Implementierung haben, die dann auch noch keinen 
einzigen Taktzyklus und kein einziges Byte im Flash herschenkt.

Das heisst: nachdem natürlich gegen einen der weiter verbreiteten 
C-Versionen geprüft wurde, ob dem auch wirklich so ist.

von Carl D. (jcw2)


Lesenswert?

Alles was ich von Moby's ASM-Künsten in den Projekten finden konnte, 
sine 33 Maschinenbefehle, die irgendwie den ADC benutzen. Was sie genau 
tun ist leider nicht dokumentiert, es scheint auch nur ein Fragment zu 
sein und ich vermute in C wäre das sowas wie:
ADC_init() und ADC_read() wobei letzteres wohl in einem TimerInt 
aufgerufen werden sollte. Zur Doku würden auch die benutzten Register 
gehören, denn ein Sicher von solchen ist nicht Bestandteil der "Lib".
In dem Thread geht es übrigens hauptsächlich um einen 
Meßbereicheumsetzer LM335 an 5V AVR-ADC. "Elektronische" verhält sich M. 
dabei genau so wie "programmatisch".

von Horst S. (Gast)


Lesenswert?

2032!
Die 2k-Grenze hab' ich geknackt. Die Switch-Anweisungen sehen jetzt 
schon etwas undurchschaubar aus.
UARTTelegramV3.c
1
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2
// UARTTelegram: PC controlled UART protocol with 4 commands 
3
//V3 state compressed version
4
//
5
// ReadMem/WriteMem: Direct Reading/Writing a block of memory (specified by start address and block length) from/to this device  
6
// ReadDevice/ WriteDevice: Indirect reading/writing a blöck of memory (specified by start address and block length)
7
// 
8
//WRITEMEM
9
// PC Sends      |OldState    |NewState    |RxDTask
10
// TelID         |0x00        |0x01        |buffer telegramID
11
// cmd 0x01      |0x01        |0x10        |prepare receiving target address low byte
12
// Targ. addr lb |0x10        |0x11        |get target address low byte
13
// Targ. addr hb |0x11        |0x12        |get target address high byte
14
// Length lb     |0x12        |0x13        |get length low byte
15
// Length hb     |0x13        |0x14        |get length high byte
16
// data       |0x14        |0x14/5      | set data to RAM, decrement length.
17
//                                         | If length = 0, set state to 0x15 and start ack telegram by sending TelegramID
18
//                                         | SWITCH TO TxD
19
// -       |0x15        |0x16        | Send writemem ack (0x81)
20
// -       |0x16        |0x00        | Send checksum and terminate transfer by setting state to 0x00 (listen)
21
//
22
//
23
//READMEM
24
// PC Sends      |OldState    |NewState    |RxDTask
25
// TelID         |0x00        |0x01        |buffer telegramID
26
// cmd 0x02      |0x01        |0x20        |prepare receiving target address low byte
27
// Targ. addr lb |0x20        |0x21        |get target address low byte
28
// Targ. addr hb |0x21        |0x22        |get target address high byte
29
// Length lb     |0x22        |0x23        |get length low byte
30
// Length hb     |0x23        |0x24        |get length high byte, and start ack telegram by sending TelegramID
31
//                                         | SWITCH TO TxD
32
// -       |0x24        |0x25        | Send readmem ack (0x82)
33
// -       |0x25        |0x25/0x00   | Send data, dec. length. If length = 0, send checksum and  
34
// -                      | terminate transfer by setting state to 0x00 (listen)
35
//
36
//
37
//WRITEDEVICE
38
// PC Sends      |OldState    |NewState    |RxDTask
39
// TelID         |0x00        |0x01        |buffer telegramID
40
// cmd 0x03      |0x01        |0x30        |prepare receiving peripherie ID
41
// Peri. addr    |0x30        |0x31        |get periphrie address
42
// Length lb     |0x31        |0x32        |get length low byte
43
// Length hb     |0x32        |0x33        |get length high byte, check lock state
44
// data       |0x33        |0x33/4      | set data to Peripherie ram if not locked, decrement length.
45
//                                         | If length = 0, set state to 0x34 and start ack telegram by sending TelegramID
46
//                                         | SWITCH TO TxD
47
// -       |0x34        |0x35        | Send writedevice ack (0x83)
48
// -       |0x35        |0x00        | Send checksum and terminate transfer by setting state to 0x00 (listen)
49
//
50
//
51
//READDEVICE
52
// PC Sends      |OldState    |NewState    |RxDTask
53
// TelID         |0x00        |0x01        |buffer telegramID
54
// cmd 0x04      |0x01        |0x40        |prepare receiving peripherie ID
55
// Peri. addr    |0x40        |0x41        |get periherie address 
56
// Length lb     |0x41        |0x42        |get length low byte
57
// Length hb     |0x42        |0x43        |get length high byte, and start ack telegram by sending TelegramID
58
//                       |!!!!If device is locked, wait for unlock
59
//                                         | SWITCH TO TxD
60
// -       |0x43        |0x44        | Send readDevice ack (0x84)
61
// -       |0x44        |0x44/0x00   | Send data, dec. length. If length = 0, send checksum and  
62
// -                      | terminate transfer by setting state to 0x00 (listen)
63
64
65
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
66
67
68
69
#include "structs.h"
70
#include <inttypes.h> 
71
#include <avr/interrupt.h>
72
#include "LEDV2.h"
73
74
75
76
77
78
//Forward references
79
PeripherieTableEntry* GetPeripherieTableEntry(uint8_t ID);
80
void TxDSendByte(uint8_t sendByte);
81
void RefreshRS232TimeOutWatchdog();
82
83
84
//Variables
85
static uint8_t UARTTimeOutWatchdog = 15; 
86
static uint8_t UARTPeripherieID;
87
static uint8_t UARTChecksum;
88
static uint8_t UARTReadWriteDeviceStatus;   //Used to signal success of ReadDevice/ WriteDevice commands
89
90
static uint8_t UARTState;   //Used to signal success of ReadDevice/ WriteDevice commands
91
static uint8_t UARTTelegrammID;
92
static uint8_t UARTCommand;
93
static uint8_t* UARTTargetAddress;
94
static uint16_t  UARTDataLength;
95
96
97
98
#define MSK_RxD_RWDSError 0x40    // 0: SUCCEEDED, 0x40: ERROR
99
#define  PT_LOCK_TWICurrentWrite_Mask  0x01  // Bit 0: TWICurrentWrite (Locked state for RS232)
100
#define  PT_LOCK_RS232CurrentWrite_Mask 0x02   // Bit 1: RS232CurrentWrite (Locked state for TWI)
101
#define  PT_LOCK_NewWriteData_Mask 0x04    // Bit 2: NewWriteData
102
#define  PT_LOCK_TWICurrentRead_Mask 0x08    // Bit 3: TWICurrentRead (Locked state for RS232)
103
#define  PT_LOCK_RS232CurrentRead_Mask 0x10  // Bit 4: RS232CurrentRead (Locked state for RS232)
104
105
106
//******************************************
107
//RxD
108
//******************************************
109
ISR(USART_RX_vect)
110
{
111
  RefreshRS232TimeOutWatchdog();
112
  uint8_t receivedByte = UDR0; 
113
114
  PeripherieTableEntry* tableEntry;
115
116
  switch (UARTState)
117
  {
118
    case 0x00:        //buffer telegramID
119
      UARTTelegrammID = receivedByte;
120
      UARTState++;
121
      break;
122
123
    case 0x01:        //get command byte
124
      UARTCommand =  receivedByte; // buffer actual command
125
      if((UARTCommand > 0) && (UARTCommand <=4))
126
        UARTState = (UARTCommand<<4);
127
      else
128
        UARTState =0;
129
      break;
130
      
131
    case 0x10:        //get target address low byte
132
    case 0x20:        //get target address low byte
133
      UARTTargetAddress = (uint8_t*) &receivedByte;
134
      UARTState++;
135
      break;
136
137
    case 0x11:        //get target address high byte
138
    case 0x21:        //get target address high byte
139
      UARTTargetAddress+= (int)receivedByte * 256;
140
      UARTState++;      
141
      break;
142
143
    case 0x12:        //get length low byte
144
    case 0x22:        //get length low byte
145
    case 0x31:        //get length low byte
146
    case 0x41:        //get length low byte
147
      UARTDataLength = receivedByte;
148
      UARTState++;
149
      break;
150
151
    case 0x13:        //get length high byte
152
      UARTDataLength += (int)receivedByte * 256;
153
      UARTState = 0x14;
154
      break;
155
156
157
    case 0x14:        //set data to RAM, decrement length.
158
      *UARTTargetAddress = receivedByte;
159
      UARTTargetAddress++;
160
161
      if (0 != UARTDataLength)
162
        UARTDataLength--;
163
      else
164
      {
165
        // Prepare and start Answer Telegramm
166
        UARTState = 0x15;
167
        TxDSendByte(UARTTelegrammID);
168
      }    
169
      break;
170
171
172
    case 0x23:        //get length high byte, and start ack telegram by sending TelegramID
173
      UARTDataLength+= (int) receivedByte * 256;
174
      // Prepare and start Answer Telegramm
175
      UARTState = 0x24;
176
      TxDSendByte(UARTTelegrammID);
177
      break;
178
179
    
180
    case 0x30:        //get periphrie address
181
    case 0x40:        //get periherie address 
182
      UARTPeripherieID = receivedByte;
183
      UARTState++;
184
      break;
185
186
187
188
    case 0x32:        //get length high byte, check lock state
189
      UARTDataLength+= (int)receivedByte * 256;
190
      UARTState = 0x33;
191
      tableEntry = GetPeripherieTableEntry(UARTPeripherieID);
192
      if (tableEntry < (PeripherieTableEntry*) &PeripherieTableEndAddress)
193
      {
194
        if ((tableEntry->LockByte & PT_LOCK_TWICurrentWrite_Mask) != 0)
195
        {
196
          //Table entry is locked by TWI->Error set in answer telegram
197
          UARTReadWriteDeviceStatus = MSK_RxD_RWDSError;//Signal Error for answer telegram
198
        }
199
        else
200
        {
201
          tableEntry->LockByte |= PT_LOCK_RS232CurrentWrite_Mask;
202
          UARTTargetAddress = (uint8_t*) &tableEntry->Comm_WriteBufferAddress;
203
          UARTReadWriteDeviceStatus=0;//Signal Success for answer telegram
204
        }
205
      }
206
      else
207
      {
208
         // PeripherieID not found->Error set in answer telegram
209
        UARTReadWriteDeviceStatus = MSK_RxD_RWDSError;//Signal Error for answer telegram
210
      }
211
      break;
212
213
214
    case 0x33:        //set data to Peripherie ram if not locked, decrement length.
215
              // If length = 0, set state to 0x34 and start ack telegram by sending TelegramID
216
      if (UARTReadWriteDeviceStatus == 0)
217
      {
218
        // Access granted
219
        *UARTTargetAddress = receivedByte;
220
        UARTTargetAddress++;
221
      }
222
223
224
      UARTDataLength--;
225
      if (0== UARTDataLength)
226
      {
227
        // last byte
228
        UARTState =0x34;
229
        //Unlock table entry and set NewData Flag
230
        tableEntry = GetPeripherieTableEntry(UARTPeripherieID);
231
        tableEntry->LockByte &=  ~PT_LOCK_RS232CurrentWrite_Mask;
232
233
        // Prepare and start Answer Telegramm
234
        TxDSendByte(UARTTelegrammID);
235
      }
236
      break;
237
238
239
240
241
242
    case 0x42:        //get length high byte, and start ack telegram by sending TelegramID
243
              //  !!!!If device is locked, wait for unlock
244
      UARTDataLength+= (int)receivedByte * 256;
245
      UARTState = 0x43;
246
247
      tableEntry = GetPeripherieTableEntry(UARTPeripherieID);
248
      if (tableEntry < (PeripherieTableEntry*) &PeripherieTableEndAddress)
249
      {
250
        tableEntry->LockByte = 100;
251
        sei();
252
        while((tableEntry->LockByte & PT_LOCK_TWICurrentRead_Mask) != 0);
253
        cli();
254
        tableEntry->LockByte |= PT_LOCK_RS232CurrentRead_Mask; // Lock it
255
        UARTTargetAddress = (uint8_t*) &tableEntry->Comm_ReadBufferAddress;
256
        UARTReadWriteDeviceStatus=0;
257
        // Start answer telegram
258
        TxDSendByte(UARTTelegrammID);
259
      }
260
      break;
261
  }
262
}
263
264
265
266
267
268
ISR(USART_TX_vect)
269
{
270
  RefreshRS232TimeOutWatchdog();
271
  PeripherieTableEntry* tableEntry;
272
   
273
  switch(UARTState)
274
  {
275
276
    case 0x15:        //Send writemem ack (0x81)
277
    case 0x24:        //Send readmem ack (0x82)
278
    case 0x34:        //Send writedevice ack (0x83)
279
    case 0x43:        //Send readDevice ack (0x84)
280
      UARTState++;    
281
      TxDSendByte(UARTCommand | 0x80);
282
      break;
283
284
285
    case 0x16:        //Send checksum and terminate transfer by setting state to 0x00 (listen)
286
    case 0x35:        //Send checksum and terminate transfer by setting state to 0x00 (listen)
287
      UARTState = 0x00;    
288
      TxDSendByte(UARTChecksum);
289
      break;
290
291
    case 0x25:        //Send data, dec. length. If length = 0, send checksum and  
292
              //  terminate transfer by setting state to 0x00 (listen)
293
      if (0!= UARTDataLength)
294
      {
295
        UARTDataLength--;
296
        TxDSendByte(*UARTTargetAddress);
297
        UARTTargetAddress++;
298
      }
299
      else
300
      {
301
        UARTState = 0x00;    
302
        TxDSendByte(UARTChecksum);
303
      }
304
      break;
305
306
    case 0x44:        //Send data, dec. length. If length = 0, send checksum and  
307
              //  terminate transfer by setting state to 0x00 (listen)
308
      if (0 == UARTDataLength)
309
      {
310
        //Unlock table
311
        tableEntry = GetPeripherieTableEntry(UARTPeripherieID);
312
      if (tableEntry < (PeripherieTableEntry*) &PeripherieTableEndAddress)
313
        {
314
          tableEntry->LockByte &= ~PT_LOCK_RS232CurrentRead_Mask;
315
        }
316
        UARTState = 0x00;    
317
        TxDSendByte(UARTChecksum);
318
      }
319
      else
320
      {
321
        UARTDataLength--;
322
        TxDSendByte(*UARTTargetAddress);
323
        UARTTargetAddress++;
324
      }
325
      break;
326
  }
327
} 
328
329
330
//***************************************************************************
331
// COMMON
332
//***************************************************************************
333
334
uint8_t MakeChecksumOfByte(uint8_t bt)
335
{
336
  uint8_t rval=0;
337
  for (int i = 0; i < 8; i++)
338
  {
339
    rval += (bt &0x01);  
340
    bt = (bt >> 1);
341
  }
342
  return rval;
343
}
344
345
//***********************************************************************  
346
// INIT
347
//***********************************************************************
348
void UARTTelegramInit()
349
{
350
  UARTState =0;
351
}
352
353
354
355
//***********************************************************************  
356
// RefreshRS232TimeOutWatchdog: 
357
// Called from subroutines in this module.
358
// Signals a running data transfer by initializing a watchdog counter
359
// if watchdog counter (decremented by MainTimer.asm) is timed out, 
360
//  RxD/TxD state machines are switcheing to 1st State
361
//***********************************************************************  
362
void RefreshRS232TimeOutWatchdog()
363
{
364
  UARTTimeOutWatchdog = 15;
365
} 
366
367
368
369
//***********************************************************************  
370
// TestRS232TimeOutWatchdog: 
371
// Called from MainTimerInterrupt: If Counter is timed out, 
372
//  RxD/TxD state machines are switcheing to 1st State 
373
//***********************************************************************  
374
void TestRS232TimeOutWatchdog()
375
{
376
  if (UARTTimeOutWatchdog > 0)
377
  {
378
    UARTTimeOutWatchdog--;
379
    if (0 == UARTTimeOutWatchdog)
380
      UARTTelegramInit();
381
  }
382
}
383
384
385
//****************************************************************************
386
// GetPeripherieTableEntry: Used by WriteDevice/ ReadDevice
387
// returns a pointer to table entry identified by ID in peripherie table
388
// if Pointer > &PeripherieTable + sizeof(PeripherieTable), no appropriate entry was found
389
//****************************************************************************
390
PeripherieTableEntry* GetPeripherieTableEntry(uint8_t ID)
391
{
392
  PeripherieTableEntry* rval = (PeripherieTableEntry*) &PeripherieTable;
393
  for (int i=0; i< 2; i++)
394
  {
395
    if (rval->ID == ID)
396
      return rval;
397
    rval++;
398
  }
399
  return rval;
400
}
401
402
403
404
405
406
407
408
void TxDSendByte(uint8_t sendByte)
409
{
410
  while ((UCSR0A & (1<<UDRE0)) == 0); // wait for UART data register empty flag
411
  UDR0 = sendByte;
412
}
413
414
void UART_Init()
415
{
416
  ///***********
417
  // 9600 Baud
418
  ///***********
419
  UBRR0H=0;
420
  UBRR0L=51;
421
422
  // Set frame format: 8data, 1 Stop bit, no parity
423
  UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
424
425
  //Transmitter/Receiver enabled/interrupt enabled
426
  UCSR0B = (1<<TXCIE0) | (1<<RXCIE0) | (1<<TXEN0) | (1<<RXEN0);  
427
}
Was jetzt noch zum aufhübschen fehlt:
- Vielleicht mal ein paar Konstanten für Baudrate,...
- Ich hab's noch nicht so ganz durchschaut: Bringt es etwas, wenn ich 
aus einer Modulvariable eine statische Variable in der Funktion mache? 
(Bis auf den Scope)
- Das mit der Zusammenfassung der Variablen zur Struktur wollte ich noch 
ausprobieren.


Hmm, wenn ich mir jetzt den zeitlichen Verlauf meiner Code-Sparaktion 
als Kurve weiter interpoliere, müsst ich doch in 4 oder 5 Tagen den 
Speicher restlos von Code befreit haben. Ob das Programm dann wohl noch 
läuft?

von Matthias L. (Gast)


Lesenswert?

>müsst ich doch in 4 oder 5 Tagen den Speicher restlos von Code befreit >haben.

Wenn das so ist/wäre, hättest du durch >5Tage Arbeit jetzt den uC 
eingespart. Also >5Tage Arbeit für (wieviel?) 10Euro oder weniger?

Wenn der Materialpreis des uC natürlich (drastisch) höher als dein 
Gehalt für die Zeit ist, lohnt sich das ja auch ;-)

von Carl D. (jcw2)


Lesenswert?

Falsch gerechnet! Er hat gelernt, wie er auch ohne ASM ans Ziel kommt, 
was sich schon bei wenigen switch/case Optimierung, die der Compiler in 
ms macht, auszahlt.

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


Lesenswert?

Horst S. schrieb:
> 2032!
> Die 2k-Grenze hab' ich geknackt.

Nur Pech für dich, dass es in der Serie keinen kleineren Controller
als einen ATmega48 gibt. :-)

> UARTTelegramV3.c

Bitte lieber als Anhang posten.

> - Vielleicht mal ein paar Konstanten für Baudrate,...
> - Ich hab's noch nicht so ganz durchschaut: Bringt es etwas, wenn ich
> aus einer Modulvariable eine statische Variable in der Funktion mache?
> (Bis auf den Scope)

Nur den Scope, du kannst dir also sicher sein, dass die Daten niemand
von außen manipulieren kann.

von Horst S. (Gast)


Lesenswert?

Matthias L. schrieb:
> Wenn der Materialpreis des uC natürlich (drastisch) höher als dein
> Gehalt für die Zeit ist, lohnt sich das ja auch ;-)
Sorry, wenn ich das rechne, bekomme ich eine Nulldivision. Für's Proggen 
zahl ich mir nix.

Jörg W. schrieb:
> Bitte lieber als Anhang posten.
Jörg W. schrieb:
> Nur den Scope, du kannst dir also sicher sein, dass die Daten niemand
> von außen manipulieren kann.

Werd's mir merken.

von avion23 (Gast)


Lesenswert?

@Horst
welche Compileroptionen verwendest du?
Bei Projekten mit vielen Dateien hilft "-Os -flto -fuse-linker-plugin" 
viel. Das muss in die CFLAGS und LDFLAGS. Ist erst ab gcc-4.9 wirklich 
sinnvoll.

von Karl Käfer (Gast)


Lesenswert?

Hallo Moby,

Moby schrieb:
> Für Dich steht da allerdings auch noch eine Aufgabe an:
> Dem SerialComInstruments wirklich Paroli zu bieten ;-)

Lesen lernen: das hab' ich schon.

Liebe Grüße,
Karl

von Moby (Gast)


Lesenswert?

Karl Käfer schrieb:
> Lesen lernen: das hab' ich schon.

Verstehen lernen: Simpel geht anders.
Aber ich weiß ja, das kannst Du nicht ;-)

von Falk B. (falk)


Lesenswert?

Was wäre die Welt ohne Religionskriege . . . ?

ASM akubar!

: Bearbeitet durch User
von Karl Käfer (Gast)


Lesenswert?

Lothar M. schrieb:
> Horst S. schrieb:
>> Warum benötige ich im Assembler-Projekt "nur" 2910 Bytes, in C aber
>> "satte" 3278 Bytes?
> Dieser klitzekleine(!) Mehrpreis ist das, was du dafür bezahlst, dass du
> dein Programm auch in 1 Jahr noch verstehst, erweitern und warten
> kannst.

Äh, Lothar (fast hätte ich Löthar geschrieben, das hätte aber wohl eher 
in "Platinen" gepaßt ;-)), wir sind hier schon weiter. Mit ein paar 
wenigen Handgriffen ist das C-Kompilat mittlerweise über 13% kleiner als 
der von Horst gepostete Assembler-Code, und Horst hat in dankenswerter 
Offenheit eingestanden, daß er selbst wohl nie auf die Optimierungen 
gekommen wäre, die der C-Compiler vorgenommen hat. Deshalb sind Mobys 
"Beiträge" diesmal noch lächerlicher und absurder als sonst. ;-)

Liebe Grüße,
Karl

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

avion23 schrieb:
> Bei Projekten mit vielen Dateien hilft "-Os -flto -fuse-linker-plugin"
> viel. Das muss in die CFLAGS und LDFLAGS. Ist erst ab gcc-4.9 wirklich
> sinnvoll.

"-Os -flto" läuft auch schon in 4.7.2 sehr gut und spart jede Menge ein.

von Peter D. (peda)


Lesenswert?

C hat den Charme, man kann sich voll auf den Algorithmus konzentrieren 
und muß sich nicht durch LD,ST,PUSH,POP und weiteren Ballast unnötig 
ablenken lassen.

Ich kenn das auch noch aus meiner Assemblerzeit, man war heilfroh, 
überhaupt eine funktionierende Lösung gefunden zu haben und hatte wenig 
Lust daran noch weiter zu feilen. Und man dachte, die CPU ackert zu 99%, 
kann also nichts anderes mehr machen.
Aber später unter C nen anderen Algorithmus probiert und schwups waren 
es nur noch 10% Auslastung. Und dann überlegt man, was mache ich bloß 
für andere Tasks mit hinein, daß die CPU wieder gut zu tun hat?

von Karl Käfer (Gast)


Lesenswert?

Hallo Moby,

Moby schrieb:
> Karl Käfer schrieb:
>> Lesen lernen: das hab' ich schon.
>
> Verstehen lernen: Simpel geht anders.

lol Für Könner ist das trivial. Kinder, Hausfrauen und Vorstände 
können das natürlich nicht verstehen.

> Aber ich weiß ja, das kannst Du nicht ;-)

Solange es reicht, um Dich zu überfordern, ... :-)

Liebe Grüße,
Karl

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


Lesenswert?

Karl Käfer schrieb:
>> Aber ich weiß ja, das kannst Du nicht ;-)
>
> Solange es reicht, um Dich zu überfordern, ... :-)

Könntet ihr diese Art von Plänkeleien bitte auf private Emails
verlagern?  Danke.

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Ich verstehe das ganze Geschreibe hier wieder einmal nicht so ganz. Es 
geht wieder lediglich um diese Nerd typischen Kompetenz- und 
Selbstdarstellungsspielchen . Jedem der halbwegs was vom Programmieren 
versteht und mal einen Schritt zurück tritt und einen objektiven Blick 
auf das ganze wirft, wird anerkennen müssen das natürlich Assembler 
wenn's von einem programmiert wird der es kann den kompaktesten und 
performensten  Code erzeugen wird. Im Falle eines idealen Compilers -den 
gibt es aber nicht- ist der Maschinencode gleich schnell und gleich 
groß, aber niemals größer oder langsamer als der Compilercode. Nicht 
einmal theoretisch ist das möglich. Klar das man in der Realität 
komplexe Anwendungen nicht zur Gänze in Assembler schreiben wird, es sei 
man hat zu viel Zeit oder ist Masochist. Meine persönliche Strategie mit 
der ich bisher immer gut gefahren bin bezüglich Performance und Codesize 
ist es C/C++ mit Assembler zu kombinieren. So habe ich im Laufe der Zeit 
viele Funktionen aus der Standard Lib des GCC durch eigene, in Assembler 
programmierte ersetzt. ISR's oder Funktionen zur direkten 
HW-kommunikation mit Peripheriebausteinen werden ebenfalls in Ass 
geschrieben. Jegliche Ablaufsteuerung geht in der Hochsprache auf. Für 
mich ist es dass beste Konzept und erleichtert zudem in den meist 
kritischen Bereichen des Programms das Debuggen ungemein. Ich werde dies 
auch so weiter machen. Selbst nach dem umstieg auf IAR gibt es 
Optimierungsmöglichkeiten an der Arbeit des Compilers.

von Dumdi D. (dumdidum)


Lesenswert?

Thomas H. schrieb:
> Jedem der halbwegs was vom Programmieren
> versteht und mal einen Schritt zurück tritt und einen objektiven Blick
> auf das ganze wirft, wird anerkennen müssen das natürlich Assembler
> wenn's von einem programmiert wird der es kann den kompaktesten und
> performensten  Code erzeugen wird.

Das habe ich auch mal gedacht, würde es aber inzwischen bestreiten. 
Außer der Programmierer ist wirklich bereit unwartbaren Code zu 
schreiben. Dazu sollte ein ernsthafter ASM-Programmierer aber nicht 
bereit sein. Und selbst wenn behaupte ich auch mal gibt es nicht so 
viele Programmierer die mit einem modernen Compiler mithalten können 
(vielleicht gibt es sogar keinen?)

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Dumdi D. schrieb:
> Das habe ich auch mal gedacht, würde es aber inzwischen bestreiten.

Meine Betrachtung war technisch theoretisch. Daran gibts nichts zu 
bestreiten. Ein Compiler ordnet und kombiniert letzten Endes 
Assemblermakros. Die mal von einem Assemblerprogrammierer erstellt 
wurden. Er kann also niemals kleinern Code ausspucken als ein 
Assembler-Programmierer. Das keiner der noch alle Latten im Zaun hat 
komplexe Programme zur Gänze händisch ohne das Hilfsmittel Compiler in 
Assembler schreibt habe ich auch mehr als deutlich zum Ausdruck 
gebracht.

von Sebastian V. (sebi_s)


Lesenswert?

Thomas H. schrieb:
> Er kann also niemals kleinern Code ausspucken als ein
> Assembler-Programmierer.

Sollte man etwas anders formulieren: Er kann also niemals kleinern Code 
ausspucken als die weltbesten Assembler-Programmierer.

Bereiche in denen ASM die Nase vorn hat sind meiner Meinung nach bei 
Instructions für die es in C so kein Ersatz gibt. Zum Beispiel Add with 
Carry. In C kann man zwar auch rauskriegen ob eine Addition ein Carry 
produziert und dann später auf die höherwertigen Bytes draufaddieren. 
Ich habe es ehrlich gesagt noch nicht ausprobiert aber mich würde es 
wundern wenn der Compiler das durchschaut und merkt, dass das ganze Zeug 
eigentlich nur eine Instruction ist. Andere Beispiele sind 
Multiplikationen bei denen man aus zwei n-Bit ints ein 2n-Bit Ergebnis 
kriegt und Divisionen wo man den Rest auch gleich dazu kriegt. Für sowas 
gibts immerhin Intrinsics die ich immer dann benutze wenns richtig 
schnell werden muss (nicht AVR bezogen, sondern auf dem PC). Die 
Autovectorizer von Compilern funktionieren auch nicht wirklich 
zufriedenstellend. Da kann man auch besser direkt die SIMD Intrinsics 
hinschreiben die man braucht.

von (prx) A. K. (prx)


Lesenswert?

Thomas H. schrieb:
> Er kann also niemals kleinern Code ausspucken als ein
> Assembler-Programmierer.

Das ist natürlich richtig. Aber es gibt Code, der sich mit vertretbarem 
Aufwand nur automatisch erzeugen lässt.

Ich hatte oben einen binären Suchbaum aus Vergleichen erwähnt, als 
Implementierung von switch. Sinngemässer als rekursiver Generator:
1
    vergleiche X mit A
2
    goto L1 wenn grösser
3
    goto case(A) wenn gleich
4
    betrachte auf die gleiche Weise alle Fälle von X < A 
5
L1: betrachte auf die gleiche Weise alle Fälle von X > A

Nun ist so ein Code zwar länger als der kürzestmögliche, passt also 
nicht exakt zum Thread, aber er ist bei zufällig verteilten switch-Daten 
der schnellste Code für eine nichttriviale Anzahl Fälle, in denen eine 
Sprungtabelle nicht einsetzbar ist.

Für einen Assembler-Programmierer ist das ein mittlerer Alptraum, denn 
dazu müssen die Werte sortiert werden und ein Wert aus der Mitte des 
jeweiligen Intervalls rausgepickt werden. Das ist hässlich viel Arbeit 
und die fällt mit jeder Änderung der zu unterscheidenden Fälle 
vollständig neu an.

Wenn man dann noch die Kosten von Sprungbefehlen und Sprungvorhersage 
einfliessen lassen muss, um bestimmte Arten von Sprüngen zu bevorzugen, 
dann ist die schon die Entscheidung arg schwierig, ob dieses Verfahren 
sinnvoll ist oder nicht.

Addiere dann noch Profiling hinzu, also die Optimierung anhand von 
Testläufen mit daraus resultierender realer Datenverteilung, und aus dem 
mittleren Alptraum wird ein schwerer.

Es mag Makroassembler geben, mit denen dieser rekursive Ansatz eines 
Vergleichsbaums prinzipiell implementierbar ist, aber mit klassischer 
Assembler-Programmierung hat das dann nur noch wenig zu tun.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Ein weiteres Beispiel für Code, der einem Assembler-Programmierer 
deutlich Kopfzerbrechen bereitet, ist Optimierung der Abhängigkeiten bei 
Prozessoren mit ausgeprägtem Pipelining. Also wenn man drauf achten 
sollte, dass je nach Art der Operation eine vom Ergebnis abhängige 
Folgeoperation eine Mindestanzahl von Takten entfernt sein sollte.

Das ist sowieso schon nicht trivial und wird dadurch nicht besser, dass 
jede neue Generation der Implementierung des Befehlssatzes neue Regeln 
für eine solche und ähnliche Optimierung bringt. Da kann der gleiche 
Code vorher wunderbar effizient sein, nur um dann aufgrund einer 
bestimmten Eigenschaft der Implementierung des Cores bös auf die Nase zu 
fallen (z.B. INC/DEC Befehle beim Pentium 4 gegenüber Pentium III).

Mit einem Compiler braucht man den Code bloss für den neuen Core neu 
übersetzen.

Das ist zwar bei heutigen vollintegrierten Mikrocontrollern à la Cortex 
Mx noch kaum relevant, aber warten wir mal ein paar Jährchen...

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

Thomas H. schrieb:
> Er kann also niemals kleinern Code ausspucken als ein
> Assembler-Programmierer.

Das ist falsch!
 Richtig wäre "als der ideale Code". Aber dazu braucht man für 
nichttriviale Probleme den einen allerbesten Programmierer. Die Frage 
ist eher, wieviel Prozent der ASM-Programmierer bekommen das besser hin, 
als der Compiler, und in einem konkreten Fall, ist man selbst unter 
diesen. Besonders in zweiten Punkt kann man sich massiv verschätzen.
 Nichts spricht natürlich dagegen, die ISR, die nur ein GPOIR0-Bit 
setzen soll, in (Inline-)Assembler hinzuschreiben. Wenn man sicher ist, 
daß man da nichts mehr dran bauen will/muß.

von (prx) A. K. (prx)


Lesenswert?

Carl D. schrieb:
>> Er kann also niemals kleinern Code ausspucken als ein
>> Assembler-Programmierer.
>
> Das ist falsch!

Was ein Compiler erzeugen kann, das kann rein theoretisch betrachtet 
auch ein Assembler-Programmierer erzeugen. Dem Prinzip nach.

Nur kann es sein, dass dafür der frisch von der Ausbildung weg 
eingestelle Assembler-Programmierer vor Beendigung seiner Arbeit in 
Rente geht. ;-)

Soll heissen: Was theoretisch zutrifft kann praktisch falsch sein, weil 
nicht realistisch machbar.

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

Und wir wollten ja mit dem Code fertig sein, bevor Atmel die 
AVR-Vertigung einstellt, oder?  ;-)

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

A. K. schrieb:
> Das ist natürlich richtig. Aber es gibt Code, der sich mit vertretbarem
> Aufwand nur automatisch erzeugen lässt.

Na immerhin gibt es zumindest einen der es verstanden hat.

Wenn ich theoretisch Assembler mit C oder einer anderen Hochsprache 
vergleiche, dann habe ich dabei keinen komplexen Algorithmus im Kopf 
oder gar eine Komplexe Applikation, sondern ein einfaches Codesegment. 
Das reicht mir aus um eine Aussage über den Vergleich Assembler vs 
Compiler machen zu können. Denn  komplexes Programm ist nichts anderes 
als eine Aneinanderreihung einfacher codesegmente und letzen Endes 
einfacher Instruktionen . Der Compiler macht nichts anderes als den 
komplexen Code in einfache Teilaufgaben zu zerlegen. Um die Aussage zu 
tätigen das dies theoretisch von einem Assemblerprogrammierer mit 
gleichem oder im Falle aller real existierenden Compiler besser erledigt 
werden könnte reicht der Vergleich einer so simplen Codesequenz. Weder 
habe ich eine Aussage über die Zeit die der Programmierer dazu hat 
gemacht noch über die Anzahl der Assemblerprogrammierer auf die Aufgabe 
verteilt werden könnte. Auch habe ich klar -und ich sage es zum zweiten 
male- zum Ausdruck gebracht das man in der Realität keine Komplexen 
Aufgaben nur in Assembler lösen wird.

Carl D. schrieb:
> Nichts spricht natürlich dagegen, die ISR, die nur ein GPOIR0-Bit
> setzen soll, in (Inline-)Assembler hinzuschreiben. Wenn man sicher ist,
> daß man da nichts mehr dran bauen will/muß.


Ich habe nach 36J Assemblerprogramierung schon die eine oder andere ISR 
erstellt, die ein wenig mehr macht als lediglich einen Portbit  zu 
bedienen. Wer allerdings float Berechnungen oder anderen Aufgaben in 
einer ISR erledigt von denen er denkt das ginge nur in einer 
Hochsprache, der  hat eh etwas essentielles nicht verstanden. Auch bin 
ich in der Lage später noch etwas an meinem Code zu modifizieren. Von 
inline Assembler wie er in GCC zelebriert wird lasse ich prinzipiell die 
Finger.

von Moby (Gast)


Lesenswert?

Carl D. schrieb:
> Und wir wollten ja mit dem Code fertig sein, bevor Atmel die
> AVR-Vertigung einstellt, oder?  ;-)

Ob Du weißt, welche Codemassen in Asm für AVR schon existieren? Warum 
wohl? Und daß die 8-Bitter jemals obsolet werden wird wohl keiner hier 
mehr erleben ;-)

A. K. schrieb:
> Was ein Compiler erzeugen kann, das kann rein theoretisch betrachtet
> auch ein Assembler-Programmierer erzeugen.

Genau das will er aber gar nicht.
Sondern es selbst in der Hand haben.
Mit all den vielen Vorteilen, die damit einhergehen.

Was den erhöhten Zeitbedarf anbetrifft machen sich viele hier falsche 
Vorstellungen.
Der erste Trick ist, bei einer vielseitigen, 
/hinreichend/leistungsstarken, typenreichen Architektur zu bleiben. Die 
man dann gut kennt. Der zweite, sich universell einsetzbare Programm- & 
Peripherie-Codebausteine und eine grundlegende immergleiche 
Programmstruktur zuzulegen. Dann ist der Rest nicht viel mehr als 
sinnvolle Verknüpfung.
Sicher gibt es programmierer- und projektabhängig irgendwo eine 
sinnvolle Grenze, die höhere Sprachen erforderlich macht. Die sehe ich 
bei den kleinen AVR Maschinen aber weit weit weg.

Durch Assembler beim assemblerfreundlichen AVR bleiben können- so wird 
ein Schuh draus. Hochsprachenverwendung ist einer der wichtigsten 
Treiber für permanente Controller-, Architektur- und Programmiermittel- 
Wechsel.

von Moby (Gast)


Lesenswert?

Thomas H. schrieb:
> Ich habe nach 36J Assemblerprogramierung

Kompliment.
Das möchte ich auch noch erreichen.
Die Hälfte hab ich schon ;-)

von scelumbro (Gast)


Lesenswert?

Moby schrieb:
> Genau das will er aber gar nicht.
> Sondern es selbst in der Hand haben.

Du möchtest vielleicht alles selbst in der Hand haben. Das ist okay, 
genauso wie Leute nur an einem Esstisch sitzen wollen, den sie höchst 
persönlich mit dem Taschenmesser aus einem Baumstamm geschnitzt haben.
Professionelle Entwickler programmieren Lösungsorientiert. Da steht dann 
sowohl Performance als auch Codegröße hinter effizienter, fehlerfreier 
und langfristig wartbarer Entwicklung weit zurück.

Moby schrieb:
> Der zweite, sich universell einsetzbare Programm- &
> Peripherie-Codebausteine und eine grundlegende immergleiche
> Programmstruktur zuzulegen. Dann ist der Rest nicht viel mehr als
> sinnvolle Verknüpfung.

Oder man nimmt sich einen Compiler mit Standard Bibliotheken, der genau 
das tut (Programm - und Codebausteine kombinieren und zu optimieren), 
nur auf Basis der Erfahrung tausender Hochkarätiger Compilerentwickler.
Im übrigen widerspricht das deiner Forderung danach alles perfekt zu 
optimieren. Das sah man dann deinem Tastenentprellen-Blinky Beispiel das 
du vor einiger Zeit gepostet hast. Obwohl noch massig Register frei 
waren, hat dein Programm völlig unnötig RAM genutzt. Eben weil du statt 
komplett handoptimierten Assembler, fertige - selbstgeschriebene -  Bibs 
verwendet hast.

von Ingo (Gast)


Lesenswert?

> Kompliment.
> Das möchte ich auch noch erreichen.
> Die Hälfte hab ich schon ;-)
ich denke ich mach mit dem GCC und meinen 6 Jahren C kleineren und 
wartbareren Code als Du mit deinen 18 Jahren ASM ;)

#MalWiederHolzAuflegen

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

scelumbro schrieb:
> auf Basis der Erfahrung tausender Hochkarätiger Compilerentwickler

Danke für die Blumen

von Moby (Gast)


Lesenswert?

scelumbro schrieb:
> Professionelle Entwickler programmieren Lösungsorientiert.

Ach?
Ich sollte meine vielen funktionierenden Ergebnisse nochmal danach 
bewerten, ob es sich wirklich um Lösungen handelt ;-)

> nur auf Basis der Erfahrung tausender Hochkarätiger Compilerentwickler.

Die ist ja toll und die braucht es sicherlich auch- nur nicht bei den 
simplen AVRs.

> Im übrigen widerspricht das deiner Forderung danach alles perfekt zu
> optimieren.

Von Perfektion rede selbst ich nicht.

> Obwohl noch massig Register frei
> waren, hat dein Programm völlig unnötig RAM genutzt.

Ob dahinter auch eine Absicht gesteckt haben könnte? Das war nämlich 
eines von vielen kombinierbaren Modulen. Wenn da jedes eigene Register 
beanspruchen würde... Hilfe! Nein, da hast Du nur das System nicht 
verstanden...
Sich allein auf Register zu beschränken kann man bei ganz kleinen Sachen 
machen bei denen sich absehen lässt, daß sie nicht mehr erweitert 
werden.

von Moby (Gast)


Lesenswert?

Ingo schrieb:
> wartbareren Code

Bildet Euch doch darauf nicht zuviel ein.
Alles eine Frage des Systems, der Doku und eben der Programmiersprache: 
Asm als Klartext ist selbsterklärend.

von Karl Käfer (Gast)


Lesenswert?

Hallo Thomas,

Thomas H. schrieb:
> Jedem der halbwegs was vom Programmieren
> versteht und mal einen Schritt zurück tritt und einen objektiven Blick
> auf das ganze wirft, wird anerkennen müssen das natürlich Assembler
> wenn's von einem programmiert wird der es kann den kompaktesten und
> performensten  Code erzeugen wird. Im Falle eines idealen Compilers -den
> gibt es aber nicht- ist der Maschinencode gleich schnell und gleich
> groß, aber niemals größer oder langsamer als der Compilercode.

Dein Ansatz geht davon aus, daß es perfekte Assembler-Programmierer 
gibt, solche also, die perfekten Code schreiben können. Das gibt es 
tatsächlich aber nur bei den allertrivialsten Programmen.

Mit zunehmender Funktionalität, mithin Größe des Codes, wird die Sache 
aber immer schwieriger. Irgendwann sind die Grenzen des menschlichen 
Fassungsvermögens erreicht, auch des besten Programmierers aller Zeiten.

Spätestens da schlägt dann die Stunde der Compiler, die zwar weniger 
kreativ sein mögen als ein menschlicher Programmierer und Optimierer, 
die dafür aber ein schier unerschöpfliches Fassungsvermögen haben.

Der Punkt, auf den ich hinauswill, ist: im realen Leben gibt es leider 
keinen perfekten Programmierer, und von daher ist die Annahme, daß ein 
perfekter Programmierer den perfekten Code schreiben könnte, letztlich 
schlicht unrealistisch. Wenn Du von dieser Prämisse ausgehen wolltest, 
müßtest Du einen perfekten Programmierer mit einem perfekten Compiler 
vergleichen, und am Ende würden beide genau denselben perfekten Code 
hervorbringen.

Wenn man also etwas vom Programmieren versteht, einen Schitt zurück 
tritt und einen objektiven Blick auf das Ganze werfen will, dann kommt 
man nicht an der Erkenntnis vorbei, daß es so etwas wie perfekte 
Programmierer oder perfekte Compiler in der realen Welt nicht gibt. Das 
bedeutet, daß wir uns mit unseren eigenen Unzulänglichkeiten als 
Menschen und auch mit jenen der Maschinen arrangieren müssen, und daß es 
nunmal Tätigkeiten gibt, die eine Maschine besser, schneller und 
fehlerärmer erledigen kann als wir. Sonst würden wir ja gar keine 
Maschinen bauen und benutzen, oder?

Daher gilt für Compiler, daß sie auch bei nichttrivialen Programmen 
immer noch alle Variablen und Verzweigungen quasi "im Kopf" behalten 
können, wo unser Verstand schon längst mit einem Pufferüberlauf 
ausgestiegen ist, so daß ein Compiler mit zunehmender Komplexität des 
Programms immer bessere Ergebnisse erzielt als ein noch so guter 
Programmierer.

Deswegen haben die Hochsprachen heute längst gewonnen, überall. Bei den 
Atmel AVRs wurde sogar das Hardware-Design eigens für die Benutzung mit 
Hochsprachen ausgelegt, so daß es etwas anachronistisch und ewiggestrig 
erscheint, ausgerechnet diese Mikrocontroller vollständig mit Assembler 
programmieren zu wollen. Die Daseinsberechtigung von Assembler auf AVRs 
erschöpft sich daher heute in nur zwei Anwendungsfällen: für besonders 
zeitkritische Programmteile, die mit in C eingebettetem Assembler-Code 
eine bessere Kontrolle über das Timing ermöglichen, sowie zweitens als 
Zwischenschritt der Kompilierung einer Hochsprache.

Liebe Grüße,
Karl

PS: Lieber Jörg, ich werde zu gerne darauf verzichten, Nickeligkeiten 
mit diesem "Herrn" auszutauschen, sowohl hier, als auch per E-Mail. Ich 
würde mich aber freuen, wenn ich nicht ständig grundlos von ihm 
provoziert und beim ersten Gegenhalten meinerseits zurechtgewiesen 
würde. Immerhin gibt es da ja so etwas wie Ursache und Wirkung. Nix für 
ungut, danke.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Thomas H. schrieb:
> Jedem der halbwegs was vom Programmieren versteht und mal
> einen Schritt zurück tritt und einen objektiven Blick auf das
> ganze wirft, wird anerkennen müssen das natürlich Assembler
> wenn's von einem programmiert wird der es kann den kompaktesten
> und performensten  Code erzeugen wird.

Nicht selten ist das dann so wie mit physikalischen Theorien; zu einer 
solchen meinte Hawking mal:

"That's nice.  Too bad it's wrong".

Auf kiki Architekturen wir AVR ist es noch mehr oder weniger trivial, 
effizienten und korrekten Assembler zu schreiben.

Aber auf einer multiskalaren Maschine mit 20-schrittigen Pipelines, 
Caches, Prefetch-Buffers, oder netten "Features" wie exposed Pipeline, 
Out-of-Order Execution etc.

Selbt ohne all diese Nettigkeiten ist die beste Codesequenz nicht 
naheliegend.  Instruktives Beispiel:  Laden eines Immediate auf ARM: 
Für den Fall, dass die Konstante besser direkt geladen wird (anstatt sie 
in einem const-Pool abzulegen u vo ndort zu lagen) verwenden GCC über 
1000 Zeilen seiner Quellen.  Ich würd mal sagen, dass ein 
Asm-Programmiere nicht ad hoc die beste Sequenz findet.

Übel wird es auch, wenn neue Konstanten zum const-Pool hinzugefügt 
werden und Sprungbefehle eingefügt werden müssen um den Pool zu 
umspringen.  In Asm tut sich das doch niemand an, oder?

von unbelegt und falsch (Gast)


Lesenswert?

>Moby schrieb:   Asm als Klartext ist selbsterklärend.

Schon mal in das Programm eines anderen Programmieres gelinst?
Klingt nicht so.

von Moby (Gast)


Lesenswert?

unbelegt und falsch schrieb:
> Moby schrieb:   Asm als Klartext ist selbsterklärend.
>
> Schon mal in das Programm eines anderen Programmieres gelinst?
> Klingt nicht so.

Ja muß man das nun auch noch erklären?
Steht mit Asm nicht etwa genau das auf dem Papier was passiert? Eine 
kurzer Kommentar zur Funktion noch und gut ist!
Zum Verständnis gehört im Falle des Falles aber immer das Datenblatt. 
Was auch C-Programmierern keinesfalls schadet!

von scelumbro (Gast)


Lesenswert?

Moby schrieb:
> scelumbro schrieb:
>> Obwohl noch massig Register frei
>> waren, hat dein Programm völlig unnötig RAM genutzt.
>
> Ob dahinter auch eine Absicht gesteckt haben könnte? Das war nämlich
> eines von vielen kombinierbaren Modulen. Wenn da jedes eigene Register
> beanspruchen würde... Hilfe! Nein, da hast Du nur das System nicht
> verstanden...
> Sich allein auf Register zu beschränken kann man bei ganz kleinen Sachen
> machen bei denen sich absehen lässt, daß sie nicht mehr erweitert
> werden.

Ich habe dein System sehr wohl verstanden. Dein genialer selbst 
Entwickelter Ansatz ist der Hochsprachenwelt seit Jahrzehnten bekannt. 
Es kommt ja auch kein C Programmierer auf die Idee, printf & Co selbst 
zu implementieren.
Aber einerseits redest du andauernd vom Compiler bloat, andererseits 
erzeugst du - auf dieses konkrete Projekt bezogen - ganz eindeutig 
unnötigen Code Bloat mit der Verwendung eines handgebauten aber nicht 
projektoptimierten Moduls. Ist Compiler generierter Bloat schlechter als 
handgenerierter Bloat? Schau dir auch bitte mal die Geschichte der C 
Compiler an, vielleicht wird dir dann klar das du ein uraltes Rad  neu 
erfindest - und dann auch noch viereckig.

von Moby (Gast)


Lesenswert?

Johann L. schrieb:
> Auf kiki Architekturen wir AVR ist es noch mehr oder weniger trivial,
> effizienten und korrekten Assembler zu schreiben.

Na also. Genauso ist es.
Und das Schönste: Mit kiki läßt sich immer noch jede Menge anstellen. 
Und zwar kiki im Vergleich zu hochgezüchteten C auf ARM Lösungen...

von Moby (Gast)


Lesenswert?

scelumbro schrieb:
> Moby schrieb:
> scelumbro schrieb:
> ganz eindeutig
> unnötigen Code Bloat mit der Verwendung eines handgebauten aber nicht
> projektoptimierten Moduls.

Na mein Eindruck ist ganz eindeutig,daß Du das System eben nicht 
verstanden hast und auch nicht vorhast, es zu verstehen.

> vielleicht wird dir dann klar das du ein uraltes Rad  neu
> erfindest - und dann auch noch viereckig.

Auf das System als solches erhebe ich weißgott keine Urheberansprüche.
Ich weiß aber, daß es auf diese Weise recht schnell rund läuft und eben 
nicht viereckig ;-)

von scelumbro (Gast)


Lesenswert?

Moby schrieb:
> Na mein Eindruck ist ganz eindeutig,daß Du das System eben nicht
> verstanden hast und auch nicht vorhast, es zu verstehen.

Erleuchte mich und die anderen Jünger des großen Compilers doch bitte.

von Moby (Gast)


Lesenswert?

scelumbro schrieb:
> Erleuchte mich und die anderen Jünger des großen Compilers doch bitte.

Lies einfach noch mal meine Erklärung weiter oben warum ich im konkreten 
Fall das heilige RAM anzapfe.

Und meinst Du wirklich, ich hätte den Anspruch zu "erleuchten" ?
Es kann ja sein daß Simplizität und Effizienz von Asm nicht in die 
heutige Zeit passt wo es heisst: Komplex ist cool und macht Eindruck.
Trotzdem gebe ich meine Erfahrungen weiter, und die stehen unter der 
Maxime: Keep it simple!

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Karl Käfer schrieb:
> Daher gilt für Compiler, daß sie auch bei nichttrivialen Programmen
> immer noch alle Variablen und Verzweigungen quasi "im Kopf" behalten
> können, wo unser Verstand schon längst mit einem Pufferüberlauf
> ausgestiegen ist, so daß ein Compiler mit zunehmender Komplexität des
> Programms immer bessere Ergebnisse erzielt als ein noch so guter
> Programmierer.


Deshalb schrieb ich:

Thomas H. schrieb:
> Wenn ich theoretisch Assembler mit C oder einer anderen Hochsprache
> vergleiche, dann habe ich dabei keinen komplexen Algorithmus im Kopf
> oder gar eine Komplexe Applikation, sondern ein einfaches Codesegment.
> Das reicht mir aus um eine Aussage über den Vergleich Assembler vs
> Compiler machen zu können. Denn  komplexes Programm ist nichts anderes
> als eine Aneinanderreihung einfacher codesegmente und letzen Endes
> einfacher Instruktionen . Der Compiler macht nichts anderes als den
> komplexen Code in einfache Teilaufgaben zu zerlegen. Um die Aussage zu
> tätigen das dies theoretisch von einem Assemblerprogrammierer mit
> gleichem oder im Falle aller real existierenden Compiler besser erledigt
> werden könnte reicht der Vergleich einer so simplen Codesequenz. Weder
> habe ich eine Aussage über die Zeit die der Programmierer dazu hat
> gemacht noch über die Anzahl der Assemblerprogrammierer auf die Aufgabe
> verteilt werden könnte. Auch habe ich klar -und ich sage es zum zweiten
> male- zum Ausdruck gebracht das man in der Realität keine Komplexen
> Aufgaben nur in Assembler lösen wird.

Karl Käfer schrieb:
> so daß es etwas anachronistisch und ewiggestrig
> erscheint, ausgerechnet diese Mikrocontroller vollständig mit Assembler
> programmieren zu wollen.

Exact was ich geschrieben habe.

von Bastler (Gast)


Lesenswert?

Wenn 18 Jahre Assembler zu diesem Ergebnis führen:
Beitrag "Re: Analoger Sensor (LM355) mit Operationsverstärker (+AVR Asm-Code)"
dann hätte man die Zeit besser in was anderes investiert.
(andere Beispiele für Code von unserem Freund sind leider nicht zu 
finden)

von Moby (Gast)


Lesenswert?

Bastler schrieb:
> Wenn 18 Jahre Assembler zu diesem Ergebnis führen:
> Beitrag "Re: Analoger Sensor (LM355) mit Operationsverstärker (+AVR
> Asm-Code)"
> dann hätte man die Zeit besser in was anderes investiert.
> (andere Beispiele für Code von unserem Freund sind leider nicht zu
> finden)

Stell Dir vor, das Ding ist im Einsatz und es macht seine Sache gut.
Kann aber verstehen, wenn es mancher gern komplizierter gelöst hätte ;-)

von scelumbro (Gast)


Lesenswert?

Moby schrieb:
> Bastler schrieb:
>> Wenn 18 Jahre Assembler zu diesem Ergebnis führen:
>> Beitrag "Re: Analoger Sensor (LM355) mit Operationsverstärker (+AVR
>> Asm-Code)"
>> dann hätte man die Zeit besser in was anderes investiert.
>> (andere Beispiele für Code von unserem Freund sind leider nicht zu
>> finden)
>
> Stell Dir vor, das Ding ist im Einsatz und es macht seine Sache gut.
> Kann aber verstehen, wenn es mancher gern komplizierter gelöst hätte ;-)

Eine Lösung dieses Problemchens in einer Hochsprach würde nur für 
jemanden komplizierter Aussehen, der diese Hochsprache nicht verstünde.

von Hmmmm (Gast)


Lesenswert?

Moby schrieb:
> Stell Dir vor, das Ding ist im Einsatz und es macht seine Sache gut.

Die "Sache" ist so ein kleines Problem, wenn du da noch etwas verkehrt 
gemacht hättest, dann stimme ich dem Vorposter 2x zu. So aber auf 
jedenfall einmal.

Du machst deine Rolle als Gruppenkasper noch besser als 
Assemblerprogrammierer ;-) Um Längen sogar.

von Hmmmm (Gast)


Lesenswert?

Als Vorposter meinte ich "Bastler" ......

von Moby (Gast)


Lesenswert?

Hmmmm schrieb:
> Du machst deine Rolle als Gruppenkasper

Hmmmm, ob Du auch was zur Sache beitragen kannst?
Gute Unterhaltung ist aber auch was wert ;-)

von Hmmmm (Gast)


Lesenswert?

Moby schrieb:
> ob Du auch was zur Sache beitragen kannst?

Könnte ich sicher, lohnt aber nicht :-)

von Moby (Gast)


Lesenswert?

Hmmmm schrieb:
> Moby schrieb:
>> ob Du auch was zur Sache beitragen kannst?
>
> Könnte ich sicher, lohnt aber nicht :-)

Das glaub ich Dir ;-)

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


Lesenswert?

Thomas H. schrieb:
> Von inline Assembler wie er in GCC zelebriert wird lasse ich prinzipiell
> die Finger.

GCCs Inline-Assembler ist einsame Spitze.  Wenn du mal eine Krücke
wie den IAR da gesehen hast, bei dem du dich im Inline-Asm bestenfalls
auf globale Variablen verlassen kannst (alles andere könnte sich
bereits in der nächsten Compilerversion ja geändert haben, weil es
letztlich implementation defined ist), dann weißt du, warum die auf
den ersten Blick umständlich und kryptisch anmutende Variante des GCC
wirklich gut ist: sie gestattet es, dort, wo man es tatsächlich mal
braucht, handoptimierten Assemblercode einzuflechten, der auch über
ein paar Generationen des Compilers Bestand haben kann, ohne dabei
dem Compiler bei seinen Optimierungsstrategien im Weg herum zu stehen.

(Bezüglich der „Krücke“: der IAR ist sonst ein wirklich guter Compiler.
Aber an dieser Stelle ist er einfach nur <zensiert>.)

unbelegt und falsch schrieb:
>> Moby schrieb:   Asm als Klartext ist selbsterklärend.
>
> Schon mal in das Programm eines anderen Programmieres gelinst?

Das einzige Schnipsel Code, was wir von ihm hier bislang sehen durften,
führt seine Behauptung doch bereits komplett ad absurdum.  Damit
erübrigt sich jegliche weitere Diskussion.

von Moby (Gast)


Lesenswert?

Jörg W. schrieb:
>>> Moby schrieb:   Asm als Klartext ist selbsterklärend.
>>
>> Schon mal in das Programm eines anderen Programmieres gelinst?
>
> Das einzige Schnipsel Code, was wir von ihm hier bislang sehen durften,
> führt seine Behauptung doch bereits komplett ad absurdum.  Damit
> erübrigt sich jegliche weitere Diskussion.


Was ist an

Moby schrieb:
> Steht mit Asm nicht etwa genau das auf dem Papier was passiert? Eine
> kurzer Kommentar zur Funktion noch und gut ist!
> Zum Verständnis gehört im Falle des Falles aber immer das Datenblatt.
> Was auch C-Programmierern keinesfalls schadet!

absurd?
Absurd ist höchstens Dein Einwand...

von Moby (Gast)


Lesenswert?

Jörg W. schrieb
> Wenn du mal eine Krücke
> wie den IAR da gesehen hast, bei dem du dich im Inline-Asm bestenfalls
> auf globale Variablen verlassen kannst (alles andere könnte sich
> bereits in der nächsten Compilerversion ja geändert haben, weil es
> letztlich implementation defined ist), dann weißt du, warum die auf
> den ersten Blick umständlich und kryptisch anmutende Variante des GCC
> wirklich gut ist: sie gestattet es, dort, wo man es tatsächlich mal
> braucht, handoptimierten Assemblercode einzuflechten, der auch über
> ein paar Generationen des Compilers Bestand haben kann, ohne dabei
> dem Compiler bei seinen Optimierungsstrategien im Weg herum zu stehen.

Probleme gibts...

von (prx) A. K. (prx)


Lesenswert?

Ich finde die Art der Assembler-Integration sehr gut. Sie ist zwar 
gewöhnungsbedürftig, erlaubt aber eine sehr effiziente Integration 
kleiner Assembler-Einsprengsel in C Code. Man muss wirklich nur das 
absolute Minimum in Asm codieren. Das, was anders nicht geht. 
Gleichzeitig behindern diese Sequenzen die Optimierung nicht, weil der 
Compiler die dazu nötige Information erhält.

: Bearbeitet durch User
von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Jörg W. schrieb:
> GCCs Inline-Assembler ist einsame Spitze

Spitze von unterirdisch vieleicht. Ich schreibe meinen Assemblercode 
extern und linke zusammen.

Jörg W. schrieb:
> Wenn du mal eine Krücke
> wie den IAR da gesehen hast, bei dem du dich im Inline-Asm bestenfalls
> auf globale Variablen verlassen kannst

Habe ich und dem stimme ich zu.

Jörg W. schrieb:
> handoptimierten Assemblercode einzuflechten, der auch über
> ein paar Generationen des Compilers Bestand haben kann

ein externenes .s File übersteht das hervorragend. Sowohl beim GCC als 
auch beim IAR.

Jörg W. schrieb:
> Bezüglich der „Krücke“: der IAR ist sonst ein wirklich guter Compiler

Der beste im Moment auf dem Markt.

von (prx) A. K. (prx)


Lesenswert?

Thomas H. schrieb:> Spitze von unterirdisch 
vieleicht. Ich schreibe meinen Assemblercode
> extern und linke zusammen.

Beides ergibt Sinn, je nachdem um was es geht.

Wer einen kompletten Interrupt-Handler in Asm fomulieren will, der ist 
mit einem separaten File besser bedient.

Wer einen einzelnen Befehl oder Sequenzen aus wenigen Befehlen 
integrieren will, wie etwa Semaphor-Befehle oder Spezialbefehle für 
Steuerregister, der ist mit inline-Asm wesentlich effizienter bedient.

In konventionellem Inline-Asm würde man die gesamten Semphor-Funktionen 
von ARM als Asm implementieren. Im GCC Inline-Asm reicht es, die beiden 
relevanten Befehle entsprechend zu definieren. Sie Semaphor-Sequenz kann 
dann normal in C programmiert werden.

: Bearbeitet durch User
von Karl Käfer (Gast)


Lesenswert?

Hallo Thomas,

Thomas H. schrieb:
> Exact was ich geschrieben habe.

Das hatte ich in Deinem ersten Beitrag anders verstanden. Mein Fehlerm 
entschuldige bitte.

Liebe Grüße,
Karl

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


Lesenswert?

Thomas H. schrieb:
> Ich schreibe meinen Assemblercode extern und linke zusammen.

Klar, aber das ist ja nicht das Zielgebiet des Inline-Assemblers.

Dort, wo man so hantieren kann, ist doch die Welt auf diese Weise
völlig in Ordnung, und das ist dann sicherlich der beste Weg.

Der Inline-Assembler des GCC ist dort gut, wo man eine möglichst
nahtlose inline Integration eines Stückchens Assemblercode braucht
(also alles, was man eher nicht als eigene Funktion implementieren
will).  Dann muss ich mich eben nicht auf ein konkretes Register
festlegen (das der Compiler vielleicht an dieser Stelle lieber mit
etwas anderem belegen würde), sondern kann dem Compiler sagen: „ich
brauche hier irgendein Register“ oder „ich brauche hier eines der
Zeigerregister“.

von Horst S. (Gast)


Lesenswert?

avion23 schrieb:
> @Horst
> welche Compileroptionen verwendest du?
> Bei Projekten mit vielen Dateien hilft "-Os -flto -fuse-linker-plugin"
> viel. Das muss in die CFLAGS und LDFLAGS. Ist erst ab gcc-4.9 wirklich
> sinnvoll.

Ich hab hier gcc 4.3.3 (stand zumindest in der html des WInAVR-Pakets). 
Ich muss ehrlich gestehen, ich kann mich nicht mehr erinnern, wann ich 
den mal installiert hatte und ob die Version an mein altes AVRStudio 
(4.10) gebunden war.

Moby schrieb:
> Durch Assembler beim assemblerfreundlichen AVR bleiben können- so wird
> ein Schuh draus. Hochsprachenverwendung ist einer der wichtigsten
> Treiber für permanente Controller-, Architektur- und Programmiermittel-
> Wechsel.

Für mich war der Treiber zum Wechsel des Programmiermittels, dass ich 
endlich auf den Fischen nicht nur Daten hin- und herschieben will, 
sondern vielleicht auch gelegentlich mal etwas RECHNE.
Wenn Du also in Deiner Bastelkiste so was, wie die math.lib (mit den 
trigonometrischen Funktionen) schon seit geraumer Zeit in optimierter 
Performance in asm herumliegen hast - her damit - find ich gut. Die 
gcc-Programmierer küssen Dir sicherlich auch die Füße, wenn Du Sinus und 
ArcSin in weniger als 100us berechnen kannst (dann aber bitte ohne 
Sprungtabelle, also code- UND performanceoptimiert).

von Klaus Peters (Gast)


Lesenswert?

Moby schrieb:
> Und meinst Du wirklich, ich hätte den Anspruch zu "erleuchten" ?
warum tauchst du dann regelmaessig in threads zu hochsprachen auf und 
zwingst deine missionierung auf? obwohl es die leute nervt?

> Es kann ja sein daß Simplizität und Effizienz von Asm nicht in die
> heutige Zeit passt wo es heisst: Komplex ist cool und macht Eindruck.
> Trotzdem gebe ich meine Erfahrungen weiter, und die stehen unter der
> Maxime: Keep it simple!
asm ist nicht simpel und auch nicht effizient. es zwingt dazu, wie ein 
prozessor zu denken statt wie ein mensch. das lenkt vom problem ab, das 
man loesen will. das komplexe sieht man dem fertigen programm sowieso 
nicht an. es waere dumm, etwas unnoetig komplex zu machen, wenn es 
hinterher sowieso keiner bewundert.

von Kaj (Gast)


Lesenswert?

Horst S. schrieb:
> Ich hab hier gcc 4.3.3 (stand zumindest in der html des WInAVR-Pakets).
Besorg dir bitte wenigstens die aktuelle Atmel-Toolchain...
http://www.atmel.com/tools/ATMELAVRTOOLCHAINFORWINDOWS.aspx

von Moby (Gast)


Lesenswert?

Horst S. schrieb:
> Für mich war der Treiber zum Wechsel des Programmiermittels, dass ich
> endlich auf den Fischen nicht nur Daten hin- und herschieben will,
> sondern vielleicht auch gelegentlich mal etwas RECHNE.

Stimmt. Erwischt. In meinen Projekten gibt es meist nur wenige 
aufwendige Berechnungen. Wenn, dann bediene ich mich ausnahmsweise mal 
an fremden Routinen, so wie sie zum Beispiel in den empfehlenswerten 
Asm-Büchern von Manfred Schwabl-Schmidt oder im Netz zu finden sind.
Im Punkt Berechnungen ist man mit Hochsprache zugegebenermaßen bequemer 
unterwegs. Das ist dann aber auch schon der einzige Moment, neidisch 
hinüberzuschielen :-)

von Moby (Gast)


Lesenswert?

Klaus Peters schrieb:
> warum tauchst du dann regelmaessig in threads zu hochsprachen auf und
> zwingst deine missionierung auf? obwohl es die leute nervt?

Aufzwingen? Werd doch nicht albern. Und wer fragt denn was mich nervt? 
Also das kann wirklich kein Kriterium sein. Wenn das Darstellen der 
Vorteile von Asm missionierend wirkt, dann vielleicht wegen der Vorteile 
von Asm ?

> asm ist nicht simpel und auch nicht effizient. es zwingt dazu, wie ein
> prozessor zu denken statt wie ein mensch. das lenkt vom problem ab, das
> man loesen will. das komplexe sieht man dem fertigen programm sowieso
> nicht an. es waere dumm, etwas unnoetig komplex zu machen, wenn es
> hinterher sowieso keiner bewundert.

In diesem Einwand kommt für mich nur mangelnde Erfahrung mit Asm zum 
Ausdruck, sorry.

Das zunächst bequemer scheinende C bringt in der Folge nur mehr und mehr 
künstliche Probleme mit sich, die man ohne nicht hat. C-Threads sind 
voll davon... Ein AVR braucht i.d.R. keine Hochsprache. Asm passt 
perfekt.

von Frank (Gast)


Lesenswert?

So, das Bullshit-Bingo ist ja jetzt schon mehr als voll...

Mit den ganzen Zeichen hier die nichts mit der Sache zu tun haben, hätte 
man glaube ich schon ein Atomkraftwerk programmieren können ;-)

von Frank (Gast)


Lesenswert?

Mein post eingeschlossen.

von TriHexagon (Gast)


Lesenswert?

Moby schrieb:
>> asm ist nicht simpel und auch nicht effizient. es zwingt dazu, wie ein
>> prozessor zu denken statt wie ein mensch. das lenkt vom problem ab, das
>> man loesen will. das komplexe sieht man dem fertigen programm sowieso
>> nicht an. es waere dumm, etwas unnoetig komplex zu machen, wenn es
>> hinterher sowieso keiner bewundert.
>
> In diesem Einwand kommt für mich nur mangelnde Erfahrung mit Asm zum
> Ausdruck, sorry.

Du scheinst noch nie großartig pure Logik implementiert zu haben. Denn 
wenn das Problem eben nicht technischer Art ist, sondern logischer, dann 
ist eine "technische" Sprache (ASM) eben doch hinderlich und trägt nur 
zur Verkomplizierung der Lösung bei. "Wer als Werkzeug nur einen Hammer 
hat, sieht in jedem Problem einen Nagel." :P

Moby schrieb:
> Ein AVR braucht i.d.R. keine Hochsprache. Asm passt
> perfekt.

Nein danke, wenn ich mit einem AVR Dateien auf einer SD Karte lesen und 
schreiben muss (FAT Dateisystem), kann ich gern auf Assembler 
verzichten. Der Umgang mit "komplexeren" Datenstrukturen ist mit 
Assembler ziemlich mühselig.

von Klaus Peters (Gast)


Lesenswert?

Moby schrieb:
> Aufzwingen? Werd doch nicht albern.
merkst du es nicht? sind die anderen die geisterfahrer? echt jetzt?

> Und wer fragt denn was mich
> nervt?
niemand draengt sich dir auf. nur andersrum.

> Also das kann wirklich kein Kriterium sein. Wenn das Darstellen der
> Vorteile von Asm missionierend wirkt, dann vielleicht wegen der
> Vorteile
> von Asm ?
wegen der penetranz, besserwisserei und unbelehrbarkeit, die du an den 
tag legst. viele hier sind lange asm-progger und aus gutem grund zu den 
hochsprachen gegangen.

du ignorierst alle argumente, die dir nicht in den kram passen, zeigst 
nur kinderkrams und laberst die ganze zeit nur herum. sogar solche 
fachleute wie peter danegger widersprechen dir und merkst nix.

>> asm ist nicht simpel und auch nicht effizient. es zwingt dazu, wie > ein
>> prozessor zu denken statt wie ein mensch. das lenkt vom problem ab, > das
>> man loesen will. das komplexe sieht man dem fertigen programm
> sowieso
>> nicht an. es waere dumm, etwas unnoetig komplex zu machen, wenn es
>> hinterher sowieso keiner bewundert.
>
> In diesem Einwand kommt für mich nur mangelnde Erfahrung mit Asm zum
> Ausdruck, sorry.
sorry es waren drei einwaende. 1. dass asm zum denken als prozessor 
zwingt, 2. dass es deswegen vom problem ablenkt, 3. dass es bescheuert 
waere dinge komplex zu machen wenn einen dafür keiner bewundern kann.

> Das zunächst bequemer scheinende C bringt in der Folge nur mehr und > mehr
> künstliche Probleme mit sich, die man ohne nicht hat.
so ein quatsch. willst du etwa sagen, dass man asm nicht koennen muss? 
oder laesst du das nur fuer was gelten, das du nicht kannst?

> C-Threads sind
> voll davon...
cthreads sind voll davon, weil mehr leute c benutzen. sogar die meisten 
anfaenger sind klug genug.

> Ein AVR braucht i.d.R. keine Hochsprache. Asm passt
> perfekt.
er ist fuer die hochsprache c designt worden. sagt atmel selbst.

von Moby (Gast)


Lesenswert?

Klaus Peters schrieb:
> Moby schrieb:
>> Aufzwingen? Werd doch nicht albern.
> merkst du es nicht? sind die anderen die geisterfahrer? echt jetzt?

Was soll die Übertreibung? Was soll dieses Entweder Oder?
Unfug. Das Ergebnis zählt und ein solches ist natürlich auch in C 
erreichbar. Das ändert freilich nix an Simplizität und Effizienz von Asm 
für eine große Klasse von Anwendungen.

> er ist fuer die hochsprache c designt worden. sagt atmel selbst.

Ja das ist so. Die neueren XMegas sogar noch besser.
Daß schmälert umgekehrt aber seine Eignung für Asm in keinster Weise.
Asm ist da aus Prinzip nämlich sehr flexibel ;-)

TriHexagon schrieb:
> Du scheinst noch nie großartig pure Logik implementiert zu haben. Denn
> wenn das Problem eben nicht technischer Art ist, sondern logischer, dann
> ist eine "technische" Sprache (ASM) eben doch hinderlich und trägt nur
> zur Verkomplizierung der Lösung bei.

Nun, für viele viele MSR- und Steuerungsanwendungen brauchts das nicht.
Und stell Dir vor, für Logik gibts eigene Controller-Befehle!
Das muß man bei weitem nicht so hoch hängen...

> Nein danke, wenn ich mit einem AVR Dateien auf einer SD Karte lesen und
> schreiben muss (FAT Dateisystem), kann ich gern auf Assembler
> verzichten. Der Umgang mit "komplexeren" Datenstrukturen ist mit
> Assembler ziemlich mühselig.

In diesem konkreten Fall magst Du Recht haben.
Diese Sorte Probleme kann man allerdings auch auf speziellere Hardware 
auslagern. Schau, ich hab für solche Fälle ein einfach ansteuerbares 
VDIP Modul im Einsatz. Was meinst Du wie das flutscht. Solcherlei 
Zusatzhardware gibts in großer Fülle. Das muß man heute wirklich nicht 
mehr selbst machen!

von Moby (Gast)


Lesenswert?

Klaus Peters schrieb:
> du ignorierst alle argumente, die dir nicht in den kram passen

Den Eindruck hat man meistens von der Gegenseite ;-)
Zunächst sollte man die eigene Erfahrung nicht ignorieren.

> fachleute wie peter danegger widersprechen dir und merkst nix.

Die eigene Erfahrung zählt wiegesagt... Die spür ich zuallererst.
Darüber kann man sich doch ganz unaufgeregt austauschen- oder geht das 
etwa nicht?

> sorry es waren drei einwaende. 1. dass asm zum denken als prozessor
> zwingt, 2. dass es deswegen vom problem ablenkt, 3. dass es bescheuert
> waere dinge komplex zu machen wenn einen dafür keiner bewundern kann.

Obwohl ohne Hoffnung, es einem Nicht-ASMler zu erklären dazu soviel:
Punkt1: Wie ein Controller zu denken spielt sich noch (mindestens) eine 
Ebene tiefer ab. Asm zwingt in allererster Linie zur Kenntnis des 
Controllers. Ermöglicht ja gerade dadurch die feinere Anpassung an den 
Controller. Ermöglicht ja gerade dadurch jenes Plus an Performance und 
Minus an Platzbedarf. Sicher ermöglicht Hochsprache, Probleme abstrakter 
fassen zu können. Mit allen bekannten Nachteilen. Ich als ASMler bin 
darauf nicht angewiesen. Und viele andere auch (Punkt2).
Punkt3: Kompliziert gehts prinzipiell in jeder Sprache. ASM vereinfacht 
insofern, als daß die Dinge auf direkte Weise angepackt werden. Viele 
viele künstliche Konstruktionen der Hochsprache überflüssig werden.
Nimm sowas dämliches wie einen Cast-Operator... Ein typisches 
Kunstproblem, daß man sich mit erst mit dem Datentypkonzept einhandelt.
Und was die Bewunderung anbetrifft... Jo mei. Die notwendige Komplexität 
meiner Haussteuerung zum Beispiel soll doch in erster Linie nur 
funktionieren! Dann bin ich schon glücklich.

von Scelumbro (Gast)


Lesenswert?

Moby schrieb:
> Ermöglicht ja gerade dadurch jenes Plus an Performance und
> Minus an Platzbedarf.
Schon wieder erzählst du uns von dem 'Plus an Performance und Minus and 
Platzbedarf', veröffentlichst aber Code der offensichtlich noch nicht 
optmiert ist. Ja was den nun?

> Nimm sowas dämliches wie einen Cast-Operator... Ein typisches
> Kunstproblem, daß man sich mit erst mit dem Datentypkonzept einhandelt.
Glaubst du wirklich, der Compiler könnte nicht von alleine Casts setzen 
wenn die Compilerprogrammierer es wollten?  Explizite Casts sind dazu 
da, Fehler zu vermeiden in dem sie den Programmierer zwingen 1. nochmal 
darüber nachzudenken ob ein Cast zwischen inkompatiblen Datentypen an 
dieser Stelle überhaupt richtig ist 2. Einen potentiell 'gefährlichen' 
Cast durch explizites hinschreiben zu dokumentieren. Hier geht es also 
allein darum Programmierfehler zu vermeiden. Im generierten 
Maschinencode ist übrigens die Cast operation nicht mehr zu sehen, 
kostet also weder Performance noch Platz. Und 'komplexer' wird der Code 
nicht, im Gegenteil er wird besser lesbar - wenn man den C lesen kann. 
Es sei den du misst Komplexität an der Anzahl der für den Programmcode 
benötigten Zeichen.

Und spätestens wenn du mal statt 8-Bit Ints mit 32 Bit ints oder gar 
floats rechnen darfst, ist das mit der 'Komplexität' sowieso ein anderes 
Thema. Für den C Programmierer ist es nur ein anderer Datentyp.


> Und was die Bewunderung anbetrifft... Jo mei. Die notwendige Komplexität
> meiner Haussteuerung zum Beispiel soll doch in erster Linie nur
> funktionieren! Dann bin ich schon glücklich.
Publizier doch bitte mal deine Haussteuerung. Ein Haussteuerungsprojekt 
komplett in ASM, wäre wirklich ein schönes Beispiel für ein großes 
Projekt.

von Moby (Gast)


Lesenswert?

Scelumbro schrieb:
> Schon wieder erzählst du uns von dem 'Plus an Performance und Minus and
> Platzbedarf', veröffentlichst aber Code der offensichtlich noch nicht
> optmiert ist. Ja was den nun?

Der ist für seine geplanete Anwendung sogar schon sehr gut optimiert.
So gut, daß sich bislang keiner getraut hat, mit mit C gegenzuhalten.
Den kann ich gern nochmal anhängen- allein, ich vermute, ein echtes 
Interesse besteht da nicht. Hier gehts eher um Bashing gegen ASM...

>  Explizite Casts sind dazu
> da, Fehler zu vermeiden in dem sie den Programmierer zwingen 1. nochmal
> darüber nachzudenken ob ein Cast zwischen inkompatiblen Datentypen an
> dieser Stelle überhaupt richtig ist 2. Einen potentiell 'gefährlichen'
> Cast durch explizites hinschreiben zu dokumentieren. Hier geht es also
> allein darum Programmierfehler zu vermeiden.

Die man in ASM gar nicht erst macht ;-)
Da gibts kein "inkompatible Datentypen"-Wissenschaft.

> Im generierten
> Maschinencode ist übrigens die Cast operation nicht mehr zu sehen,
> kostet also weder Performance noch Platz.

Ach? Hatte ich das vermutet? Ich spiele auf sinnlos Verkomplizierung des 
Quellcodes durch Konzepte/Konstruktionen aller Art an- war das nun nicht 
eindeutig?

> Und spätestens wenn du mal statt 8-Bit Ints mit 32 Bit ints oder gar
> floats rechnen darfst

Ja ja rechnen. Ist ja gut und schön. Braucht man für AVR-MSR aber nur 
selten.

> Publizier doch bitte mal deine Haussteuerung. Ein Haussteuerungsprojekt
> komplett in ASM, wäre wirklich ein schönes Beispiel für ein großes
> Projekt.

Das könnte Dir so passen... Sonst noch Wünsche?
Und jetzt kommt die Frechheit: Trotzdem sag ich weiter meine Meinung ;-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ich kann die ganze Diskussion um Assembler <-> C überhaupt nicht 
verstehen.

Wer sich einfach mal die letzten 20 Jahre anschaut, wird erkennen, dass 
Hardware sich stetig weiterentwickelt. Dagegen sind Software-Algorithmen 
in der Entwicklungsgeschwindigkeit lahme Schnecken.

Algorithmen, die man einmal programmiert hat, kann man auch 20 Jahre 
später weiter verwenden. Die Hardware jedoch nicht, die bekommt man noch 
nichtmals mehr zu kaufen.

Wer Assembler programmiert, denkt keine 5 Meter weit. Er schreibt ein 
unportables Programm, dass bei einem Hardware-Wechsel komplett 
weggeworfen und neu geschrieben werden muss. Ein C-Programmierer muss 
sein Programm einfach an die neue Hardware anpassen - fertig.

Nicht portable Programme braucht kein Mensch. Denn sie sind morgen schon 
tot.

von Walter T. (nicolas)


Lesenswert?

Notiz an mich selbst: Nicht "mal eben" in der Frühstückspause µC.net 
lesen. Man kommt nicht mehr davon los und die Kollegen wundern sich über 
das laute lachen.

von Moby (Gast)


Lesenswert?

Frank M. schrieb:
> Wer sich einfach mal die letzten 20 Jahre anschaut, wird erkennen, dass
> Hardware sich stetig weiterentwickelt. Dagegen sind Software-Algorithmen
> in der Entwicklungsgeschwindigkeit lahme Schnecken.
>
> Algorithmen, die man einmal programmiert hat, kann man auch 20 Jahre
> später weiter verwenden. Die Hardware jedoch nicht, die bekommt man noch
> nichtmals mehr zu kaufen.

Ach was. AVR gibts schon so lange und die langen noch für viele 
weitere... Lasst Euch doch durch technische Entwicklungen nicht so unter 
Druck setzen. Aber OK, als Hobbyist kann man das entspannter sehen.


> Wer Assembler programmiert, denkt keine 5 Meter weit. Er schreibt ein
> unportables Programm, dass bei einem Hardware-Wechsel

Lies nochmal weiter oben zu den Treibern für Hardware-Wechsel...

> Nicht portable Programme braucht kein Mensch. Denn sie sind morgen schon
> tot.

Also meine liebe 128erMega Haussteuerung läuft bald ein ganzes Jahrzehnt 
:-)

von Moby (Gast)


Lesenswert?

Walter T. schrieb:
> Notiz an mich selbst: Nicht "mal eben" in der Frühstückspause
> µC.net
> lesen. Man kommt nicht mehr davon los

Ja hast Recht. Kann süchtig machen. Deshalb werd ich mich jetzt auch 
wieder anderen Dingen zuwenden und den Thread zur Ruhe kommen lassen ;-)
Einen schönen Tag allen Beteiligten!

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Moby schrieb:
> Also meine liebe 128erMega Haussteuerung läuft bald ein ganzes Jahrzehnt
> :-)

Wie süß.

Ich verdiene mein Geld unter anderem mit C-Programmen. Eines davon, das 
nach wie vor aktiv weiterentwickelt wird, gibt es seit Herbst 1992.

Das ist immer noch C, auch wenn der Compiler schon etliche Male durch 
einen neuen, besseren ersetzt wurde, und das Betriebssystem, auf dem das 
ganze läuft, natürlich auch schon diverse Iterationen und 
Verschlimmbesserungen mitgemacht hat.

Und auch wenn die Zielarchitektur bislang immer x86 war, würde es mich 
ein müdes Arschrunzeln kosten, mein Programm auf irgendwas anderem 
laufen zu lassen, sofern es mindestens 32 Bit breit ist.

Dieser Beitrag ist gesperrt und kann nicht beantwortet werden.