Forum: Mikrocontroller und Digitale Elektronik bit invertieren


von hugo (Gast)


Lesenswert?

Wie kann man am besten so "mal eben" ein Bit invertieren, um es so an 
einem Port auszugeben?!
Also aus 11101010 mach 01010111

von Peter II (Gast)


Lesenswert?

hugo schrieb:
> 11101010

11101010 xor 11111111

xor passend zu deiner Programmiersprache suchen

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Das ist aber kein Bit, welches invertiert wird, sondern ein Byte, was 
gespiegelt wird.

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


Lesenswert?

hugo schrieb:
> Wie kann man am besten so "mal eben" ein Bit invertieren, um es so an
> einem Port auszugeben?!
> Also aus 11101010 mach 01010111
Das ist ein invertiertes BYTE... :-o

Und das gabs schon oft hier im Forum. Die Suche wird dir helfen...
http://www.mikrocontroller.net/search?query=Byte+spiegeln&forums[]=1&forums[]=2

EDIT: Mist, Fenster zu lang offen... :-/

von ET-Tutorials (Gast)


Lesenswert?

Ein einzelnes Bit kannst di ändern wie im Video gezeigt:
http://et-tutorials.de/1908/bitweise-manipulation/

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


Lesenswert?

ET-Tutorials schrieb:
> Ein einzelnes Bit kannst di ändern
Thema verfehlt...   ;-)

von Stephan (Gast)


Lesenswert?

CPL

von Christian W. (chrisw84)


Lesenswert?

Werden immer die selben Bits invertiert?
Dann z.B. mit einer Bitmaske!

Viele Grüße

von ich (Gast)


Lesenswert?

falls du einen xmega verwendest:

PORTx.OUTTGL = 0xFF; (alle Bits im Ausgangsregister toggeln)

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


Lesenswert?

ich schrieb:
> PORTx.OUTTGL = 0xFF; (alle Bits im Ausgangsregister toggeln)

Christian W. schrieb:
> Werden immer die selben Bits invertiert?
> Dann z.B. mit einer Bitmaske!

Stephan schrieb:
> CPL

An alle drei: Thema verfehlt.

Lest mal, was
hugo schrieb:
> Also aus 11101010 mach 01010111

von J.-u. G. (juwe)


Lesenswert?

Lothar Miller schrieb:
> Lest mal, was
> hugo schrieb:
>> Also aus 11101010 mach 01010111

hugo schrieb aber auch:
> Wie kann man am besten so "mal eben" ein Bit invertieren, um es so an
> einem Port auszugeben?!

Offensichtlich weiß er selbst nicht was er will und weiß auch nicht was 
ein Bit und was ein Byte ist.

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


Lesenswert?

J.-u. G. schrieb:
> Offensichtlich weiß er selbst nicht was er will und weiß auch nicht was
> ein Bit und was ein Byte ist.
Das geht offenbar vielen so, die das nicht wissen... ;-)
Nochmal der Link zur Suche, da sind auch ein paar solcher Kandidaten:
> Lothar Miller schrieb:
>> Die Suche wird dir helfen...
>> http://www.mikrocontroller.net/search?query=Byte+spiegeln

Und weil er es selbst nicht weiß, was er will, es aber beschreiben kann, 
gilt die Regel:
1
Es gibt 2 Arten von Menschen:
2
1. die, die auf der Basis unzureichender Information extrapolieren können

von Jürgen W. (juergen_w) Benutzerseite


Lesenswert?

>> Also aus 11101010 mach 01010111
1
    ldi    r16,0b11101010
2
    ldi    r18,8    ;8 mal schieben
3
loop:
4
    rol    r16
5
    ror    r17      ;Da kommt das Ergebniss rein
6
    dec    r18
7
    brne  loop
8
    ...

Nicht ausprobiert, deshalb ohne Gewähr ;-)


Grüsse

von hugo (Gast)


Lesenswert?

Okay, Ihr habt Recht, ich wusste nicht genau was ich wollte :D.
Also ich will das Byte natürlich Spiegeln. Und das am besten in C.
Es war gestern glaub einfach schon zu spät xD

von Volker Z. (vza)


Lesenswert?

1
char in = 0xEA;
2
char out = 0;
3
int loop;
4
5
for(loop=0;loop<8;loop++)
6
{
7
   if(in & 0x01)
8
   {
9
      out |= 0x01;
10
   }
11
   in  = in >> 1;
12
   out = out<< 1;
13
}
Ohne Gewähr.

Volker

