28 votes

Différences entre les architectures ARM du point de vue d'un programmeur C ?

Je suis assez novice en matière de programmation pour ARM. J'ai remarqué qu'il y a plusieurs architectures comme ARMv4, ARMv5, ARMv6, etc. Quelle est la différence entre ces architectures ? Ont-elles des jeux d'instructions ou des comportements différents ?

Plus important encore, si je compile un code C pour ARMv6, fonctionnera-t-il sur ARMv5 ? Et qu'en est-il du code ARMv5 exécuté sur ARMv6 ? Ou dois-je me préoccuper de la différence uniquement si j'écris du code assembleur de noyau ?

31voto

Thomas Pornin Points 36984

Le monde ARM est un peu désordonné.

Pour les programmeurs C, les choses sont simples : toutes les architectures ARM offrent un modèle de programmation régulier, 32 bits avec adressage plat. Tant que vous restez avec le code source C, la seule différence que vous pouvez voir concerne l'adressage et les performances. La plupart des processeurs ARM (même les anciens modèles) peuvent être à la fois big-endian et little-endian ; le choix est alors fait par la carte logique et le système d'exploitation. Un bon code C est neutre endienne La neutralité endienne est une bonne chose pour la fiabilité et la maintenabilité, mais aussi pour les performances : un code non neutre est un code qui accède aux mêmes données par des pointeurs de tailles différentes, ce qui nuit aux règles strictes d'aliasing que le compilateur utilise pour optimiser le code.

La situation est tout à fait différente si l'on considère binaire la compatibilité (c'est-à-dire la réutilisation d'un code qui a été compilé une fois) :


  • Il existe plusieurs jeux d'instructions :
    1. le jeu d'instructions ARM original avec un compteur de programme de 26 bits (très ancien, très peu susceptible d'être rencontré de nos jours)
    2. le jeu d'instructions ARM avec un compteur de programme de 32 bits (souvent appelé "code ARM")
    3. le jeu d'instructions Thumb (opcodes simplifiés de 16 bits)
    4. le jeu d'instructions Thumb-2 (Thumb avec extensions)

Un processeur donné peut mettre en œuvre plusieurs jeux d'instructions. Le processeur le plus récent qui ne connaît que le code ARM est le StrongARM, un représentant de l'ARMv4 qui est déjà assez vieux (15 ans). L'ARM7TDMI (architecture ARMv4T) connaît à la fois ARM et Thumb, comme presque tous les systèmes ARM ultérieurs, à l'exception du Cortex-M. Les codes ARM et Thumb peuvent être mélangés au sein d'une même application, à condition d'insérer la colle appropriée là où les conventions changent ; c'est ce que l'on appelle l'interfonctionnement des pouces et peut être géré automatiquement par le compilateur C.

Le Cortex-M0 ne connaît que les instructions Thumb. Il connaît quelques extensions, car dans les processeurs ARM "normaux", le système d'exploitation doit utiliser du code ARM (pour gérer les interruptions) ; ainsi, le Cortex-M0 connaît quelques éléments Thumb pour le système d'exploitation. Cela n'a pas d'importance pour le code d'application.

Les autres Cortex-M ne connaissent que le pouce 2. Le pouce 2 est principalement rétrocompatible avec Thumb, au moins au niveau de l'assemblage.


  • Certaines architectures ajoutent des instructions supplémentaires.

Ainsi, si un code est compilé avec un commutateur de compilateur indiquant que c'est pour un ARMv6, alors le compilateur peut utiliser une des quelques instructions avec l'ARMv6 a mais pas l'ARMv5. C'est une situation courante, rencontrée sur presque toutes les plateformes : par exemple, si vous compilez du code C sur un PC, avec GCC, en utilisant l'option -march=core2 le binaire résultant peut ne pas fonctionner sur un ancien processeur Pentium.


  • Il existe plusieurs conventions d'appel.

