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
Vous devez vous connecter pour publier un commentaire.
Le moyen le plus efficace est complètement dépendant du compilateur. Vous avez certainement de comprendre comment obtenir un assemblage d'inscription à partir de votre compilateur pour un 8051 projet.
Une méthode que vous pouvez essayer qui est similaire à ceux déjà mentionnés est une union:
OriginalL'auteur semaj
Un autre pas si brillante façon de diviser l'adresse:
L'homme, connaissez-vous le coût de la div instructions sur les processeurs comme 8051?
Je ne sais pas ce que les compilateurs pour 8051 sont comme, mais au moins pour un type non signé, je serais étonné si un compilateur C (sur n'importe quelle architecture) qui prétendait à optimiser à tous, émis un code différent pour
ptr / 256
contreptr >> 8
. Je ne peux pas dire ce que insns il utilise, mais il n'est pas difficile pour le compilateur de repérer l'équivalence et de choisir la meilleure. Les valeurs négatives ne sont pas forcément si simple.OriginalL'auteur Anders Westrup
plus efficace est d'abord un, puisqu'il est fait dans une seule instruction.
PAS! J'ai menti à vous, désolé. J'ai oublié que 8051 jeu d'instructions a seulement 1-instructions de décalage de bits. Deuxième devrait être plus rapide, mais le compilateur peut générer du code à la con, alors méfiez-vous et vérifiez le code d'assemblée.
Comment le second générer plusieurs instructions? Ma conjecture est qu'ils sont aussi efficaces
Dépend du compilateur. Le plus simple est de compiler et vérifier l'assemblée
la principale façon je pense qu'un simple compilateur pourrait gâcher 2, c'est qu'il pourrait écrire
ptr
d'un registre sur la pile dans l'ordre de prendre l'adresse, puis lire un char en arrière à partir de la pile. Donc, une écriture et deux lectures pour les deux lignes de code (je l'espère pour mémoire rapide, comme le cache, je ne sais pas le 8051). À l'inverse, la première version du code peut ou ne peut pas, il suffit de faire quelques entier ops. Je remarque que la plupart des 8051 les registres de 8 bits, de sorte que soit l'option pourrait être un no-op: registres pourrait juste être réaffectés, de sorte que le registre qui a été la partie basse de la ptr est maintenant ADDH.la première est lente. voir ma réponse révisée. il n'y a pas de cache à la 8051, mais il est rapide sur la puce de mémoire, qui n'est pas transparent pour le développeur
OriginalL'auteur Andrey
Je viens de créer deux définit(comme suit).
Il me semble plus simple, et moins sujette aux erreurs.
OriginalL'auteur Jim T