2008-12-07 9 views
7

Mam 32-bitowe (szesnastkowe) słowo 0xaabbccdd i muszę zamienić 2. i 3. bajt. w końcu powinno to wyglądać jak 0xaaccbbddJak zamaskować bajty w zespole ARM?

jak mogę "zamaskować" drugi i trzeci bajt, aby najpierw załadować je do rejestru r1 i r2 i zamienić je .. wiem też, że muszę pracować z Polecenia lsl i lsr, ale nie wiem od czego zacząć.

Przepraszam za mój zły angielski.hope ktoś może mi pomóc!

pozdrowienia, Sebastian

Odpowiedz

6

To nie jest prostym zadaniem w zespole ramienia, ponieważ nie można łatwo korzystać z 32-bitowych stałych. Musisz rozbić wszystkie operacje, które maskują bajty, aby użyć 8-bitowych stałych (również te stałe można obracać).

Maskujesz bajt2 i 3 za pomocą instrukcji AND i wykonujesz przesunięcie później. w asemblerze ARM masz większość instrukcji jedną zmianę za darmo, więc przesunięcie w pozycję i połączenie z innymi bitami często kończy się jako pojedyncza instrukcja.

Oto niesprawdzone kod, który robi swap środkowy bajt (ARMv4 nie kciukiem zestaw instrukcji):

 .text 

swap_v4: 
     AND  R2, R0, #0x00ff0000  @ R2=0x00BB0000 get byte 2 
     AND  R3, R0, #0x0000ff00  @ R3=0x0000CC00 get byte 1 
     BIC  R0, R0, #0x00ff0000  @ R0=0xAA00CCDD clear byte 2 
     BIC  R0, R0, #0x0000ff00  @ R0=0xAA0000DD clear byte 1 
     ORR  R0, R2, LSR #8   @ R0=0xAA00BBDD merge and shift byte 2 
     ORR  R0, R3, LSL #8   @ R0=0xAACCBBDD merge and shift byte 1 
     B  LR 

To przetłumaczyć wiersz po wierszu w następujący c-Code:

int swap (int R0) 
{ 
    int R2,R3; 
    R2 = R0 & 0x00ff0000; 
    R3 = R0 & 0x0000ff00; 
    R0 = R0 & 0xff00ffff; 
    R0 = R0 & 0xffff00ff; 
    R0 |= (R2>>8); 
    R0 |= (R3<<8); 
    return R0; 
} 

Zobaczysz - wiele linii do tak prostego zadania. Nawet architektura ARMv6 nie pomaga tutaj wiele.


EDIT: wersja ARMv6 (również niesprawdzone, ale dwie instrukcje krótsze)

swap_v6: 
     @ bits in R0: aabbccdd 
     ROR  R0, R0, #8    @ r0 = ddaabbcc 
     REV  R1, R0     @ r1 = ccbbaadd 
     PKHTB R0, R0, R1    @ r0 = ddaaccbb 
     ROR  R0, R0, #24    @ r0 = aaccbbdd 
     BX  LR 
+0

Uh, nie jest to, że za pomocą 32-bitowych stałych, w pierwszym przykładzie? Mylące. – unwind

+1

Tak, są to stałe 32-bitowe, ale jeśli przyjrzeć się bliżej, mają tylko 8 kolejnych bitów używanych w ich stałych. ARM może wykonać 8 bitów, ale ich położenie można dowolnie obracać w wybrane miejsce. Asembler jest wystarczająco inteligentny, aby zakodować dla ciebie stałe. –

+2

dowolne * nawet * miejsce, które chcesz; 0x1fe nie jest reprezentowalny natychmiast, na przykład, ale 0x3fc jest. –

0

Ty vould wystarczy użyć wskazówek, aby zamienić dwa bajty

static union { 
BYTE BBuf[4]; 
WORD WWBuf[2]; 
DWORD DWBuf; 
}swap; 

unsigned char *a; 
unsigned char *b; 
swap.DWBuf = 0xaabbccdd; 

a = &swap.BBuf[1]; 
b = &swap.BBuf[2]; 

