PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit Bitverschiebung



Moritz f.
25.03.2008, 00:09
Hallo,
muss gerade viel mit Bitverschiebungen arbeiten und habe hier ein Riesenproblem:

Hier mal der Code des ganzen



uint32_t i=0;
uint32_t t;

for(i=0; i<20; i++)
{
t = 1<<i;
}


Ansich nichts kompliziertes, is auch nur ein Beispiel für mein Problem.

Wenn ich das ganze nun mit dem GCC von WinAvr kompiliere (keine Warnings, Fehler, ect) kann ich im Debugfenster von AVR Studio folgende Werte ablesen:



1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
-->4294934528


Wie sich der aufmerksame Leser vielleicht vorstellen kann stimmt der letzte Wert nicht.
Eine Bitverschiebung um 1 nach links sollte doch gleich wirken wie eine multiplikation mit 2.

Zig mal mit Taschenrechner, und PC-C Programmen probiert, da klappts immer.

Die Frage ist nun:
Hat der Compiler einen Fehler?
Stimmt etwas in den Headerdateien nicht (hab eigentlich nachgeschaut)
Habe ich eine Fehler im Code?
Muss ich um mit uint32_t Typen zu arbeiten ein besonderes Compilerflag setzen?



Ich bitte um Antwort!

lg MoFe

Fabi2607
25.03.2008, 08:52
Ich habe gerade einfach mal unter Linux diesen Code compiliert und ausgeführt:

#include <stdio.h>

int main(void)
{
unsigned long i=0;
unsigned long t;
for(i=0;i<20;i++)
{
t= 1<<i;
printf("%u \n", t);
}
return 0;
}
und ich erhielt die Ausgabe


1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536
131072
262144
524288

also kann es an deinem Programmcode eigentlich nicht liegen. Allerdings wundert mich dein Ergebnis auch, denn du hast als letztes Ergebnis genau den maximalen Wert den die Variable annehmen kann minus den erwarteten Wert.
Ich kann aber auch nicht sagen woran das liegen könnte. Vielleicht ein Fehler im AVR-Studio?
Aber eine andere Möglichkeit weiß ich auch nicht.

PicNick
25.03.2008, 09:27
Na, der Effekt is klar:
Der nächste Shift setzt das Vorzeichen von einem 16-Bit-Wort.
Da es aber 32-Bit sein sollen, kopiert er das Bit in alle andern darüber.
Raus kommt eben 0xfff800 = 4294934528
Eben wir bei einem
int32_variable = int16_variable.

Ich hätt ja den Printf im Verdacht, der kann es machmal.

Versuch mal

