Intel décode en interne les instructions CISC en instructions RISC depuis leur architecture Skylake (?) Et AMD le fait depuis leurs processeurs K5. Cela signifie-t-il que les instructions x86 sont traduites en un ISA RISC interne étrange pendant l'exécution? Si c'est ce qui se passe, alors je me demande s'il est possible de créer un processeur qui comprend (c'est-à-dire se traduit en interne par ses propres instructions propriétaires) les instructions x86 et ARM. Si cela est possible, à quoi ressemblerait la performance? Et pourquoi cela n'a-t-il pas déjà été fait?

-1
Rithik Kumar 16 août 2020 à 21:46

2 réponses

Meilleure réponse

Plus les normes ISA sont différentes, plus ce serait difficile. Et plus cela coûterait cher, en particulier le back-end. Ce n'est pas aussi facile que de gifler un frontal différent sur une conception de microarchitecture back-end commune.

S'il s'agissait juste d'un coût de zone de dé pour différents décodeurs, et non d'autres différences de puissance ou de performances, ce serait mineur et totalement viable de nos jours, avec de gros budgets de transistors. (Prendre de la place dans une partie critique de la puce qui place les choses importantes plus loin les unes des autres est toujours un coût, mais il est peu probable que ce soit un problème dans le front-end). L'horloge ou même le déclenchement de l'alimentation peut éteindre complètement le décodeur qui n'est pas utilisé. Mais comme je l'ai dit, ce n'est pas aussi simple car le back-end doit être conçu pour prendre en charge les instructions de l'ISA et d'autres règles / fonctionnalités; Les processeurs ne décodent pas en un back-end RISC entièrement générique / neutre. En relation: Pourquoi Intel cache le RISC interne core dans leurs processeurs? a quelques réflexions et informations sur ce à quoi ressemblent les uops internes de type RISC dans les conceptions Intel modernes.

L'ajout de la capacité de support ARM à Skylake, par exemple, le rendrait plus lent et moins économe en énergie lors de l'exécution de code x86 pur, ainsi que coûterait plus de zone de découpe. Cela n'en vaut pas la peine sur le plan commercial, étant donné le marché limité pour cela et la nécessité d'un système d'exploitation ou d'un logiciel hyperviseur spécial pour même en profiter. (Bien que cela puisse commencer à changer avec AArch64 devenant plus pertinent grâce à Apple.)

Un processeur capable d'exécuter à la fois du code ARM et x86 serait bien pire à l'un ou l'autre qu'une conception pure qui n'en gère qu'un.

  • l'exécution efficace d'ARM 32 bits nécessite la prise en charge d'une exécution entièrement prédéfinie, y compris la suppression des erreurs pour les charges / magasins. (Contrairement à AArch64 ou x86, qui n'ont que des instructions de type ALU-select comme csinc vs cmov / setcc qui ont juste une dépendance de données normale sur FLAGS ainsi que leurs autres entrées.)

  • ARM et AArch64 (en particulier les shuffles SIMD) ont plusieurs instructions qui produisent 2 sorties, alors que presque toutes les instructions x86 n'écrivent qu'un seul registre de sortie. Ainsi, les microarchitectures x86 sont conçues pour suivre les uops qui lisent jusqu'à 3 entrées (2 avant Haswell / Broadwell) et n'écrivent qu'une sortie (ou 1 reg + EFLAGS).

  • x86 nécessite le suivi des composants séparés d'une instruction CISC, par ex. la charge et l'ALU uops pour un opérande de source de mémoire, ou la charge, l'ALU et le stockage pour une destination de mémoire.

  • x86 nécessite des caches d'instructions cohérentes , et la recherche de magasins qui modifient les instructions déjà récupérées et en cours de vol dans le pipeline, ou un moyen de gérer au moins les garanties ISA du code auto-modifiable de x86 (Observation de la récupération d'instructions obsolètes sur x86 avec un code auto-modifiable ) .

  • x86 nécessite un modèle de mémoire fortement ordonné . (ordre de programme + tampon de stockage avec retransmission). Vous devez intégrer cela à vos tampons de chargement et de stockage, donc je m'attends à ce que même lors de l'exécution de code ARM, un tel processeur utilise essentiellement le modèle de mémoire beaucoup plus puissant de x86. (Les processeurs Intel modernes se chargent tôt de manière spéculative et effacent une machine de commande de mémoire en cas de spéculation erronée, alors peut-être que vous pourriez laisser cela se produire et simplement ne pas faire ces armes nucléaires de pipeline. Sauf dans les cas où cela était dû à une erreur -prédire si une charge rechargeait ou non un magasin récent par ce thread; cela doit bien sûr être géré correctement.)

    Un ARM pur pourrait avoir des tampons de chargement / stockage plus simples qui n'interagissent pas autant. (Sauf dans le but de rendre la stlr / ldar sortie / acquisition moins chère, pas seulement complètement stagnante.)

  • Différents formats de table de page. (Vous choisiriez probablement l'un ou l'autre pour le système d'exploitation à utiliser, et ne prendre en charge que l'autre ISA pour l'espace utilisateur sous un noyau natif.)

  • Si vous avez essayé de gérer entièrement les éléments privilégiés / noyau des deux ISA, par exemple afin que vous puissiez avoir la virtualisation HW avec des VM de l'un ou l'autre ISA, vous avez également des éléments tels que des fonctions de registre de contrôle et de débogage.


Cela existe déjà pour d'autres combinaisons d'ISA, notamment AArch64 + ARM , mais aussi x86-64 et 32 ​​bits x86 ont des formats de code machine légèrement différents et un ensemble de registres plus grand. Ces paires d'ISA étaient bien entendu conçues pour être compatibles et pour que les noyaux du nouvel ISA prennent en charge l'exécution de l'ancien ISA en tant que processus d'espace utilisateur.

À l'extrémité la plus simple du spectre, nous avons des processeurs x86-64 qui prennent en charge l'exécution de code machine x86 32 bits (en "mode compat") sous un noyau 64 bits. Ils utilisent pleinement le même pipeline d'extraction / décodage / issue / out-of-order-exec pour tous les modes. Le code machine x86 64 bits est volontairement assez similaire aux modes 16 et 32 ​​bits pour que les mêmes décodeurs puissent être utilisés, avec seulement quelques différences de décodage dépendant du mode. (Comme inc / dec vs préfixe REX.) AMD était intentionnellement très conservateur, malheureusement, laissant de nombreuses verrues mineures x86 inchangées pour le mode 64 bits, afin de garder les décodeurs aussi similaires que possible. (Peut-être qu'au cas où AMD64 n'aurait même pas compris, ils ne voulaient pas être bloqués à dépenser des transistors supplémentaires que les gens n'utiliseraient pas.)