*a ^= *b; 
*b ^= *a; 
*a ^= *b; 

A teraz wynik jest

swap.DWbuf == 0xaaccbbdd; 
2

H mmm, nie wiem co się stało, przedłożyłem moją odpowiedź, zanim naprawdę zacząłem.

Na początku nie sądziłem, że mogę to zrobić tylko z dwoma rejestrami, ale potem zdecydowałem, że mogę i zrobiłem. Rozwiązania te są tylko rejestrem, bez pamięci (inne niż ldr r0, = które można zastąpić czterema instrukcjami). Jeśli używasz pamięci i hmmm, dwa rejestry możesz zmniejszyć liczbę instrukcji być może: str, bic, bic, ldrb, orr lsl, ldrb, orr lsl. Okay Zrobiłem to w jednej instrukcji mniej, ale potem potrzebujesz miejsca w pamięci i cykli kosztowych sklepów i obciążeń, tyle samo pamięci i więcej cykli, aby zrobić to z pamięcią. Ktoś inny może mieć dobre sztuczki. Myślę, że niektóre z nowszych rdzeni mają instrukcję zamiany końcówek, co jeszcze bardziej ułatwiłoby pracę.

.globl midswap 
midswap: 
    mov r2,r0,lsl #8  ;@ r2 = BBCCDDAA 
    mov r3,r0,lsr #8  ;@ r3 = DDAABBCC (this might drag a sign bit, dont care) 
    and r2,r2,#0x00FF0000 ;@ r2 = 00CC0000 
    and r3,r3,#0x0000FF00 ;@ r3 = 0000BB00 
    bic r0,r0,#0x00FF0000 ;@ r0 = AA00CCDD 
    bic r0,r0,#0x0000FF00 ;@ r0 = AA0000DD 
    orr r0,r0,r2   ;@ r0 = AACC00DD 
    orr r0,r0,r3   ;@ r0 = AACCBBDD 
    bx lr ;@ or mov pc,lr for older arm cores 


.globl tworegs 
tworegs: 
    mov r2,r0,ror #8  ;@ r2 = DDAABBCC 
    bic r2,r2,#0xFF000000 ;@ r2 = 00AABBCC 
    bic r2,r2,#0x00FF0000 ;@ r2 = 0000BBCC 
    orr r2,r2,ror #16  ;@ r2 = BBCCBBCC 
    bic r2,r2,#0xFF000000 ;@ r2 = 00CCBBCC 
    bic r2,r2,#0x000000FF ;@ r2 = 00CCBB00 
    bic r0,r0,#0x00FF0000 ;@ r0 = AA00CCDD 
    bic r0,r0,#0x0000FF00 ;@ r0 = AA0000DD 
    orr r0,r0,r2   ;@ r0 = AACCBBDD 
    bx lr 

testfun: 
    ldr r0,=0xAABBCCDD 
    bl midswap 
8

Wracając do dnia, w którym używaliśmy tego rodzaju oszustwa, często polegaliśmy na EOR.

Możesz to zrobić w 4 cyklach.

Po pierwsze, musimy fakt, że: a^(A^B) = B

Zaczniemy 0xAABBCCDD i chcemy 0xAACCBBDD. Aby się tam dostać, potrzebujemy 0x00EEEE00^0xAABBCCDD, gdzie EE = BB^CC.

Teraz musimy kilka cykli zbudować 00EEEE00:

eor  r1,r0,r0,lsr #8 
and  r1,r1,#0xFF00 
orr  r1,r1,r1,lsl #8 
eor  r0,r0,r1 

w C:

t=x^(x>>8); 
t=t&0xFF00; 
t=t|(t<<8); 
x^=t; 

po każdym wierszu, wynik obliczany jest: zaczynające się od: AABBCCDD

eor XXXXEEXX 
and 0000EE00 
orr 00EEEE00 
eor AACCBBDD 

Będzie to działać na każdym 32-bitowym rdzeniu ARM.

0

można używać BFI i UBFX będą one ułatwić zadanie