Werbung
Wiederspreche dir ja ungern, aber da liegst du falsch. Mehrere Ringbuffer habe ich schon mehrfach in Basom in Projekten programmiert, das gehört zu den einfachsten Dingen in Bascom. Immer diese VorurteileKommt immer auf das Projekt an. Ein Hello World hat man mit Bascom vermutlich schneller programmiert, sobald aber es aber darum geht eine komplexe Daten Ein-/Ausgabe mit mehreren Ringpuffer usw. zu realisieren ist man mit C schneller.![]()
Genau das spricht dagegen. In C werden für gleiche Aufgaben eine Unmege mehr an Programmzeilen benötigt. Die Programmlänge (Programmzeilen) sidn durchaus 3 bis 5 mal so lang. Von dahe rbleibt einen da nix anderes übrig als aufzusplittenEs spricht ja nichts dagegen das bei C auch zu tun. Aber wenn man eine einzige Datei mit über 2000 Zeile Code habe verliert man vollkommen die Übersicht.![]()
Wie gesagt bei sehr komplexen PC Programmen die immer wieder gleiche Routinen verwenden, stimme ich dir zu. Aber weniger bei Controllern, da die Programme einfach zu unterschiedlich sind. Insbesondere wenn man eine so umfangreiche Libary wie in Bascom nutzt, ist das selten notwendig. Mir persönlich ist eine einzige Quelldatei hier viel angenehmer und übersichtlicher. Aber auch das ist sicher etwas AnsichtssacheDa ist es wesentlich angenehmer das Ganze aufzusplitten in verschiedene Dateien in denen jeweils zusammenhängender Code groupiert wird. Diese Dateien stellen dann bestimmt Funktionen als Schnittstelle zur Verfügung mit denen man den Ganzen Code nutzten kann ohne direkt verstehen zu müssen wie er im Einzelnen funktioniert![]()
Hi Kijon,
könntest du zu so einer C-Zeile wie z.B:
" red0 = (boden_value_red0[2*i]*256 | boden_value_red0[2*i + 1]) >> 2;"
auch mal den erzeugten ASM-Code zeigen,
wie in deinem ersten Beispiel.
Den würde ich mir gern mal anschauen.
Gruß Jan
sieht schlimmer aus, als es ist. Das ist ja gerade die c-Schwelle, wo viele kleben bleiben.Zitat von JanB
Interessant, daß er die Werte im Motorola-Format (network order?)angelegt hat.
Aber daß er "2*i" u. "*256" wirklich hinschreiben würde, kann ich kaum glauben.
mfg robert
Wer glaubt zu wissen, muß wissen, er glaubt.
Hi Robert,
Nee, ist schon klarsieht schlimmer aus, als es istda hab ich kein Problem mit.
Ich hätte nur gern mal gesehen wie C einen etwas komlizierteren Ausdruck
in ASM übersetzt.
Speziell, wie C das mit dem notwendigen Zwischenspeicher regelt.
Wird alles durch den Stack geschoben, oder wird Speicher alloziert oder was ?
Das dürfte doch auch das Problem sein, das die BASCOM-Programmierer davon abhält,
einen ordentlichen Parser einzubauen, der auch komplexere Ausdrücke
in einer Anweisung zulässt.
Bei einem kleinen AVR mit nur 128Byte RAM oder so ist da nämlich schnell Ende.
Gruß Jan
Eigentlich kein Problem, er gibt ja eine Assembler-Liste her. Sehr lehrreich auch, wenn man erstmal den Optimizer abmurkst und dann "mit" vergleicht.Zitat von JanB
Es ist ja eigentlich mehr eine Arbeit für den Compiler, die innersten ausdrücke zu finden und dann gemütlich nach außen zu wandern.
Malloc wird er nicht nehmen, behaupt ich mal, er wird ja wohl deswegen keine Heap-Verwaltung starten. Wahrscheinlich stackt er sich eins.
Ich kann ja mal ein Programm zum Gucken stricken. Kann lustig sein.
mfg robert
Wer glaubt zu wissen, muß wissen, er glaubt.
kommt schonZitat von JanB
![]()
Der GCC optimiert sowas eigentlich ganz gut.Code:red0 = (boden_value_red0[2*i]*256 | boden_value_red0[2*i + 1]) >> 2; 824: f7 01 movw r30, r14 826: 80 81 ld r24, Z 828: 99 27 eor r25, r25 82a: 98 2f mov r25, r24 82c: 88 27 eor r24, r24 82e: 21 81 ldd r18, Z+1 ; 0x01 830: 33 27 eor r19, r19 832: 82 2b or r24, r18 834: 93 2b or r25, r19 836: 95 95 asr r25 838: 87 95 ror r24 83a: 95 95 asr r25 83c: 87 95 ror r24 83e: 68 2f mov r22, r24
Wie man erkennt kann läd er zuerst die Adresse des Array boden_value_red0 in das Register Z. Darüber lädt er den ersten Teil des Ausdrucks in die Register r24,r25 den zweiten in r18,r19, löscht die entsprechenden Bytes und verodert beides und schiebt es zweimal nach rechts.
Dann wird das Ergebnis in r22 kopiert, in welchem der Wert für red0 gespeichert ist.
Sehr viel besser hätte ich das jetzt von Hand auch nicht hinbekommen ( zwei Befehle kann man einsparen, wer findet sie ?)
MfG Kjion
Und einmal ohne optimize, auch nicht so schlimm
In der Version sieht man, was sich so ein Compiler denkt bei der ArbeitCode:.NOLIST .INCLUDE "M16DEF.INC" .LIST INIT: JMP L_0x0054 ............. L_0x0054: CLR r1 OUT SREG,r1 LDI YL,0x5F ................ JMP L_0x008E L_0x008A: JMP INIT unsigned char boden_value_red0[16]; void main() { unsigned short red0; unsigned char i; red0 = (boden_value_red0[2*i]*256 | boden_value_red0[2*i + 1]) >> 2; return; } L_0x008E: LDI YL,0x5C LDI YH,0x04 OUT SPH,YH OUT SPL,YL LDD r24,Y + 3 MOV r18,r24 CLR r19 MOVW r24,r18 ADD r24,r18 ADC r25,r19 MOVW ZL,r24 SUBI ZL,0xA0 SBCI ZH,0xFF LDD r24,Z + 0 MOV r18,r24 CLR r19 LDI r24,0x00 LDI r25,0x01 MUL r18,r24 MOVW r20,r0 MUL r18,r25 ADD r21,r0 MUL r19,r24 ADD r21,r0 CLR r1 LDD r24,Y + 3 MOV r18,r24 CLR r19 MOVW r24,r18 ADD r24,r18 ADC r25,r19 MOVW ZL,r24 SUBI ZL,0x9F SBCI ZH,0xFF LDD r24,Z + 0 CLR r25 OR r24,r20 OR r25,r21 ASR r25 ROR r24 ASR r25 ROR r24 STD Y + 1,r24 STD Y + 2,r25 JMP L_0x00EA L_0x00EA: ; return RJMP L_0x00EA
Beim Optimieren hat er ja dann gemerkt, daß er sich das Meiste ersparen kann.
mfg robert
Wer glaubt zu wissen, muß wissen, er glaubt.
Ich hab's ein bißchen kommentiert, wenn das wen interessiert
Listig, daß er das +1 rechts gleich in das Tabellen-Offset eingebaut hat.Code:red0 = (boden_value_red0[2*i]*256 | boden_value_red0[2*i + 1]) >> 2; L_0x008E: LDI YL,0x5C LDI YH,0x04 OUT SPH,YH OUT SPL,YL ; work frame LDD r24,Y + 3 ; get i MOV r18,r24 CLR r19 MOVW r24,r18 ; --> r24 ADD r24,r18 ; * r18 ---> = *2 ADC r25,r19 ; vielleicht n'carry, weiß man ja nie MOVW ZL,r24 ; SUBI ZL,0xA0 ; + 96 = (&boden_value_red0[0]) SBCI ZH,0xFF ; + 96 = (&boden_value_red0[0]) LDD r24,Z + 0 ; r24 = boden_value_red0[2*i] MOV r18,r24 :r18:r19 CLR r19 LDI r24,0x00 ;r24:r25 = 256 LDI r25,0x01 MUL r18,r24 ; * 256 MOVW r20,r0 ;-> r20 MUL r18,r25 ADD r21,r0 MUL r19,r24 ADD r21,r0 ;-> r21 CLR r1 ; heilige Kuh, muß null sein LDD r24,Y + 3 ; get i MOV r18,r24 ; s.o CLR r19 ; s.o MOVW r24,r18 ; s.o ADD r24,r18 ; s.o ADC r25,r19 ; * 2 (s.o.) MOVW ZL,r24 SUBI ZL,0x9F ; + 95 = (&boden_value_red0[1]) SBCI ZH,0xFF LDD r24,Z + 0 ; r24 = boden_value_red0[2*i + 1] CLR r25 OR r24,r20 ; r24 | r20 OR r25,r21 ; r24 | r21 ASR r25 ; >> 1 ROR r24 ASR r25 ; >> 1 ROR r24 STD Y + 1,r24 ; store red0 STD Y + 2,r25 JMP L_0x00EA ; forEver L_0x00EA: RJMP L_0x00EA
mfg robert
Wer glaubt zu wissen, muß wissen, er glaubt.
Hallo,
Danke, der erzeugte Code sieht wirklich ganz gut aus.
Schön ist auch, das C das mit Registern regelt, und nicht
stur das RAM benutzt. Wirklich interessant.
Das Array scheint allerdings ein Byte-Array zu sein,
denn er lädt nur Bytes.
Aber C behandelt die Werte ständig als INT. Deshalb
könnte man da deutlich mehr als zwei Befehle weglassen.
Gruß Jan
Hier mal mein Vorschlag:
Code:red0 = (boden_value_red0[2*i]*256 | boden_value_red0[2*i + 1]) >> 2; 824: f7 01 movw r30, r14 826: 80 81 ld r24, Z ;ersetzen durch "ld r25,Z" 828: 99 27 eor r25, r25 ;weglassen 82a: 98 2f mov r25, r24 ;weglassen 82c: 88 27 eor r24, r24 ;weglassen 82e: 21 81 ldd r18, Z+1 ;ersetzen durch "ldd r24, Z+1" 830: 33 27 eor r19, r19 ;weglassen 832: 82 2b or r24, r18 ;weglassen 834: 93 2b or r25, r19 ;weglassen 836: 95 95 asr r25 838: 87 95 ror r24 83a: 95 95 asr r25 83c: 87 95 ror r24 83e: 68 2f mov r22, r24 oder netto (und gleich r22 benutzt): movw r30, r14 ld r18, Z ldd r22, Z+1 asr r18 ror r22 asr r18 ror r22 macht 7 Befehle (und Takte) statt 14
Lesezeichen