von Jürgen W. (juergen_w) Benutzerseite


Lesenswert?

1
    ldi    r16,0b11101010    ;Soll gespiegelt werden
2
    sec
3
    rol    r16
4
lop:  ror    r17          ;Da kommt das Ergebniss rein
5
    lsl    r16
6
    brne  lop
7
    ...

Ist eleganter als oben. Diesmal mit Gewähr, habe es im Simulator 
getestet :-)

Es ist zwar C gefragt, aber vielleicht braucht es ja mal jemand in ASM.

von Klaus (Gast)


Lesenswert?

IMHO ist in C eine Tabelle das Schnellste.

MfG Klaus

von Michael D. (etzen_michi)


Lesenswert?

Warum schiebst du vor "lop" eine 1 in r16 rein?

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


Lesenswert?

hugo schrieb:
> Und das am besten in C.
Mit meinem Link zur Forumssuche hättest du das gefunden:
Beitrag "Re: reihenfolge der bits in einem byte umdrehen"

von Jürgen W. (juergen_w) Benutzerseite


Lesenswert?

Michael Dierken schrieb:
> Warum schiebst du vor "lop" eine 1 in r16 rein?

R16 ist solange <>0 bis die 1 im Carry ist. Solange springt dann brne.
Man spart so den Schleifenzähler und ein paar Zyklen..

von Sascha W. (sascha-w)


Lesenswert?

Klaus schrieb:
> IMHO ist in C eine Tabelle das Schnellste.
wenn man soviel Speicher übrig hat

Sascha

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Sascha Weber schrieb:
> Klaus schrieb:
>> IMHO ist in C eine Tabelle das Schnellste.
> wenn man soviel Speicher übrig hat

16 Byte reichen dafür. Die Nibbles kann man swappen.

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

http://en.wikipedia.org/wiki/Bit-reversal_permutation
"Bit reversal is most important for radix-2 Cooley–Tukey FFT algorithms"

nur um den englischen Begriff auch mal zu nennen

von Peter (Gast)


Lesenswert?

Folgender Code auch recht effizient compiliert...
1
#define M1  (uint8_t)0x01
2
#define M2  (uint8_t)0x02
3
#define M3  (uint8_t)0x04
4
#define M4  (uint8_t)0x08
5
#define M5  (uint8_t)0x10
6
#define M6  (uint8_t)0x20
7
#define M7  (uint8_t)0x40
8
#define M8  (uint8_t)0x80
9
10
uint8_t rotate(uint8_t MyVal)
11
{
12
  uint8_t NewVal=0;
13
  if (MyVal & M1) NewVal |= M8;
14
  if (MyVal & M2) NewVal |= M7;
15
  if (MyVal & M3) NewVal |= M6;
16
  if (MyVal & M4) NewVal |= M5;
17
  if (MyVal & M5) NewVal |= M4;
18
  if (MyVal & M6) NewVal |= M3;
19
  if (MyVal & M7) NewVal |= M2;
20
  if (MyVal & M8) NewVal |= M1;
21
  return NewVal;
22
}

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter schrieb:
> Folgender Code auch recht effizient compiliert...

Stimmt! Obwohl er recht lang aussieht, sind es nur 178 Byte erzeugter 
Code beim avr-gcc - inkl. leerer main-Funktion:

Program:     178 bytes (1.1% Full)
Data:          0 bytes (0.0% Full)

Da habe ich das mal eben mit einer Tabelle ausprobiert:
1
uint8_t
2
bitsreverse (uint8_t val)
3
{
4
    //                      0000  1000  0100  1100  0010  1010  0110  1110  0001  1001  0101  1101  0011  1011  0111  1111
5
    uint8_t reverse[16] = { 0x00, 0x08, 0x04, 0x0C, 0x02, 0x0A, 0x06, 0x0E, 0x01, 0x09, 0x05, 0x0D, 0x03, 0x0B, 0x07, 0x0F };
6
    return (reverse[val & 0x0F] << 4) | reverse[val >> 4];
7
}

Ergebnis:

Program:     266 bytes (1.6% Full)
Data:         16 bytes (1.6% Full)

Das Programm "sieht" zwar kürzer aus, kostet aber doch einiges mehr an 
Speicherplatz...

Zuallerletzt habe ich Volkers Version getestet (mit kleinen 
Modifikationen, z.B. int -> uint8_t):
1
uint8_t
2
bitsreverse (uint8_t in)
3
{
4
    uint8_t out = 0;
5
    uint8_t loop;
6
7
    for (loop = 0; loop < 8; loop++)
8
    {
9
       if (in & 0x01)
10
       {
11
           out |= 0x01;
12
       }
13
       in  = in >> 1;
14
       out = out << 1;
15
    }
16
    return (out);
17
}