printf("%u \n", (t & (1<<i));

sieht blöd aus, könnt aber helfen

manhunt
25.03.2008, 11:44
Hallo

Da sich wohl alles auf einem uProzessor abspielt gibt es wohl kein printf in dem sinne, ich schätze die werte kommen aus dem Debugger und entsprechen den Tatsächlichen Werten.

Vermutlich kann der ka 8bit prozessor nur 16bit variablen verarbeiten...

lg manhunt

Felix G
25.03.2008, 12:02
Vermutlich kann der ka 8bit prozessor nur 16bit variablen verarbeiten...Daran ist dann aber in diesem Fall nicht der Controller schuld sondern der C-Compiler, der die Anweisung nicht korrekt in Assembler-Befehle umsetzt. Denn prinzipiell kann auch ein 8-Bit Controller nahezu beliebig große Zahlen addieren, sofern man ihn richtig programmiert.


Ich würde also erstmal einen Blick auf den erzeugten Assembler-Code werfen, um herauszufinden was der Compiler da falsch macht. (und die shift-Funktion ggf. als inline-Assembler selbst schreiben)

Moritz f.
25.03.2008, 12:59
Hallo,
bin leider des Assemblercodens nicht mächtig :(
Könntest du mir einen Code dafür posten?

Mir läuft die Zeit etwas davon ;)
Werde trotzdem mal probieren den Assemblierten Code zu verstehen. . .

lg MoFe

PicNick
25.03.2008, 13:14
Na, dann, bevor du im Assembler verschwindest:


for(i=0; i<20; i++)
{
t = 1<<i;
t &= (1<<i); // das zerschmettert alle ungewollten Bits.
}

Moritz f.
25.03.2008, 14:01
Hallo PickNick,
irgendwie finde ich den unterschied zwischen deinem und meinem Code nicht, außer die UND Verknüpfung deren Sinn ich nicht sehe :/

Ergebnis ist bei mir genau das gleiche


Hier mal der Inline Assembler:


0000011E: 93CF PUSH R28 Push register on stack
+0000011F: 93DF PUSH R29 Push register on stack
+00000120: B7CD IN R28,0x3D In from I/O location
+00000121: B7DE IN R29,0x3E In from I/O location
+00000122: 9728 SBIW R28,0x08 Subtract immediate from word
+00000123: B60F IN R0,0x3F In from I/O location
+00000124: 94F8 CLI Global Interrupt Disable
+00000125: BFDE OUT 0x3E,R29 Out to I/O location
+00000126: BE0F OUT 0x3F,R0 Out to I/O location
+00000127: BFCD OUT 0x3D,R28 Out to I/O location
47: uint32_t i=0, t;
+00000128: 821D STD Y+5,R1 Store indirect with displacement
+00000129: 821E STD Y+6,R1 Store indirect with displacement
+0000012A: 821F STD Y+7,R1 Store indirect with displacement
+0000012B: 8618 STD Y+8,R1 Store indirect with displacement
52: for(i=0; i<20; i++)
+0000012C: 821D STD Y+5,R1 Store indirect with displacement
+0000012D: 821E STD Y+6,R1 Store indirect with displacement
+0000012E: 821F STD Y+7,R1 Store indirect with displacement
+0000012F: 8618 STD Y+8,R1 Store indirect with displacement
+00000130: C01D RJMP PC+0x001E Relative jump
54: t = 1<<i;

Hier fängs an:

+00000131: 812D LDD R18,Y+5 Load indirect with displacement
+00000132: 813E LDD R19,Y+6 Load indirect with displacement
+00000133: E081 LDI R24,0x01 Load immediate
+00000134: E090 LDI R25,0x00 Load immediate
+00000135: 2E02 MOV R0,R18 Copy register
+00000136: C002 RJMP PC+0x0003 Relative jump
+00000137: 0F88 LSL R24 Logical Shift Left
+00000138: 1F99 ROL R25 Rotate Left Through Carry
+00000139: 940A DEC R0 Decrement
+0000013A: F7E2 BRPL PC-0x03 Branch if plus
+0000013B: 27AA CLR R26 Clear Register
+0000013C: FD97 SBRC R25,7 Skip if bit in register cleared
+0000013D: 95A0 COM R26 One's complement
+0000013E: 2FBA MOV R27,R26 Copy register
+0000013F: 8389 STD Y+1,R24 Store indirect with displacement
+00000140: 839A STD Y+2,R25 Store indirect with displacement
+00000141: 83AB STD Y+3,R26 Store indirect with displacement
+00000142: 83BC STD Y+4,R27 Store indirect with displacement
+00000143: 818D LDD R24,Y+5 Load indirect with displacement
+00000144: 819E LDD R25,Y+6 Load indirect with displacement
+00000145: 81AF LDD R26,Y+7 Load indirect with displacement
+00000146: 85B8 LDD R27,Y+8 Load indirect with displacement
+00000147: 9601 ADIW R24,0x01 Add immediate to word
+00000148: 1DA1 ADC R26,R1 Add with carry
+00000149: 1DB1 ADC R27,R1 Add with carry
+0000014A: 838D STD Y+5,R24 Store indirect with displacement
+0000014B: 839E STD Y+6,R25 Store indirect with displacement
+0000014C: 83AF STD Y+7,R26 Store indirect with displacement
+0000014D: 87B8 STD Y+8,R27 Store indirect with displacement
+0000014E: 818D LDD R24,Y+5 Load indirect with displacement
+0000014F: 819E LDD R25,Y+6 Load indirect with displacement
---- No Source ------------------------------------------------------------------------------------
+00000150: 81AF LDD R26,Y+7 Load indirect with displacement
+00000151: 85B8 LDD R27,Y+8 Load indirect with displacement
+00000152: 3184 CPI R24,0x14 Compare with immediate
+00000153: 0591 CPC R25,R1 Compare with carry
+00000154: 05A1 CPC R26,R1 Compare with carry
+00000155: 05B1 CPC R27,R1 Compare with carry
+00000156: F2D0 BRCS PC-0x25 Branch if carry set


ich glaube das das Problem bei Speicherstelle +00000131 und folgenden liegt. Hier werden Y+5 und Y+6 in R18 und R19 kopiert. Das sind aber nur 2 byte, meine uint32_t Variablen haben ja 4 ;).
Gleiches geschieht an Stelle +00000133 wo R24 und R5 beschrieben werden, nicht jedoch R26 und R27.

Kann eigentlich kein Assembler, aber liege ich richtig in der Annahme das hier der Fehler liegt?

lg MoFe

PicNick
25.03.2008, 14:19
das AND ist zum ausmaskieren der unwerwünschten Bits
Andere Idee:
Versuch mal mit casten
t = (uint32)(1<<i);


EDIT: Denke, du hast in etwa recht. Versuch das Casten wirklich mal

Moritz f.
25.03.2008, 14:27
Hallo,
wenn der Fehler in der Bitverschiebung liegt, was er auch tut ( ;) ) hilft es mir nichts den falschen Wert mit dem gleichen falschen Wert zu maskieren.

Leider funktionierts mit casten auch nicht :(

inline assembler wird wohl die einzige Lösung sein, aber ich schaffe es nicht mal diesen asm code auf inline assembler zu portieren. . .

lg MoFe

Franzibua
25.03.2008, 14:48
Wenn ich in den Wald gehe, um ein PicNick zu machen, habe ich einen Korb mit. Ich habe gestern ordenlich eingekauft, nämlich 32 bit=4byte.

Meine geschickte Ex-freundin minigw könnte den korb so packen, dass alles reinpasst, aber sie wohnt nicht wie ich in der µC-City.

Die dumme ggc wäre zwar erreichbar, aber wenn sie den korb packt, gehen leider 2 bit verloren.

Ich könnte meine Mutter um den großen inline Korb bitten, aber der ist unhandlich und ich kann ihn nicht tragen.

Bitte helft mir!

PicNick
25.03.2008, 14:53
Jaa, wenn der Fehler im (1<<i) liegt, hast du natürlich recht.

Moritz f.
25.03.2008, 15:14
Hallo,
Problem (dank avr-ggc) mailing liste gelößt:

Blake leverett:
The problem is that (1<<i) assumes that '1' is an integer, or 16 bits. And
it's signed, so when it shifts 15 times, you get -32768 (or so), and that
converts to an unsigned long as the big number you see.

((uint32_t)1 << i) (or something like that) should work.


trotzdem danke für die Antworten

lg MoFe

PicNick
25.03.2008, 16:29
*grmpf* Ich sag's ja, "C" kommt von "casten"