Hallo zusammen, uint8_t src = gegebener variabler wert uint portB00 = PORTB & 0b11111100; Ich will die ersten 2 Bits von src nach PORTB schieben und danach src um 2 Stellen nach rechts shiften. Also so: PORTB = portB00 | (src & 0b00000011); src >>= 2; PORTB = portB00 | (src & 0b00000011); src >>= 2; PORTB = portB00 | (src & 0b00000011); src >>= 2; PORTB = portB00 | (src & 0b00000011); src >>= 2; Das muss aber in 4 Takten geschehen. C macht daraus jedoch mov, andi, or, out, lsr, lsr und das sind leider 2 Takte zu viel. Kennt jemand einen Trick? Wenn es nur 1 Bit wäre, würde ich bst, bld nehmen, aber es sind halt zwei Bits....
Möchtest du vielleicht noch sagen um welchen Mikrocontroller es sich handelt?
Gast
#4105556
Christian S. schrieb: > Kennt jemand einen Trick? (Inline) Assembler?
Kaj G. schrieb: > Möchtest du vielleicht noch sagen um welchen Mikrocontroller es sich > handelt? Sorry. Geht um den ATtiny84A-PU.
Christian S. schrieb: > Das muss aber in 4 Takten geschehen. C macht daraus jedoch mov, andi, > or, out, lsr, lsr und das sind leider 2 Takte zu viel. Kennt jemand > einen Trick? Jegliche Art von "Trick" in C ist unzuverlässig. Wenn es taktzyklengenau sein muss, ist zwingend Assembler erforderlich. Christian S. schrieb: > Wenn es nur 1 Bit wäre, würde ich bst, bld nehmen, aber es sind halt > zwei Bits.... Dann nimm eben zweimal bst und bld. Macht dann genau die gewünschten 4 Taktzyklen.
Rolf Magnus schrieb: > Dann nimm eben zweimal bst und bld. Macht dann genau die gewünschten 4 > Taktzyklen. Geht nicht, da es ein IO-Port ist, braucht es noch ein out am Ende. Naja, wahrscheinlich ist es in 4 Takten einfach nicht möglich...
Christian S. schrieb: > Das muss aber in 4 Takten geschehen. C macht daraus jedoch mov, andi, > or, out, lsr, lsr und das sind leider 2 Takte zu viel. Kennt jemand > einen Trick? Der Compiler hat schon ausgetrickst, schneller geht es nicht.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
Sagte ich ja bereits im Eingangsposting. Dachte, es gäbe noch einen Geheimtrick mit noch nicht unterstützten ASM Befehlen, aber habe selber im Instruction Set nichts gefunden... naja, habs jetzt mit einem Vorbuffer gelöst. Trotzdem danke.
Marc Vesely schrieb: > Der Compiler hat schon ausgetrickst, schneller geht es nicht. Doch. Der IN Befehl wird nur einmal gebraucht.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
Und wenn es hauptsächlich daum geht, die 2 Bits in exaktem Abstand zu erzeugen, nicht um die Gesamtlaufzeit, dann kann man 4 Register passend vorbereiten und kommt bis runter auf einen Abstand von 1 Takt.
A. K. schrieb: > Doch. Der IN Befehl wird nur einmal gebraucht. Nein. SrcReg wird geschoben, r16 OR SrcReg setzt nur die Einsen, kann aber keine löschen. Wenn SrcReg am Anfang 0x11000011 ist, wird PortB nach 4*Schieben auf 0x11111111 stehen, das soll aber nicht so sein. A. K. schrieb: > Und wenn es hauptsächlich daum geht, die 2 Bits in exaktem Abstand zu > erzeugen, nicht um die Gesamtlaufzeit, dann kann man 4 Register passend > vorbereiten und kommt bis runter auf einen Abstand von 1 Takt. Stimme ich zu, nur soll es aber gar nicht in 1 Takt Abstand gehen.
Gast
#4105784
Marc Vesely schrieb: > A. K. schrieb: >> Doch. Der IN Befehl wird nur einmal gebraucht. > > Nein. > SrcReg wird geschoben, r16 OR SrcReg setzt nur die Einsen, > kann aber keine löschen. > Wenn SrcReg am Anfang 0x11000011 ist, wird PortB nach 4*Schieben > auf 0x11111111 stehen, das soll aber nicht so sein. Für das Löschen steht jeweils zu Beginn > andi r16, 0xFC
Gast
#4105824
Eine weitere Variante mit 5 Takten könnte ich anbieten:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
Vorteil: keine weiteren Resourcen nötig, weder Register noch Flags Nachteile: 'schwammiges' Zeitverhalten, am Ende ist src nicht 0
Gast
#4105825
Und jetzt wäre es schön, wenn ich editieren könnte: Entschuldigung, das sind natürlich 2*5= 10 Takte pro Block.
S. Landolt schrieb: > Für das Löschen steht jeweils zu Beginn >> andi r16, 0xFC Ja, damit löschst du aber nur die zwei niedrigsten bits:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
Klarer ?
Gast
#4105854
Ja, danke für die Erklärung.
S. Landolt schrieb: > Ja, danke für die Erklärung. Nur ist das in seiner Version nicht anders.
Gast
#4105925
Das ist schön, dann sind wir wenigstens zu dritt.
Gast
#4105966
Die wollen zum Mars fliegen und können noch nicht mal Prozessoren designen, die unabhängig vom Problem immer nur einen Takt brauchen... tsts..
Gast
#4105977
> C macht daraus jedoch mov, andi, or, out, lsr, lsr > Der IN Befehl wird nur einmal gebraucht. Pardon, ich verstehe immer weniger, mag daran liegen, dass ich kaum C kann. Sowohl Marc Vesely als auch A.K. machen zu Beginn ein in r16,PORTB wo finde ich das in der Eingangsfragestellung? Für mich sieht es so aus, als würden die PORTB-Bits 7..2 immer gesetzt.
S. Landolt schrieb: > wo finde ich das in der Eingangsfragestellung? uint portB00 = PORTB & 0b11111100; => IN r16, PORTB ANDI r16, 0xFC > Für mich sieht es so aus, > als würden die PORTB-Bits 7..2 immer gesetzt. Nein, hier nicht: PORTB = portB00 | (src & 0b00000011); => MOV r17, src ANDI r17, 3 OR r17, r16 OUT PORTB, r17
Gast
#4105997
Also in der Summe 26 Takte, ohne allfällige push/pop. Mir reicht's erstmal, einen schönen Abend allerseits.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.