Ergebnis:

Program:     162 bytes (1.0% Full)
Data:          0 bytes (0.0% Full)

Damit liegt Volkers Version derzeit an der Spitze, was die Sparsamkeit 
an Speicherplatz angeht.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Beim Austesten stellte ich fest, dass Volkers Version einen Fehler hat. 
Es fehlte das unterste Bit im Ergebnis.

Hier die korrigierte Version:
1
uint8_t
2
bitsreverse (uint8_t in)
3
{
4
    uint8_t out = 0;
5
    uint8_t loop;
6
7
    for (loop = 0; loop < 8; loop++)
8
    {
9
       out <<= 1;
10
11
       if (in & 0x01)
12
       {
13
           out |= 0x01;
14
       }
15
16
       in  >>= 1;
17
    }
18
    return (out);
19
}

Die Zeile "out <<= 1" musste lediglich vor das if-Statment gezogen 
werden.

Es bleibt aber bei 162 Bytes an Code.

von Michael K. (mmike)


Lesenswert?

Und noch ne Funktion:
1
uint8_t ByteMirror (uint8_t n)
2
{
3
  n = ((n >> 1) & 0x55) | ((n << 1) & 0xaa); 
4
  n = ((n >> 2) & 0x33) | ((n << 2) & 0xcc); 
5
  n = ((n >> 4) & 0x0f) | ((n << 4) & 0xf0); 
6
  return n;
7
}

Grüße,
Michael

von Peter (Gast)


Lesenswert?

Volkers Version ist etwas kürzer, dafür etwas langsamer bei der 
Ausführung. Bleibt beim Anwender zu entscheiden was für ihn wichtiger 
ist, Code-Size oder Code-Speed! ;o)

von Komisch (Gast)


Lesenswert?

Lothar Miller schrieb:
> Lest mal, was
> hugo schrieb:
>> Also aus 11101010 mach 01010111

Es geht doch nichts über einen passenden Titel. Warum sagt er dann nicht 
gleich "Byte spiegeln" oder Bitfolge invertieren.
Invertieren bezogen auf ein Bit ist immer noch der Not-Operator.

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


Lesenswert?

Hier mal ein Zwischenstand. Der Speicherbedarf wurde ermittelt, indem 
vorneweg alles mit mirror auskommentiert wurde, und danach der 
Speicherplatzzuwachs festgestellt wurde (Atmega32, -Os, avr-gcc 4.3.2):
1
#include <avr/io.h>
2
3
volatile uint8_t cnt;
4
5
unsigned char mirror( unsigned char a ) // 90 Bytes
6
{
7
  a = ((a >> 4) & 0x0F) | ((a << 4) & 0xF0);
8
  a = ((a >> 2) & 0x33) | ((a << 2) & 0xCC);
9
  a = ((a >> 1) & 0x55) | ((a << 1) & 0xAA);
10
  return a;
11
}
12
13
14
#define M1  (uint8_t)0x01
15
#define M2  (uint8_t)0x02
16
#define M3  (uint8_t)0x04
17
#define M4  (uint8_t)0x08
18
#define M5  (uint8_t)0x10
19
#define M6  (uint8_t)0x20
20
#define M7  (uint8_t)0x40
21
#define M8  (uint8_t)0x80
22
23
unsigned char mirror( unsigned char MyVal ) // 52 Bytes
24
{
25
  uint8_t NewVal=0;
26
  if (MyVal & M1) NewVal |= M8;
27
  if (MyVal & M2) NewVal |= M7;
28
  if (MyVal & M3) NewVal |= M6;
29
  if (MyVal & M4) NewVal |= M5;
30
  if (MyVal & M5) NewVal |= M4;
31
  if (MyVal & M6) NewVal |= M3;
32
  if (MyVal & M7) NewVal |= M2;
33
  if (MyVal & M8) NewVal |= M1;
34
  return NewVal;
35
}
36
37
unsigned char mirror( unsigned char in ) // 52 Bytes
38
{
39
    uint8_t out = 0;
40
    uint8_t loop;
41
    for (loop = 0; loop < 8; loop++) {
42
       out <<= 1;
43
       if (in & 0x01) out |= 0x01;
44
       in  >>= 1;
45
    }
46
    return out;
47
}
48
49
uint8_t mirror (uint8_t val) // 208 Bytes
50
{
51
    uint8_t out;
52
    //                      0000  1000  0100  1100  0010  1010  0110  1110  0001  1001  0101  1101  0011  1011  0111  1111
53
    uint8_t reverse[16] = { 0x00, 0x88, 0x44, 0xCC, 0x22, 0xAA, 0x66, 0xEE, 0x11, 0x99, 0x55, 0xDD, 0x33, 0xBB, 0x77, 0xFF };
54
    out  = reverse[val&0x0F] & 0xF0;
55
    out |= reverse[val>>4]   & 0x0F;
56
    return out;
57
}
58
59
/*****************************************************************/
60
int main (void)
61
{
62
    while (1)
63
    {
64
      cnt = cnt+1;
65
      cnt = mirror(cnt);
66
    } 
67
}

