Zwei Bits in maximal 4 Takten kopieren

OP #4105503
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....
#4105573
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.
#4105738
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.
(Firma: Vescomp) #4105770
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.
Gast #4105784
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
Gast #4105824
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
(Firma: Vescomp) #4105836
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 ?
Gast #4105977
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren