Façons de diviser le haut/bas d'octets à partir d'un 16 bits de l'adresse?

Je suis le développement d'un logiciel sur 8051 processeur. Un fréquent emploi est de diviser le haut et l'octet de poids faible de 16 bits de l'adresse. Je veux le voir il y a combien de façons d'y parvenir. Les façons je viens de monter jusqu'à présent sont: (dire que le ptr est un 16bit pointeur, et l'int est 16bit int) [note de l'ia et de l'arn est registres]

opération au niveau du bit

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

SDCC donne à l'assemblée suivante de 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 me donne:


                                           ; 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

qui a beaucoup de code inutile à mon humble avis.

pointeur truc


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

SDCC me donne:


;   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 me donne:


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

qui est la même chose avec SDCC version.

Andrey de mathématiques approche


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

SDCC donne:


;   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

Je n'ai aucune idée pourquoi sdcc utiliser le registre r7...
Keil C51 me donne:


                                           ; 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

Je n'ai aucune idée pourquoi Keil utilisation R2 registre ni...

semaj de l'approche de l'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 me donne


;   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 me donne:


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

ce qui est très smiler pour les pointeurs truc. Cependant, cette approche nécessite plus de deux octets de mémoire que le magasin de l'union.

Quelqu'un at-il d'autres idées lumineuses? 😉

Et quelqu'un peut me dire qui est plus efficace?

Dans le cas où toute personne intéressée, ici, c'est le cas de test:


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);
}

}

"quelqu'un peut me dire où est le plus efficace". Puisque vous avez le 8051 compilateur là, et je n'ai pas, que diriez-vous post le démontage de chaque option, donner à d'autres sportives, à l'occasion de formuler des commentaires sur l'efficacité 😉
Merci pour l'astuce. J'espère qu'il y est une façon de "voir asm de code C code". Mais comme vous l'avez demandé, je vais télécharger le code asm demain.
Pour plus d'efficacité, vous devez connaître le nombre de cycles de chaque instruction concernés (1 ou 2 dans chaque cas). 8052.com/51mov a la liste, mais c'est un pain PITA de travail pour votre SDCC assemblée, puisqu'il n'a pas de liste les opcodes, de sorte que vous avez à comprendre la variante de MOV chaque instruction est. Aussi méfiez-vous lors de la comparaison des variantes de code que l'utilisation de différents registres, que le morceau de code que vous regardez peut avoir des répercussions sur d'autres morceaux de code. Comme vous le dites, certaines versions utilisent de plus les registres que vous attendez, sans doute pour une raison...
Donc, en résumé, peut-être plus facile de le tester. Peut-être sur un simulateur.

OriginalL'auteur Grissiom | 2010-03-29