Komisch schrieb:
> Es geht doch nichts über einen passenden Titel. Warum sagt er dann nicht
> gleich "Byte spiegeln" oder Bitfolge invertieren.
Vielleicht, weil ihm der Begriff nicht geläufig war...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Michael K. schrieb:
> Und noch ne Funktion:
>
>
1
> uint8_t ByteMirror (uint8_t n)
2
> {
3
>   n = ((n >> 1) & 0x55) | ((n << 1) & 0xaa);
4
>   n = ((n >> 2) & 0x33) | ((n << 2) & 0xcc);
5
>   n = ((n >> 4) & 0x0f) | ((n << 4) & 0xf0);
6
>   return n;
7
> }
8
>

Stimmt, die habe ich hier auf µC.net auch schon öfters rumschwirren 
sehen.

Ergebnis:

Program:     180 bytes (1.1% Full)
Data:          0 bytes (0.0% Full)

Das ist dann der 3. Platz... aber knapp :-)

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


Lesenswert?

Lothar Miller schrieb:
> uint8_t mirror (uint8_t val) // 208 Bytes
Frank M. schrieb:
> Program:     180 bytes (1.1% Full)
Ich muß mal meinen Compiler updaten... ;-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Lothar Miller schrieb:
> Hier mal ein Zwischenstand. Der Speicherbedarf wurde ermittelt, indem
> vorneweg alles mit mirror auskommentiert wurde, und danach der
> Speicherplatzzuwachs festgestellt wurde (Atmega32, -Os, avr-gcc 4.3.2):

Erstaunlich, was bei Dir an relativen(!) Unterschieden rauskommt. Bei 
mir ist es ATmega168, -Os, avr-gcc 4.3.3.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Lothar Miller schrieb:
> Lothar Miller schrieb:
>> uint8_t mirror (uint8_t val) // 208 Bytes
> Frank M. schrieb:
>> Program:     180 bytes (1.1% Full)
> Ich muß mal meinen Compiler updaten... ;-)

Da ist ein leeres main() auch mit drin. Das halte ich für legitim, da 
der Compiler auch bei Nicht-Aufruf die Funktionen NICHT wegoptimieren 
kann, da sie nicht als static deklariert sind. Wie ist das bei Dir? 
Zählst Du Deine (aufwendigere) main-Funktion mit?

EDIT: Bei mir frisst die leere main-Funktion 138 Byte, die müsste man 
also von meinen Werten abziehen. Dann sieht der 4.3.3er Compiler um 
einiges besser aus als Dein 4.3.2er.

von stru_aus (Gast)


Lesenswert?

hübsche sammlung von verschiedenen ansätzen zum bitreihenfolge 
invertieren:

http://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious

geht als schleife, mit arrays, und ein paar andere "hacks".

die ganzen tipps da sind öfters recht praktisch.

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


Lesenswert?

Frank M. schrieb:
> Wie ist das bei Dir?
So sieht die "leere" main aus:
1
int main (void)
2
{
3
    while (1)
4
    {
5
      cnt = cnt+1;
6
     // cnt = mirror(cnt);
7
    } 
8
}

von Volker Z. (vza)


Lesenswert?

Ich glaube wir haben Hugo (TO) etwas überfordert. Er meldet sich gar 
nicht mehr!

Hallo Huuuugooooo.
Konten wir dir helfen oder haben wir dich nur verwirrt?

volker

von hugo (Gast)


Lesenswert?

