Forum: Mikrocontroller und Digitale Elektronik Zwei Bits in maximal 4 Takten kopieren


von Christian (dragony)


Lesenswert?

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....

von Kaj G. (Firma: RUB) (bloody)


Lesenswert?

Möchtest du vielleicht noch sagen um welchen Mikrocontroller es sich 
handelt?

von Wolfgang (Gast)


Lesenswert?

Christian S. schrieb:
> Kennt jemand einen Trick?
(Inline) Assembler?

von Christian (dragony)


Lesenswert?

Kaj G. schrieb:
> Möchtest du vielleicht noch sagen um welchen Mikrocontroller es sich
> handelt?

Sorry. Geht um den ATtiny84A-PU.

von Rolf M. (rmagnus)


Lesenswert?

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.

von Christian (dragony)


Lesenswert?

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...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
  in    r16, PortB
2
  andi  r16, 0xFC
3
  or    r16, SrcReg
4
  out   PortB, r16
5
  lsr   SrcReg
6
  lsr   SrcReg

von Christian (dragony)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

Marc Vesely schrieb:
>  Der Compiler hat schon ausgetrickst, schneller geht es nicht.

Doch. Der IN Befehl wird nur einmal gebraucht.
1
  in    r16, PortB
2
3
  andi  r16, 0xFC
4
  or    r16, SrcReg
5
  out   PortB, r16
6
  lsr   SrcReg
7
  lsr   SrcReg
8
9
  andi  r16, 0xFC
10
  or    r16, SrcReg
11
  out   PortB, r16
12
  lsr   SrcReg
13
  lsr   SrcReg
14
15
  andi  r16, 0xFC
16
  or    r16, SrcReg
17
  out   PortB, r16
18
  lsr   SrcReg
19
  lsr   SrcReg
20
21
  andi  r16, 0xFC
22
  or    r16, SrcReg
23
  out   PortB, r16

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.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

von S. Landolt (Gast)


Lesenswert?

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

von S. Landolt (Gast)


Lesenswert?

Eine weitere Variante mit 5 Takten könnte ich anbieten:
1
  sbrs  src,0
2
   cbi  PORTB,0
3
  sbrc  src,0
4
   sbi  PORTB,0
5
  sbrs  src,1
6
   cbi  PORTB,1
7
  sbrc  src,1
8
   sbi  PORTB,1
9
10
  sbrs  src,2
11
   cbi  PORTB,0
12
  sbrc  src,2
13
   sbi  PORTB,0
14
  sbrs  src,3
15
   cbi  PORTB,1
16
  sbrc  src,3
17
   sbi  PORTB,1
18
;...
19
;...

Vorteil: keine weiteren Resourcen nötig, weder Register noch Flags
Nachteile: 'schwammiges' Zeitverhalten, am Ende ist src nicht 0

von S. Landolt (Gast)


Lesenswert?

Und jetzt wäre es schön, wenn ich editieren könnte: Entschuldigung, das 
sind natürlich 2*5= 10 Takte pro Block.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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
 SrcReg = 0x11000011   r16 = 0x yyyyyy00
2
        OR r16, SrcReg
3
 SrcReg = 0x11000011   r16 = 0x 11yyyy11
4
        lsr  SrcReg
5
        lsr  SrcReg
6
        andi r16, 0xFC
7
 SrcReg = 0x00110000   r16 = 0x 11yyyy00
8
       OR r16, SrcReg
9
 SrcReg = 0x00110000   r16 = 0x 1111yy00
10
        lsr  SrcReg
11
        lsr  SrcReg
12
        andi r16, 0xFC
13
 SrcReg = 0x00001100   r16 = 0x 1111yy00
14
       OR r16, SrcReg
15
 SrcReg = 0x00001100   r16 = 0x 11111100
16
        lsr  SrcReg
17
        lsr  SrcReg
18
        andi r16, 0xFC
19
 SrcReg = 0x00000011   r16 = 0x 11111100
20
       OR r16, SrcReg
21
 SrcReg = 0x00000011   r16 = 0x 11111111

 Klarer ?

von S. Landolt (Gast)


Lesenswert?

Ja, danke für die Erklärung.

von (prx) A. K. (prx)


Lesenswert?

S. Landolt schrieb:
> Ja, danke für die Erklärung.

Nur ist das in seiner Version nicht anders.

von S. Landolt (Gast)


Lesenswert?

Das ist schön, dann sind wir wenigstens zu dritt.

von Simpel (Gast)


Lesenswert?

Die wollen zum Mars fliegen und können noch nicht mal Prozessoren 
designen, die unabhängig vom Problem immer nur einen Takt brauchen... 
tsts..

von S. Landolt (Gast)


Lesenswert?

> 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.

von (prx) A. K. (prx)


Lesenswert?

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

von S. Landolt (Gast)


Lesenswert?

Also in der Summe 26 Takte, ohne allfällige push/pop.
Mir reicht's erstmal, einen schönen Abend allerseits.

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.