Möglichkeiten zum aufteilen der high/low byte aus einem 16-bit-Adresse?

Ich entwickle eine software, die auf dem 8051-Prozessor. Eine häufige Aufgabe ist zum teilen des high-und low-byte eines 16-bit-Adresse. Ich will sehen, es gibt, wie viele Möglichkeiten, es zu erreichen. Die Möglichkeiten, die ich kommen so weit sind: (sagen ptr ist ein 16-bit-Zeiger und int ist 16bit int) [Hinweis: die rn und arn ist registriert]

bitweise operation

ADDH = (unsigned int) ptr >> 8;
ADDL = (unsigned int) ptr & 0x00FF;

SDCC gibt die folgenden Assembler-code


;   t.c:32: ADDH = (unsigned int) ptr >> 8;
    mov ar6,r3
    mov ar7,r4
    mov _main_ADDH_1_1,r7
;   t.c:33: ADDL = (unsigned int) ptr & 0x00FF;
    mov _main_ADDL_1_1,r6

Keil C51 gibt mir:


                                           ; SOURCE LINE # 32
0045 AA00        R     MOV     R2,ptr+01H
0047 A900        R     MOV     R1,ptr+02H
0049 AE02              MOV     R6,AR2
004B EE                MOV     A,R6
004C F500        R     MOV     ADDH,A
                                           ; SOURCE LINE # 33
004E AF01              MOV     R7,AR1
0050 EF                MOV     A,R7
0051 F500        R     MOV     ADDL,A

die vielen nutzlosen code IMHO.

Zeiger trick


ADDH = ((unsigned char *)&ptr)[0];
ADDL = ((unsigned char *)&ptr)[1];

SDCC gibt mir:


;   t.c:37: ADDH = ((unsigned char *)&ptr)[0];
    mov _main_ADDH_1_1,_main_ptr_1_1
;   t.c:38: ADDL = ((unsigned char *)&ptr)[1];
    mov _main_ADDL_1_1,(_main_ptr_1_1 + 0x0001)

Keil C51 gibt mir:


                                           ; SOURCE LINE # 37
006A 850000      R     MOV     ADDH,ptr
                                           ; SOURCE LINE # 38
006D 850000      R     MOV     ADDL,ptr+01H

das ist das gleiche mit SDCC version.

Andrey ' s mathematische Ansatz


 ADDH = ptr / 256;
 ADDL = ptr % 256;

SDCC gibt:


;   t.c:42: ADDH = (unsigned int)ptr / 256;
    mov ar5,r3
    mov ar6,r4
    mov ar7,r6
    mov _main_ADDH_1_1,r7
;   t.c:43: ADDL = (unsigned int)ptr % 256;
    mov _main_ADDL_1_1,r5

Ich habe keine Ahnung, warum sdcc verwenden Sie das register r7...
Keil C51 gibt mir:


                                           ; SOURCE LINE # 42
0079 AE00        R     MOV     R6,ptr
007B AF00        R     MOV     R7,ptr+01H
007D AA06              MOV     R2,AR6
007F EA                MOV     A,R2
0080 F500        R     MOV     ADDH,A
                                           ; SOURCE LINE # 43
0082 8F00        R     MOV     ADDL,R7

Ich habe keine Ahnung, warum Keil verwenden Sie das register R2 weder...

semaj das Konzept der union


typedef union
   {
   unsigned short u16;
   unsigned char u8[2];
   } U16_U8;

U16_U8 ptr;

//Do something to set the variable ptr ptr.u16 = ?;

ADDH = ptr.u8[0]; ADDL = ptr.u8[1];

SDCC gibt mir


;   t.c:26: ADDH = uptr.u8[0];
    mov _main_ADDH_1_1,_main_uptr_1_1
;   t.c:27: ADDL = uptr.u8[1];
    mov _main_ADDL_1_1,(_main_uptr_1_1 + 0x0001)

Keil C51 gibt mir:


                                           ; SOURCE LINE # 26
0028 850000      R     MOV     ADDH,uptr
                                           ; SOURCE LINE # 27
002B 850000      R     MOV     ADDL,uptr+01H

das ist sehr smiler auf den Zeiger trick. Allerdings ist dieser Ansatz erfordert zwei bytes mehr Speicher das speichern der union.

Hat jemand irgendwelche anderen Ideen? 😉

Und jemand kann mir sagen, welche Möglichkeit die effizientere ist?

Falls es jemanden interessiert, hier ist der test-Fall:


typedef union
{
    unsigned short u16;
    unsigned char u8[2];
} U16_U8;

//call a function on the ADDs to avoid optimizition void swap(unsigned char *a, unsigned char *b) { unsigned char tm; tm = *a; *a = *b; *b = tm; }

main (void) { char c[] = "hello world."; unsigned char xdata *ptr = (unsigned char xdata *)c; unsigned char ADDH, ADDL; unsigned char i = 0;

U16_U8 uptr;
uptr.u16 = (unsigned short)ptr;

for ( ; i < 4 ; i++, uptr.u16++){
    ADDH = uptr.u8[0];
    ADDL = uptr.u8[1];
    swap(&ADDH, &ADDL);
}

for ( ; i < 4 ; i++, ptr++){
    ADDH = (unsigned int) ptr >> 8;
    ADDL = (unsigned int) ptr & 0x00FF;
    swap(&ADDH, &ADDL);
}
for ( ; i < 4 ; i++, ptr++){
    ADDH = ((unsigned char *)&ptr)[0];
    ADDL = ((unsigned char *)&ptr)[1];
    swap(&ADDH, &ADDL);
}
for ( ; i < 4 ; i++, ptr++){
    ADDH = (unsigned int)ptr / 256;
    ADDL = (unsigned int)ptr % 256;
    swap(&ADDH, &ADDL);
}

}

"wer kann mir sagen, welche Möglichkeit die effizientere ist". Da hast du die 8051-compiler Recht gibt, und ich weiß nicht, wie über Sie post von der Demontage der einzelnen option, um es anderen zu geben eine sportliche chance zu kommentieren auf den Wirkungsgrad 😉
Danke für den Tipp. Ich hoffe, es ist ein Weg, um zu "sehen asm-code aus C-code". Aber als Sie fragte, werde ich hochladen, den asm-code von morgen.
Für die Effizienz, die Sie brauchen zu wissen, der Zyklus Anzahl der jeweiligen Unterricht beteiligt sind (1 oder 2 in jedem Fall). 8052.com/51mov hat die Liste, aber es ist ein PITA zu arbeiten für Ihre SDCC Montage, da es keine Liste der opcodes, so dass Sie haben, um herauszufinden, welche Variante von MOV jede Anweisung ist. Auch Vorsicht beim Vergleich von code-Varianten, die unterschiedliche Register, dass das Stück code, die Sie eigentlich suchen, bei haben kann knock-on-Effekte auf die anderen bits des Codes. Wie Sie sagen, einige Versionen sind mit mehr Register, als man erwarten würde, vermutlich für eine tatsächliche Grund...
So, in Zusammenfassung, ist vielleicht einfacher, nur um es zu testen. Vielleicht auf einem simulator.

InformationsquelleAutor Grissiom | 2010-03-29

Schreibe einen Kommentar