Das ist ja echt der Wahnsinn xD
Ihr ward echt seeehr krass...
Naja das ganze ist so: Ich hab ein Display und das hängt direkt an einem 
Port. Aus Layout technischen Gründen müsste ich ALLE Leitungen kreuzen, 
was natürlich ziemlich dumm ist. Jetzt habe ich überlegt einfach immer 
das Byte zu spiegeln, damit ich es so übertragen kann. Ich denke aber 
bei einem Grafik LCD ist das totaler Quatsch, da der AVR ja 2/3 seiner 
Zeit nur damit verbringt Daten zu spiegeln. Da er später noch andere 
Dinger erledigen soll wäre das also dumm.
Nun bin ich am Überlegen einen SMD-Stecker zu nehmen, dann kann ich die 
Leiterbahnen von oben anfahren (kann Zuhause nur einseitige Platinen mit 
min. 8mil Leiterbahnen).

Aber ich finde diesen Thread echt klasse! Wenn wir nun vielleicht alles 
zusammenstellen und irgendwo festhalten wär das schonmal toll!

Danke euch!

von Peter (Gast)


Lesenswert?

Anbei die reine Codegrösse für die Funktionen und die Anzahl CPU-Zyklen 
für die Verarbeitung (Function Call bis Return)

Bei mirror4() habe ich den Array auf static gesetzt, dann werden dessen 
Werte nur einmal im StartUpCode initialisiert und nicht bei jedem 
Funktions-Aufruf. (Codesize und CPU-Zyklen für diese Initialisierung 
sind nicht dabei)
1
#include <avr/io.h>
2
3
volatile uint8_t cnt;
4
5
unsigned char mirror1(unsigned char a ) // 42 Bytes, 28 Cycles
6
{
7
  a = ((a >> 4) & 0x0F) | ((a << 4) & 0xF0);
8
  a = ((a >> 2) & 0x33) | ((a << 2) & 0xCC);
9
  a = ((a >> 1) & 0x55) | ((a << 1) & 0xAA);
10
  return a;
11
}
12
13
14
#define M1  (uint8_t)0x01
15
#define M2  (uint8_t)0x02
16
#define M3  (uint8_t)0x04
17
#define M4  (uint8_t)0x08
18
#define M5  (uint8_t)0x10
19
#define M6  (uint8_t)0x20
20
#define M7  (uint8_t)0x40
21
#define M8  (uint8_t)0x80
22
23
unsigned char mirror2(unsigned char MyVal ) // 40 Bytes, 27 Cycles
24
{
25
  uint8_t NewVal=0;
26
  if (MyVal & M1) NewVal |= M8;
27
  if (MyVal & M2) NewVal |= M7;
28
  if (MyVal & M3) NewVal |= M6;
29
  if (MyVal & M4) NewVal |= M5;
30
  if (MyVal & M5) NewVal |= M4;
31
  if (MyVal & M6) NewVal |= M3;
32
  if (MyVal & M7) NewVal |= M2;
33
  if (MyVal & M8) NewVal |= M1;
34
  return NewVal;
35
}
36
37
unsigned char mirror3(unsigned char in ) // 24 Bytes, 81 Cycles
38
{
39
    uint8_t out = 0;
40
    uint8_t loop;
41
    for (loop = 0; loop < 8; loop++) {
42
       out <<= 1;
43
       if (in & 0x01) out |= 0x01;
44
       in  >>= 1;
45
    }
46
    return out;
47
}
48
49
50
uint8_t mirror4(uint8_t val)  // 34 Bytes, 26 Cycles
51
{
52
    //                             0000  1000  0100  1100  0010  1010  0110  1110  0001  1001  0101  1101  0011  1011  0111  1111
53
    static uint8_t reverse[16] = { 0x00, 0x88, 0x44, 0xCC, 0x22, 0xAA, 0x66, 0xEE, 0x11, 0x99, 0x55, 0xDD, 0x33, 0xBB, 0x77, 0xFF };
54
    uint8_t out;
55
    out  = reverse[val&0x0F] & 0xF0;
56
    out |= reverse[val>>4]   & 0x0F;
57
    return out;
58
}
59
60
/*****************************************************************/
61
int main (void)
62
{
63
    while (1)
64
    {
65
      //------------------------------
66
      cnt = 0xA5;
67
      cnt = mirror1(cnt);
68
      //------------------------------
69
      cnt = 0xA5;
70
      cnt = mirror2(cnt);
71
      //------------------------------
72
      cnt = 0xA5;
73
      cnt = mirror3(cnt);
74
      //------------------------------
75
      cnt = 0xA5;
76
      cnt = mirror4(cnt);
77
      //------------------------------
78
    }
79
}

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter schrieb:
> Anbei die reine Codegrösse für die Funktionen und die Anzahl CPU-Zyklen
> für die Verarbeitung (Function Call bis Return)

