Hallo,
ich habe einen Bitstrom (uint_8 bindata[8]), von welchem jedes 2. Bit
verworfen werden soll, weil es redundant ist (aber das Vorgängerbit
invertiert). Im Moment sieht mein Code so aus:
Problem ist im Moment dass das jeweils erste Nibble der Rohdaten im
jeweils unteren Nibble der Ausgangsdaten landen, und es müsste doch
überhaupt viel einfacher gehen? Das Ergebnis soll quasi so sein als ob
ich die Daten über eine UART schicke, und jedes 2. Bit verloren ginge...
@Werner (Gast)
>überhaupt viel einfacher gehen? Das Ergebnis soll quasi so sein als ob>ich die Daten über eine UART schicke, und jedes 2. Bit verloren ginge...
Du willst ein Byte auf ein Nibble zusammenschieben. Das kann man
entweder mit einer Tabelle mit 256 Einträgen (sehr schnell aber hoher
Speicherbedarf) oder einer Berechnungsfunktion (langsam, geringer
Speicherbedarf) erledigen, siehe Bitmanipulation. Auf dem avr gcc
gibt es eine Spezialfunktion, die kann die Bits in einem Byte beliebig
verwürfeln.
http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/AVR-Built_002din-Functions.html
Das hier ist Standard-C, das kann jeder Compiler.
Falk B. schrieb:> mit einer Tabelle mit 256 Einträgen
reichen da nicht 16 Einträge die mit dem zu prüfenden Byte verodert
werden?
edit:
Nee, nur verodern reicht nicht.
Man müsste die relevanten Bits mit einer Maske aus Einsen und-verknüpfen
und kann dann mit einer 16 Byte großen Tabelle vergleichen.
Frank B. schrieb:> Falk B. schrieb:>> mit einer Tabelle mit 256 Einträgen>> reichen da nicht 16 Einträge die mit dem zu prüfenden Byte verodert> werden?
Du brauchst zwar nur 16 Einträge, die sind aber über die halbe Tabelle
verteilt (sparse table), weshalb sie eben trotzdem mindestens 128
Einträge groß ist (wenn man vorher die irrelevanten Bits wegmaskiert).
Wenn du anfängst irgendwie rumzurechnen, um mit einer kleinen Tabelle zu
vergleichen, dann kannst du gleich vollständig rechnen, das macht vom
Aufwand her auch kaum noch was aus.
Wenn's nur für AVR sein soll:
Inline ASM,
8 x BLD/BLS,
2 Byte rein, 1 Byte raus, macht 3 Register, in denen ICE Werte eh schon
stehen.
16 Takte, 16 Byte Flash
Und gut is,
Ralf D. schrieb:> Du brauchst zwar nur 16 Einträge, die sind aber über die halbe Tabelle> verteilt (sparse table), weshalb sie eben trotzdem mindestens 128> Einträge groß ist (wenn man vorher die irrelevanten Bits wegmaskiert).
Na eigentlich 17.
Werner schrieb:> von welchem jedes 2. Bit> verworfen werden soll, weil es redundant ist (aber das Vorgängerbit> invertiert)
Es gibt ja noch den Fall, daß das Bit nicht das invertierte Vorgängerbit
ist. Der Code wäre dann fehlerhaft, Fall 17.
MfG Klaus
Werner schrieb:> von welchem jedes 2. Bit> verworfen werden soll, weil es redundant ist (aber das Vorgängerbit> invertiert)
Warum prüfst du nicht auf Verfälschung, wenn du schon die Möglichkeit
hast?
Jupp schrieb:> Warum prüfst du nicht auf Verfälschung, wenn du schon die Möglichkeit> hast?
Tut er vielleicht, war aber zu trivial um danach zu fragen (um 1
schieben, XOR)?
Hier ist noch eine Lösung für CPUs mit 64 bit Registern. Zugegeben, dort
sind dann meistens auch die anderen Varianten schnell genug :-)
>Warum prüfst du nicht auf Verfälschung, wenn du schon die Möglichkeit>hast?
Ja, mache ich, allerdings mit einer Schleife die ähnlich unleserlich
aussieht wie die im Eröffnungspost...
Werner
Werner schrieb:>>Warum prüfst du nicht auf Verfälschung, wenn du schon die Möglichkeit>>hast?>> Ja, mache ich, allerdings mit einer Schleife die ähnlich unleserlich> aussieht wie die im Eröffnungspost...
Dann wäre doch eine Tabelle von 256 Werten, wie
Falk B. schrieb:> Du willst ein Byte auf ein Nibble zusammenschieben. Das kann man> entweder mit einer Tabelle mit 256 Einträgen (sehr schnell aber hoher> Speicherbedarf)
das Richtige. Da geht man mit dem Originalbyte rein und bekommt
Ergebniss oder Fehler heraus. Check und Umsetzung in einem Rutsch. Und
256 Byte halte ich heutzutage nicht wirklich für einen "hohen"
Speicherbedarf.
MfG Klaus
@ chris_ (Gast)
>Man kann auch 2 Tabellen mit 16 Werten nehmen und vorher den>Eingangswert in 2 Nibble teilen.
Kann man, aber dann ist er Vorteil der hohen Geschwindigkeit einer
Tabelle schon fast wieder weg. Selbst die Einfachversion mit bitweise
Prüfung und Setzen ist nicht wirklich langsam.
>Kann man, aber dann ist er Vorteil der hohen Geschwindigkeit einer>Tabelle schon fast wieder weg.
... fast ... vielleicht ... ist es auch ein Mittelding zwischen Tabelle
und Bit-Algo. Man müsste es mal probieren ...
In Assembler ist das simpelst zu programmieren. Einfach das eine
Register immer zweimal links schieben (oder rotieren). Und dann das
Carry-Bit in das Zielregister hinein schieben (oder rotieren). 3
Assemblerinstruktionen pro Bit. Und trivial ausrollbar.
@chris_ (Gast)
>>Kann man, aber dann ist er Vorteil der hohen Geschwindigkeit einer>>Tabelle schon fast wieder weg.>... fast ... vielleicht ... ist es auch ein Mittelding zwischen Tabelle>und Bit-Algo. Man müsste es mal probieren ...
Siehe Anhang.
Wobei die Behandlung des Bit 7 SEHR merkwürding aussieht. Da hat sich
der Optimierer selber ins Knie geschossen, auch wenn das Ergebnis stimmt
;-)
1
uint8_t squeeze(uint8_t data) {
2
uint8_t tmp=0;
3
4
if (data & (1<<7)) tmp |= (1<<3);
5
5e: 98 2f mov r25, r24
6
60: 99 1f adc r25, r25
7
62: 99 27 eor r25, r25
8
64: 99 1f adc r25, r25
9
66: 99 0f add r25, r25
10
68: 99 0f add r25, r25
11
6a: 99 0f add r25, r25
12
if (data & (1<<5)) tmp |= (1<<2);
13
6c: 85 fd sbrc r24, 5
14
6e: 94 60 ori r25, 0x04 ; 4
15
if (data & (1<<3)) tmp |= (1<<1);
16
70: 83 fd sbrc r24, 3
17
72: 92 60 ori r25, 0x02 ; 2
18
if (data & (1<<1)) tmp |= (1<<0);
19
74: 81 fd sbrc r24, 1
20
76: 91 60 ori r25, 0x01 ; 1
21
22
return tmp;
23
}
24
78: 89 2f mov r24, r25
25
7a: 08 95 ret
> if (data & (1<<7)) tmp |= (1<<3);> 5e: 98 2f mov r25, r24> 60: 99 1f adc r25, r25
*2, MSB wandert ins Carry-Bit
> 62: 99 27 eor r25, r25
r25 =0
> 64: 99 1f adc r25, r25
Carry-Bit ins LSB "kopieren"
> 66: 99 0f add r25, r25> 68: 99 0f add r25, r25> 6a: 99 0f add r25, r25
3x *2 -> 3 mal links schieben
Das ist ein guter Kandidat für code obfuscation ;-)
Manchmal ist einfach auch besser. Bei den 3 anderen Bits geht es doch
auch.
Macht 24 Takte für die normale Funktion incl. call/return. Die muss 2x
aufgerufen werden. Macht in Summe 275 Takte für die Schleife mit 4
Zielbytes.
Die 256er Tabelle klappert mit gerade mal 138 Takten durch.
Die 16er Tabelle braucht 293 Takte, sogar mehr als die Version mit der
squeeze Funktion!