AArch64 et ARM 32 bits sont des formats de code machine distincts avec des différences de codage significatives . par exemple. les opérandes immédiats sont codés différemment et je suppose que la plupart des opcodes sont différents. Vraisemblablement, les pipelines ont 2 blocs de décodeur séparés et le front-end achemine le flux d'instructions à travers l'un ou l'autre selon le mode. Les deux sont relativement faciles à décoder, contrairement à x86, donc c'est probablement bien; aucun des deux blocs ne doit être énorme pour transformer les instructions en un format interne cohérent. Cependant, prendre en charge ARM 32 bits signifie en quelque sorte implémenter un support efficace pour la prédication tout au long du pipeline.

Le premier Itanium (IA-64) avait également un support matériel pour x86, définissant comment l'état du registre x86 mappé sur l'état du registre IA-64. Ces normes ISA sont complètement différentes. Ma compréhension était que le support x86 était plus ou moins "boulonné", avec une zone séparée de la puce dédiée à l'exécution du code machine x86. Les performances étaient mauvaises, pires qu'une bonne émulation logicielle, donc une fois que c'était prêt, les conceptions HW l'ont abandonnée. ( https://en.wikipedia.org/wiki/IA-64#Architectural_changes)

Cela signifie-t-il que les instructions x86 sont traduites en un ISA RISC interne étrange pendant l'exécution?

Oui, mais "RISC ISA" n'est pas similaire à ARM. par exemple. il a toutes les bizarreries de x86, comme des décalages laissant FLAGS inchangés si le compte de décalage est de 0. (Modern Intel gère cela en décodant shl eax, cl à 3 uops; Nehalem et les versions antérieures ont bloqué le front-end si une instruction ultérieure voulait lire les DRAPEAUX d'un quart de travail.)

Les registres partiels x86, comme écrire AL et AH, puis lire EAX, sont probablement un meilleur exemple d'une bizarrerie principale qui doit être prise en charge. Le RAT (table d'allocation de registre) dans le back-end doit suivre tout cela et émettre des uops de fusion ou comment il le gère. (Voir Pourquoi GCC n'utilise pas de registres partiels?).

3
Peter Cordes 17 août 2020 à 06:57

Bref ans. Oui, peut être fait. Voir / Google "microcode mainframe". Oui, cela a été fait avec les mainframes et les minis. Parce que les cpus de nos jours sont hautement optimisés pour leur propre architecture, peu probable pour de bonnes performances si un microcode alternatif. L'expérience montre que l'émulation de cpu x par cpu y dans le microcode est un problème non trivial. En fin de compte, vous devez en savoir plus sur les deux processeurs que sur les concepteurs originaux. Et le paradis vous aide avec les variations de masque. Mieux vaut écrire des émetteurs de niveau supérieur. Voix d'expérience.

0
sys101 20 août 2020 à 16:50