Welche avr-gcc-Version? Welche Optimierungsstufe? Wie wir gestern 
gesehen haben, gibt es allein bei der Version erhebliche Unterschiede im 
Ergebnis.

> Bei mirror4() habe ich den Array auf static gesetzt, dann werden dessen
> Werte nur einmal im StartUpCode initialisiert und nicht bei jedem
> Funktions-Aufruf.

Ohja, das hatte ich doch glatt übersehen. Damit liegt mirror4 mit der 
Ausführungszeit an erster Stelle und vom Speicherplatz immerhin noch an 
2. Stelle.

Interessant, dass mirror3() als kleinste Funktion auch die langsamste 
ist.

Danke für die Aufstellung.

Gruß,

Frank

von hugo (Gast)


Lesenswert?

Also das ist ja super!
Wo speichern wir das jetzt ab?! ;-)

von MWS (Gast)


Lesenswert?

hugo schrieb:
> Also ich will das Byte natürlich Spiegeln. Und das am besten in C.

Na, wenn nicht ausschließlich C, dann hat auch noch 'ne Bascom-Version 
Platz ;D
1
$Regfile = "m32def.dat"
2
$Crystal = 8000000
3
$hwstack = 32
4
$swstack = 32
5
$framesize = 32
6
7
Dim Var_In As Byte , Var_Out As Byte
8
9
Var_In = &B11011001
10
Print Bin(Var_In)
11
12
  !LDS  R16, {Var_In}
13
  !BST  R16, 0
14
  !BLD  R17, 7
15
  !BST  R16, 1
16
  !BLD  R17, 6
17
  !BST  R16, 2
18
  !BLD  R17, 5
19
  !BST  R16, 3
20
  !BLD  R17, 4
21
  !BST  R16, 4
22
  !BLD  R17, 3
23
  !BST  R16, 5
24
  !BLD  R17, 2
25
  !BST  R16, 6
26
  !BLD  R17, 1
27
  !BST  R16, 7
28
  !BLD  R17, 0
29
  !STS  {Var_Out}, R17
30
31
Print Bin(Var_Out)
32
33
End

40Bytes, 20 Cycles.

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


Lesenswert?

MWS schrieb:
> dann hat auch noch 'ne Bascom-Version Platz ;D
>   !LDS  R16, {Var_In}
>   !BST  R16, 0
Naja. Ich würde sagen, das fällt fast schon unter "Assembler-Doping"...

> 40Bytes, 20 Cycles.
Das ist jetzt aber noch keine richtige Unterroutine...
>> Peter schrieb:
>>> Anbei die reine Codegrösse für die Funktionen und die Anzahl CPU-Zyklen
>>> für die Verarbeitung (Function Call bis Return)

von Arc N. (arc)


Lesenswert?

hugo schrieb:
> Das ist ja echt der Wahnsinn xD
> Ihr ward echt seeehr krass...
> Naja das ganze ist so: Ich hab ein Display und das hängt direkt an einem
> Port. Aus Layout technischen Gründen müsste ich ALLE Leitungen kreuzen,
> was natürlich ziemlich dumm ist. Jetzt habe ich überlegt einfach immer
> das Byte zu spiegeln, damit ich es so übertragen kann. Ich denke aber
> bei einem Grafik LCD ist das totaler Quatsch, da der AVR ja 2/3 seiner
> Zeit nur damit verbringt Daten zu spiegeln. Da er später noch andere
> Dinger erledigen soll wäre das also dumm.

Bei der Initialisierung des GLCD kann man auch entsprechende Konstante 
nehmen (und das kommentieren), die Fonts zur Textausgabe lassen sich 
auch vorher spiegeln/passend generieren und die Routinen zum 
Pixel-Setzen/Linien-Zeichnen kann man auch passend schreiben...

von MWS (Gast)


Lesenswert?

Lothar Miller schrieb:
> Naja. Ich würde sagen, das fällt fast schon unter "Assembler-Doping"...

Da hast Du natürlich recht, da sich aber Assembler bei Bascom äußerst 
problemlos in Basic-Code einbetten lässt, so ist das legitim.

> Das ist jetzt aber noch keine richtige Unterroutine...

Das sind sie im C-Beispiel auch nicht. Nur mirror2 wird über einen CALL 
aufgerufen, alles andere wird vom Compiler Inline eingebaut (mit -Os).
Und zwar wiederholt, zweimal mirror1 aufgerufen wird auch zweimal als 
Inline compiliert. Wahrscheinlich weil bei der kleinen Codegröße der 
Funktion der Overhead unrentabel ist.