La convention d'appel est l'ensemble des règles qui spécifient comment les fonctions échangent des paramètres et des valeurs de retour. Le processeur ne connaît que ses registres, et n'a aucune notion de pile. La convention d'appel indique dans quels registres vont les paramètres, et comment ils sont codés (par exemple, s'il y a un paramètre de retour dans le processeur). char il est placé dans les 8 bits inférieurs d'un registre, mais l'appelant est-il censé effacer/étendre les 24 bits supérieurs, ou non ?) Il décrit la structure et l'alignement de la pile. Il normalise les conditions d'alignement et le remplissage des champs de la structure.

Il existe deux conventions principales pour ARM, appelées ATPCS (ancienne) et AAPCS (nouvelle). Elles sont assez différentes en ce qui concerne les valeurs à virgule flottante. Pour les paramètres entiers, elles sont pratiquement identiques (mais AAPCS exige un alignement de pile plus strict). Bien entendu, les conventions varient en fonction du jeu d'instructions et de la présence de l'interfonctionnement du Pouce.

Dans certains cas, il est possible d'avoir un code binaire conforme à la fois à l'ATPCS et à l'AAPCS, mais ce n'est pas fiable et il n'y a pas d'avertissement en cas d'incompatibilité. En résumé, il est impossible d'obtenir une véritable compatibilité binaire entre des systèmes qui utilisent des conventions d'appel distinctes.


  • Il existe des coprocesseurs optionnels.

L'architecture ARM peut être étendue avec des éléments optionnels, qui ajoutent leurs propres instructions au jeu d'instructions de base. Le FPU est un tel coprocesseur optionnel (et il est très rarement rencontré en pratique). Un autre coprocesseur est NEON, un jeu d'instructions SIMD que l'on trouve sur certains des processeurs ARM les plus récents.

Le code qui utilise un coprocesseur ne s'exécutera pas sur un processeur qui ne dispose pas de ce coprocesseur, à moins que le système d'exploitation ne piège les opcodes correspondants et n'émule le coprocesseur en logiciel (c'est plus ou moins ce qui se passe avec les arguments à virgule flottante lorsqu'on utilise la convention d'appel ATPCS, et c'est lent ).


En résumé, si vous avez du code C, recompilez-le. N'essayez pas de réutiliser du code compilé pour une autre architecture ou un autre système.

5voto

dwelch Points 27195

Pensez à ce truc ARM contre ARM comme à un ordinateur wintel contre un mac Intel. Supposez que vous ayez la même puce Intel (famille) sur les deux ordinateurs, donc des parties de votre code C pourraient être compilées une fois et fonctionner sur les deux processeurs sans problème. Où et pourquoi vos programmes varient n'a rien à voir avec le processeur Intel mais tout à voir avec les puces et la carte mère qui l'entourent plus le système d'exploitation dans ce cas.

Avec ARM contre ARM, la plupart des différences ne sont pas le noyau mais la logique spécifique du fournisseur qui entoure le noyau. C'est donc une question chargée, si votre code C est une application appelant des appels d'API standard, il devrait compiler sur ARM, Intel, PowerPC ou autre. Si votre application parle à des périphériques sur puce ou sur carte, alors peu importe le type de processeur, une carte, une puce variera et en conséquence votre code C devra être écrit pour cette puce ou cette carte mère. Si vous compilez un binaire pour ARMv6, il peut avoir et aura des instructions considérées comme non définies sur un ARMv4 et provoquera une exception. Si vous compilez pour ARMv4, le ARMv6 devrait l'exécuter sans problème.

Au mieux, si vous êtes dans cet espace d'application, vous ne verrez probablement que des différences de performances. Certaines d'entre elles sont liées à votre choix d'options de compilation. Et parfois vous pouvez aider avec votre code. Je recommande d'éviter les divisions et la virgule flottante dans la mesure du possible. Je n'aime pas les multiplications mais je prendrai une multiplication au lieu d'une division si on me pousse. Le x86 nous a gâtés avec des accès non alignés, si vous commencez maintenant avec des E/S alignées, cela vous sauvera en cours de route lorsque vous entrerez dans d'autres puces qui préfèrent aussi les accès alignés, et ou vous vous ferez piquer par les différents systèmes d'exploitation et chargeurs de démarrage qui configurent l'ARM pour réagir, rien de tout cela n'est ce à quoi vous étiez habitué sur un x86. De même, gardez cette habitude et votre code x86 s'exécutera beaucoup plus rapidement.

Obtenez une copie de l'ARM ARM (google : ARM Architectural Reference Manual, vous pouvez le télécharger gratuitement à plusieurs endroits, je ne sais pas quelle est la version actuelle, rev I ou quelque chose comme ça peut-être). Parcourez le jeu d'instructions ARM et voyez que la plupart des instructions sont supportées par tous les cœurs, et que certaines ont été ajoutées au fil du temps, comme la division et le byteswap, etc. Vous verrez qu'il n'y a rien à craindre entre les cœurs.

Pensez du point de vue des systèmes, le wintel contre le mac intel. ARM ne fabrique pas de puces, mais des cœurs et des licences. La plupart des vendeurs qui utilisent un ARM dans leur puce ont leur propre sauce spéciale autour de celui-ci. C'est donc comme le wintel contre le mac avec le même processeur au milieu, mais complètement différent quand il s'agit de tout ce que le processeur touche et doit utiliser. Cela ne s'arrête pas au noyau ARM, ARM vend des périphériques, des unités à virgule flottante, des caches, etc. Ainsi, peu ou pas d'ARMv4 sont identiques, par exemple. Si votre code touche les différences, vous aurez des problèmes, sinon vous n'en aurez pas.

Pour les portions de bras de la puce, en plus de l'ARM ARM, il existe des TRM (Technical Reference Manuals). Mais si vous obtenez le mauvais trm pour le composant que vous utilisez, cela peut vous donner des maux de tête. Le TRM peut avoir des descriptions de registres et d'autres choses que l'ARM ARM n'a pas, mais si vous vivez dans un espace d'application, vous n'aurez probablement besoin d'aucun d'entre eux, ni de l'ARM ARM. L'ARM ARM est bon à des fins éducatives si rien d'autre. Comprendre pourquoi vous pourriez ne pas vouloir diviser ou utiliser des accès non alignés.

4voto

Yann Ramin Points 25139

Le système ARM lui-même est assez compatible, à condition que vous vous en teniez au code utilisateur (le code du noyau est bien sûr différent). Dans un environnement d'OS hébergé, vous vous en tiendrez probablement à ARMv5 (processeurs ARM926).

La grande différence vient de :

  1. Le comportement des caches est très différent. Sur certains ARM, le cache est même virtuellement adressé, ce qui peut rendre les changements de processus douloureux.
  2. La FPU existe en plusieurs versions (VFP, NEON, etc.). De nombreux petits processeurs n'ont même pas de FPU.
  3. Le mode pouce a changé de façon spectaculaire. Le mode pouce entre ARMv5 n'est pas portable vers Thumb2 (ARMv6+), ni compatible en arrière.

3voto

Karl Knechtel Points 24349

Si la différence est vraiment si importante pour vous, vous devriez être en mesure de la découvrir dans la documentation publique d'ARM.

Mais l'intérêt d'écrire dans un langage de haut niveau (même s'il n'est qu'aussi "élevé" que le C) est de ne pas s'en inquiéter . Tout ce que vous devez faire est recompiler . Même au sein du noyau, il n'est pas nécessaire d'écrire beaucoup de choses en assembleur, et lorsque c'est le cas, il n'est pas nécessaire d'écrire en assembleur. doivent écrire quelque chose en assembleur (c'est-à-dire pas seulement pour obtenir des performances maximales), c'est typiquement à cause de plus que le simple choix de l'unité centrale (par exemple, qu'est-ce qui a été directement mappé en mémoire où ?)

2voto

auselen Points 13961

Liste très rapide et sale des domaines à vérifier lors du portage entre architectures en général :

  • Endianness Utilisation des unions, moulage des types de données, champs de bits, partage des données.
  • Alignement : exigences d'alignement mais aussi caractéristiques de performance d'un éventuel accès non aligné
  • Modèle de mémoire : faible vs fort ?
  • Multi-core : comment fonctionne la cohérence ?
  • Divers : types de données signés et non signés, emballage des structures de données, utilisation de la pile, type de données enum...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X