2016-10-29 1 views
0

Je vais avoir ce code:AVR GCC, fonctions stub assemblage C, EOR et la valeur constante requise

uint16_t swap_bytes(uint16_t x) 
{ 
    asm volatile(
     "eor, %A0, %B0"  "\n\t" 
     "eor, %B0, %A0"  "\n\t" 
     "eor, %A0, %B0"  "\n\t" 
     : "=r" (x) 
     : "0" (x) 
    ); 
    return x; 
} 

ce qui se traduit (par AVR gcc version 4.8.1 avec -std=gnu99 -save-temps) à:

.global swap_bytes 
    .type swap_bytes, @function 
swap_bytes: 
/* prologue: function */ 
/* frame size = 0 */ 
/* stack size = 0 */ 
.L__stack_usage = 0 
/* #APP */ 
; 43 "..\lib\own\ownlib.c" 1 
    eor, r24, r25 
    eor, r25, r24 
    eor, r24, r25 

; 0 "" 2 
/* #NOAPP */ 
    ret 
    .size swap_bytes, .-swap_bytes 

Mais alors le compilateur se plaint comme ça:

|65|Error: constant value required| 
|65|Error: garbage at end of line| 
|66|Error: constant value required| 
|66|Error: garbage at end of line| 
|67|Error: constant value required| 
|67|Error: garbage at end of line| 
||=== Build failed: 6 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===| 

Les lignes mentionnées sont celles avec les commandes eor. Pourquoi le compilateur a-t-il des problèmes avec ça? Les registres sont même supérieurs (> = r16) où presque toutes les opérations sont possibles. constant value required me semble comme il s'attend à un littéral ... Je ne comprends pas.

+0

gcc a des built-ins pour cela. Pourquoi ne pas les utiliser? Vous êtes de toute façon dépendant du compilateur. Pourquoi ne pas utiliser C simple? – Olaf

+0

Je suis avec Olaf: Utilisez des builtins si vous le pouvez. Cependant, si vous devez utiliser inline asm, je me demande si votre problème est une virgule "extra". Googling pour avr eor retourne 'eor r4, r4' et' eor r0, r22' (notez la virgule après la commande eor). Je ne suis pas un expert avr, mais c'est ce que j'essayerais en premier. –

+0

f # * k! tu as raison. il ne devrait pas y avoir ','. Quoi qu'il en soit, les AVR sont des microcontrôleurs, donc l'espace du programme est restreint. 3 instruction est imbattable pour C. merci encore! – milkpirate

Répondre

0

Juste pour clarifier pour les futurs Googlers:

eor, r24, r25 

a une virgule supplémentaire après l'EOR. Cela devrait être écrit:

eor r24, r25 

Je vous encourage (nouveau) à envisager d'utiliser __builtin_bswap16 gcc. Si vous n'êtes pas familier avec les fonctions 'builtin' de gcc, ce sont des fonctions qui sont intégrées dans le compilateur, et (malgré des fonctions similaires) sont généralement en ligne. Ils ont été écrits et optimisés par des personnes qui comprennent tous les tenants et les aboutissants des différents processeurs et peuvent prendre en compte des choses que vous n'avez peut-être pas envisagées. Je comprends le désir de garder le code aussi petit que possible. Et j'accepte qu'il est possible que (d'une manière ou d'une autre) ce builtin sur votre processeur spécifique produise du code sous-optimal (je suppose que vous avez vérifié?). D'un autre côté, il peut produire exactement le même code. Ou il peut utiliser un truc encore plus intelligent pour le faire. Ou il peut entrelacer les instructions du code environnant pour profiter de pipelining (ou d'une autre chose spécifique avr dont je n'ai jamais entendu parler parce que je ne parle pas 'avr').

De plus, pensez à ce code:

int main() 
{ 
    return __builtin_bswap16(12345); 
} 

Votre code prend toujours 3 des instructions pour traiter un swap. Cependant, avec les builtins, le compilateur peut reconnaître que l'argument est constant et calculer la valeur au moment de la compilation au lieu de l'exécuter. Difficile d'être plus efficace que ça.

Je pourrais également souligner les avantages de "plus facile à soutenir." Ecrire inline asm est dur à faire correctement. Et les futurs mainteneurs détestent le toucher parce qu'ils ne savent jamais très bien comment cela fonctionne. Et bien sûr, le builtin va être plus portable multi-plateforme.

Toujours pas convaincu? Mon dernier pitch: Même après avoir réparé les virgules, votre code asm inline n'est toujours pas correct. Considérez ce code:

int main(int argc, char *argv[]) 
{ 
    return swap_bytes(argc) + swap_bytes(argc); 
} 

En raison de la façon dont vous avez écrit swap_bytes écrite (utilisation volatile), gcc doit calculer la valeur deux fois (voir la définition de volatile). Si vous aviez omis volatile (ou si vous aviez utilisé le builtin qui le fait correctement), il aurait réalisé que argc ne change pas et réutilisé la sortie du premier appel. Ai-je mentionné que écrire correctement en ligne asm est HARD?

Je ne connais pas votre code, vos contraintes, votre niveau d'expertise ou vos exigences. Peut-être que votre solution est vraiment la meilleure. Le plus que je peux faire est de vous encourager à réfléchir longuement avant d'utiliser inline asm dans le code de production.