>>>> Anbei die reine Codegrösse für die Funktionen und die Anzahl CPU-Zyklen
>>>> für die Verarbeitung (Function Call bis Return)

Eine Bascom-Sub, die auch tatsächlich als Sub eingebunden ist, benötigt 
dann 39 Cycles, liegt daran, daß die Variablenzeiger auf den Frame 
gehen/von dort geholt werden müssen.

von Räuber Hotzenplotz (Gast)


Lesenswert?

Also die Bascom Variante von MWS (Gast) gefällt mir doch sehr.
Wie könnte ich das auf C übertragen?
Geht das in C überhaupt, Werte an Assembler zu übergeben und 
zurückzubekommen?

von MWS (Gast)


Lesenswert?

Räuber Hotzenplotz schrieb:
> Wie könnte ich das auf C übertragen?

Sollte per Inline Assembler gehen, ist aber im Vergleich zu dem 
Gezeigten relativ kompliziert, der C-Compiler hat's nicht gern, wenn man 
sich einmischt.

Vorteil meiner Version ist die völlig freie Bitzuweisung, somit lassen 
sich einfach die Anschlüsse intern "umverdrahten".

So entstand dieser Codeteil auch, wurde in ein Lib eingebunden um 
entsprechend einem anderes Platinenlayout für ein Display mit einem 
I2C-Expander PCF8574 die Pins frei zuweisen zu können.

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


Lesenswert?

MWS schrieb:
> Das sind sie im C-Beispiel auch nicht. Nur mirror2 wird über einen CALL
> aufgerufen, alles andere wird vom Compiler Inline eingebaut (mit -Os).
Das schon. Aber die Aufrufparameter sind frei wählbar.

> Eine Bascom-Sub, die auch tatsächlich als Sub eingebunden ist, benötigt
> dann 39 Cycles
Liegt damit annähernd gleichauf zur Lösung mirror2, wo ja auch beliebige 
Bits zugeordnet werden könnten.

von MWS (Gast)


Lesenswert?

Lothar Miller schrieb:
> Das schon. Aber die Aufrufparameter sind frei wählbar.

Wenn man Speed braucht, dann ist's egal, ob die Aufrufparameter frei 
wählbar sind. Speziell für den Fall eine Pinbelegung "umzubiegen" wird 
dieser Codeblock in die ausgebende Funktion eingebaut, da brauch' ich 
keinen Call auf eine Funktion machen, und dann sind wir wieder bei 20 
Takten. Da beißt die Maus keinen Faden ab.

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


Lesenswert?

MWS schrieb:
> Da beißt die Maus keinen Faden ab.
Es ging ja nicht um den Faden der Maus, sondern um die 
Vergleichbarkeit... ;-)

von MWS (Gast)


Lesenswert?

Lothar Miller schrieb:
> Es ging ja nicht um den Faden der Maus, sondern um die
> Vergleichbarkeit... ;-)

Ja, und mir ging's um die Verwendbarkeit im Sinnes des TEs :D

von MWS (Gast)


Lesenswert?

Um auch das noch zu beantworten:

Räuber Hotzenplotz schrieb:
> Wie könnte ich das auf C übertragen?
> Geht das in C überhaupt, Werte an Assembler zu übergeben und
> zurückzubekommen?
1
unsigned char mirror5(unsigned char in ) // 21 Takte
2
{
3
   unsigned char out;
4
5
   asm volatile ( 
6
    "bst  %[in_reg], 0           \n\t"    
7
    "bld  %[out_reg],7           \n\t"    
8
    "bst  %[in_reg], 1           \n\t"    
9
    "bld  %[out_reg],6           \n\t"    
10
    "bst  %[in_reg], 2           \n\t"    
11
    "bld  %[out_reg],5           \n\t"    
12
    "bst  %[in_reg], 3           \n\t"    
13
    "bld  %[out_reg],4           \n\t"    
14
    "bst  %[in_reg], 4           \n\t"    
15
    "bld  %[out_reg],3           \n\t"    
16
    "bst  %[in_reg], 5           \n\t"    
17
    "bld  %[out_reg],2           \n\t"    
18
    "bst  %[in_reg], 6           \n\t"    
19
    "bld  %[out_reg],1           \n\t"    
20
    "bst  %[in_reg], 7           \n\t"    
21
    "bld  %[out_reg],0           \n\t"    
22
         : [out_reg] "=&r" (out), [in_reg] "+r" (in)
23
   );
24
   return out;
25
}

von Räuber Hotzenplotz (Gast)


Lesenswert?

@MWS (Gast):
Ganz vielen Dank für die Mühe!   :-)
: [out_reg] "=&r" (out), [in_reg] "+r" (in)
verstehe ich nicht so ganz (bin Anfänger in C )
Werde es am Montag testen, wenn ich wieder in der "Firma" bin ;-)
Hoffentlich geht das mit AVRStudio4 und WINAVR...
Ich wär so froh   :-)

von MWS (Gast)


Lesenswert?

Räuber Hotzenplotz schrieb:
> : [out_reg] "=&r" (out), [in_reg] "+r" (in)
> verstehe ich nicht so ganz

Nennt sich "clobber list". Ich fand's interessant wie's dem Compiler 
beizubringen ist, mach' normalerweise nichts in C-asm. Du kannst 
übrigens auch mirror2 nehmen, da wird sehr schöner und kurzer Code 
erzeugt. Funktional ist's gleich.

von Markus G. (thechief)


Lesenswert?

Hallo Räuber, :-)

ich habs mal kurz für Dich getestet, damit Du am Montag beruhigt in die 
Firma fahren kannst:
1
unsigned char mirror5(unsigned char);  // Prototyp
2
3
int main (void)
4
{
5
  mirror5 (234);
6
}
7
8
9
unsigned char mirror5(unsigned char in ) // 21 Takte
10
{
11
   unsigned char out;
12
13
   asm volatile ( 
14
    "bst  %[in_reg], 0           \n\t"    
15
    "bld  %[out_reg],7           \n\t"    
16
    "bst  %[in_reg], 1           \n\t"    
17
    "bld  %[out_reg],6           \n\t"    
18
    "bst  %[in_reg], 2           \n\t"    
19
    "bld  %[out_reg],5           \n\t"    
20
    "bst  %[in_reg], 3           \n\t"    
21
    "bld  %[out_reg],4           \n\t"    
22
    "bst  %[in_reg], 4           \n\t"    
23
    "bld  %[out_reg],3           \n\t"    
24
    "bst  %[in_reg], 5           \n\t"    
25
    "bld  %[out_reg],2           \n\t"    
26
    "bst  %[in_reg], 6           \n\t"    
27
    "bld  %[out_reg],1           \n\t"    
28
    "bst  %[in_reg], 7           \n\t"    
29
    "bld  %[out_reg],0           \n\t"    
30
         : [out_reg] "=&r" (out), [in_reg] "+r" (in)
31
   );
32
   return out;
33
}

Getestet mit AVR-Studio 4.18 (Build 716) / Amtel 8515 Simulator, lässt 
sich einwandfrei compilieren!


Gruß

Markus

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Und warum Inline-Assembler???
1
#include <stdint.h>
2
3
uint8_t swap (uint8_t a)
4
{
5
    uint8_t c = a >> 7;
6
    
7
    if (a & (1 << 6))  c |= 1 << 1;
8
    if (a & (1 << 5))  c |= 1 << 2;
9
    if (a & (1 << 4))  c |= 1 << 3;
10
    if (a & (1 << 3))  c |= 1 << 4;
11
    if (a & (1 << 2))  c |= 1 << 5;
12
    if (a & (1 << 1))  c |= 1 << 6;
13
    if (a & (1 << 0))  c |= 1 << 7;
14
    return c;
15
}

Belegt nur 2 Register, das Input-Register bleibt erhalten und braucht 19 
Ticks + RET (deviceabhängig), hier avr-gcc 4.6.1:
1
swap:
2
  mov r25,r24
3
  rol r25
4
  clr r25
5
  rol r25
6
  sbrc r24,6
7
  ori r25,lo8(2)
8
  sbrc r24,5
9
  ori r25,lo8(4)
10
  sbrc r24,4
11
  ori r25,lo8(8)
12
  sbrc r24,3
13
  ori r25,lo8(16)
14
  sbrc r24,2
15
  ori r25,lo8(32)
16
  sbrc r24,1
17
  ori r25,lo8(64)
18
  sbrc r24,0
19
  ori r25,lo8(-128)
20
  mov r24,r25
21
  ret

In Assembler geht auch
1
LSL src  $  ROR dest
2
LSL src  $  ROR dest
3
LSL src  $  ROR dest
4
LSL src  $  ROR dest
5
LSL src  $  ROR dest
6
LSL src  $  ROR dest
7
LSL src  $  ROR dest
8
LSL src  $  ROR dest

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.