Le génie des microprocesseurs RISC-V

image


Les guerres entre RISC et CISC à la fin des années 1990 ont disparu depuis longtemps, et on pense aujourd'hui que la différence entre RISC et CISC est totalement hors de propos. De nombreuses personnes affirment que les jeux de commandes ne sont pas pertinents.



Cependant, les jeux de commandes sont en fait importants. Ils imposent des restrictions sur les types d'optimisations qui peuvent ĂȘtre facilement ajoutĂ©s au microprocesseur.



J'ai récemment examiné de plus prÚs les informations sur l'architecture du jeu d'instructions RISC-V (ISA), et voici quelques-uns des aspects qui m'ont vraiment impressionné à propos du RISC-V ISA:



  1. Il s'agit d'un petit jeu de commandes RISC facile à apprendre. TrÚs préféré pour ceux qui souhaitent acquérir des connaissances sur les microprocesseurs.
  2. , , .
  3. CPU ISA RISC-V.
  4. , , RISC-V.


RISC



En commençant Ă  mieux comprendre RISC-V, j'ai rĂ©alisĂ© que RISC-V s'est avĂ©rĂ© ĂȘtre un retour radical Ă  ce que beaucoup croyaient ĂȘtre une Ăšre rĂ©volue de l'informatique. Du point de vue de la conception, RISC-V sur une machine similaire Ă  la durĂ©e de mouvement Ă  un classique R Ă©duquĂ© I nstruction S et C omputer (RISC, «ordinateur avec un ensemble de commandes courtes") au dĂ©but des annĂ©es 80 et 90.



Ces derniÚres années, beaucoup ont fait valoir que la division en RISC et CISC n'avait plus de sens, car tant d'instructions ont été ajoutées aux processeurs RISC comme ARM, et si beaucoup d'entre elles sont assez complexes, qu'au stade actuel, il s'agit plus d'un processeur hybride que d'un pur processeur RISC. Des considérations similaires ont été appliquées à d'autres processeurs RISC tels que le PowerPC.



RISC-V, d'autre part, est un représentant véritablement «hardcore» des processeurs RISC. Si vous lisez les discussions sur RISC-V sur Internet, vous trouverez des gens affirmant que RISC-V a été développé par des radicaux RISC de la vieille école qui refusent de suivre le rythme.



L'ancien ingénieur ARM Erin Shepherd a écrit une critique intéressante du RISC-V il y a quelques années :



ISA RISC-V . , .. (, , ) , .


Je vais donner un peu de contexte briÚvement. La petite taille du code présente un avantage en termes de performances car elle facilite le stockage du code exécutable dans le cache haute vitesse du processeur.



La critique ici est que les concepteurs de RISC-V se sont trop concentrés sur la fourniture d'un petit jeu d'instructions. AprÚs tout, c'est l'un des objectifs originaux du RISC.



Selon Erin, la conséquence en était qu'un vrai programme aurait besoin de beaucoup plus d'instructions pour accomplir des tùches, c'est-à-dire qu'il prendrait plus d'espace mémoire.



Traditionnellement, pendant de nombreuses annĂ©es, on croyait que davantage d'instructions devraient ĂȘtre ajoutĂ©es au processeur RISC pour le rendre plus similaire au CISC. L'idĂ©e est que des commandes plus spĂ©cialisĂ©es peuvent remplacer l'utilisation de plusieurs commandes courantes.



Compression de commandes et fusion de macro-opérations



Cependant, il existe deux innovations dans l'architecture du processeur qui rendent cette stratégie d'ajout d'instructions plus complexes, à bien des égards, redondante:



  • Instructions compressĂ©es - Les instructions sont compressĂ©es en mĂ©moire et dĂ©compressĂ©es dans la premiĂšre Ă©tape du processeur.
  • Fusion de macro-opĂ©ration - Deux instructions simples ou plus sont lues par le processeur et fusionnĂ©es en une instruction plus complexe.


En fait, ARM utilise déjà ces deux stratégies, et les processeurs x86 utilisent cette derniÚre, donc RISC-V ne fait aucune nouvelle astuce ici.



Cependant, il y a ici une subtilité: RISC-V profite beaucoup plus de ces deux stratégies pour deux raisons importantes:



  1. Les commandes compressées ont été ajoutées initialement. D'autres architectures, comme ARM, y ont réfléchi plus tard et les ont vissées de maniÚre assez hùtive.
  2. C'est là que se justifie l'obsession de RISC pour un petit nombre d'équipes uniques. Il reste simplement plus d'espace pour ajouter des commandes compressées.


Le deuxiĂšme point nĂ©cessite quelques Ă©claircissements. Dans les architectures RISC, les commandes ont gĂ©nĂ©ralement une largeur de 32 bits. Ces bits doivent ĂȘtre utilisĂ©s pour coder diverses informations. Disons que nous avons une commande comme celle-ci (il y a des commentaires aprĂšs le point-virgule):



ADD x1, x4, x8    ; x1 ← x4 + x8
      
      





Il ajoute le contenu des registres x4



et x8



stocke le résultat dans x1



. Le nombre de bits requis pour coder cette instruction dĂ©pend du nombre de registres disponibles. RISC-V et ARM ont 32 registres. Le nombre 32 peut ĂȘtre exprimĂ© en 5 bits:



2⁔ = 32


Puisque la commande doit spĂ©cifier trois registres diffĂ©rents, un total de 15 bits (3 × 5) est nĂ©cessaire pour coder les opĂ©randes (donnĂ©es d'entrĂ©e pour l'opĂ©ration d'addition).



Par conséquent, plus nous voulons prendre en charge de fonctionnalités dans le jeu d'instructions, plus nous prendrons de bits sur les 32 bits dont nous disposons. Bien sûr, nous pouvons passer aux commandes 64 bits, mais cela consommera trop de mémoire, ce qui signifie que les performances en pùtiront.



Dans un effort agressif pour rĂ©duire le nombre d'instructions, RISC-V laisse plus de place pour ajouter des bits pour indiquer que nous utilisons des instructions compressĂ©es. Si le processeur voit que certains bits sont dĂ©finis dans la commande, il comprend alors qu'il doit ĂȘtre interprĂ©tĂ© comme compressĂ©.



Cela signifie qu'au lieu de coller 32 bits d'une instruction Ă  l'intĂ©rieur, nous pouvons insĂ©rer deux instructions de 16 bits chacune. Naturellement, toutes les commandes RISC-V ne peuvent pas ĂȘtre exprimĂ©es au format 16 bits. Par consĂ©quent, un sous-ensemble d'instructions 32 bits est sĂ©lectionnĂ© en fonction de leur utilitĂ© et de leur frĂ©quence d'utilisation. Alors que les instructions non compressĂ©es peuvent recevoir 3 opĂ©randes (donnĂ©es d'entrĂ©e), les instructions compressĂ©es ne peuvent recevoir que 2 opĂ©randes. Autrement dit, la commande compressĂ©e ADD



ressemblera Ă  ceci:



C.ADD x4, x8     ; x4 ← x4 + x8
      
      





Le code d'assemblage RISC-V utilise un préfixe C.



pour indiquer que la commande doit ĂȘtre assemblĂ©e dans une commande compressĂ©e.



Essentiellement, les instructions compressées réduisent le nombre d'opérandes. Trois registres d'opérandes prendraient 15 bits, laissant seulement 1 bit pour indiquer l'opération! Ainsi, lorsque vous utilisez deux opérandes pour indiquer l'opcode (l'opération à effectuer), il nous reste 6 bits.



C'est en fait proche du fonctionnement de l'assembleur x86 lorsque pas assez de bits sont réservés pour utiliser les trois registres d'opérandes. Le processeur x86 gaspille des bits pour permettre, par exemple, à la commande de ADD



lire les données entrantes de la mémoire et des registres.



Cependant, le vrainous bénéficions de la combinaison de la compression de commande et de la fusion de macro-opération. Lorsque le processeur reçoit un mot de 32 bits contenant deux instructions compressées de 16 bits, il peut les fusionner en une instruction plus complexe.



Cela semble absurde - sommes-nous revenus à notre point de départ?



Non, car nous contournons le besoin de remplir la spécification ISA avec un tas d'instructions complexes (c'est-à-dire que la stratégie ARM suit). Au lieu de cela, nous exprimons, par essence, toute une série de commandes complexes indirectement , à travers diverses combinaisons de commandes simples.



Dans des circonstances normales, la macro-fusion poserait un problÚme: bien que deux instructions soient remplacées par une, elles occupent toujours deux fois plus de mémoire. Cependant, lors de la compression des commandes, nous ne prenons pas d'espace supplémentaire. Nous profitons des deux architectures.



Regardons l'un des exemples donnés par Erin Shepherd. Dans son article critique sur ISA RISC-V, elle montre une fonction simple en C.Pour clarifier les choses, j'ai pris la liberté de la réécrire:



int get_index(int *array, int i) { 
    return array[i];
}
      
      





Sur x86, cela compilera le code d'assembly suivant:



mov eax, [rdi+rsi*4]
ret
      
      





Lorsqu'une fonction est appelée dans un langage de programmation, les arguments sont généralement passés à la fonction dans un registre selon un ordre établi qui dépend du jeu d'instructions utilisé. Sur x86, le premier argument est placé dans un registre rdi



, le second dans rsi



. Par dĂ©faut, les valeurs de retour doivent ĂȘtre placĂ©es dans un registre eax



.



La premiĂšre commande multiplie le contenu rsi



par 4. Elle contient une variable i



. Pourquoi se multiplie-t-il? Parce qu'il se array



compose d'Ă©lĂ©ments entiers sĂ©parĂ©s par 4 octets. Par consĂ©quent, le troisiĂšme Ă©lĂ©ment du tableau est Ă  un dĂ©calage de 3 × 4 = 12 octets.



Ensuite, nous ajoutons ceci Ă  rdi



qui contient l'adresse de base array



... Cela nous donne l'adresse finale du i



e élément array



. Nous lisons le contenu de la cellule mémoire à cette adresse et le stockons dans eax



: tùche terminée.



Sur ARM, tout se passe de la mĂȘme maniĂšre:



LDR r0, [r0, r1, lsl #2]
BX  lr                    ;return
      
      





Ici, nous ne multiplions pas par 4, mais décalons le registre de r1



2 bits vers la gauche, ce qui équivaut à multiplier par 4. C'est probablement une description plus précise de ce qui se passe sur x86. Je doute qu'il soit possible de multiplier par tout ce qui n'est pas un multiple de 2, car la multiplication est une opération assez compliquée et le déplacement est peu coûteux et facile.



D'aprĂšs ma description de x86, le reste est Ă  deviner. Passons maintenant Ă  RISC-V, oĂč le vrai plaisir commence! (les commentaires commencent par un point-virgule)



SLLI a1, a1, 2     ; a1 ← a1 << 2
ADD  a0, a0, a1    ; a0 ← a0 + a1
LW   a0, a0, 0     ; a0 ← [a0 + 0]
RET
      
      





Sur RISC-V, les registres a0



et a1



sont simplement des alias pour x10



et x11



. C'est là que sont placés les premier et deuxiÚme arguments de l'appel de fonction. RET



Est une pseudo-commande (raccourci):



JALR x0, 0(ra)     ; sp ← 0 + ra
                   ; x0 ← sp + 4  ignoring result
      
      





JALR



accÚde à l'adresse stockée ra



qui fait référence à l'adresse de retour. ra



Est un pseudonyme x1



.



Et tout cela a l'air absolument terrible, non? Deux fois plus de commandes pour une opération simple et couramment utilisée, comme effectuer une recherche d'index sur une table et renvoyer un résultat.



Ça a vraiment l'air mauvais. C'est pourquoi Erin Shepherd a Ă©tĂ© extrĂȘmement critique Ă  l'Ă©gard des dĂ©cisions de conception prises par les dĂ©veloppeurs RISC-V. Elle Ă©crit:



Les simplifications de RISC-V simplifient le décodeur (c'est-à-dire le processeur frontal), mais cela se fait au prix de plus d'instructions. Cependant, la mise à l'échelle de la largeur du pipeline est une tùche délicate, tandis que le décodage de quelques instructions (ou trÚs) inhabituelles est bien étudié (les principales difficultés surviennent lors de la détermination de la longueur de la commande n'est pas triviale - en raison de ses préfixes infinis, x86 est un cas particuliÚrement négligé).


Cependant, grĂące Ă  la compression des commandes et Ă  la fusion macro-op, la situation peut ĂȘtre amĂ©liorĂ©e.



C.SLLI a1, 2      ; a1 ← a1 << 2
C.ADD  a0, a1     ; a0 ← a0 + a1
C.LW   a0, a0, 0  ; a0 ← [a0 + 0]
C.JR   ra
      
      





DĂ©sormais, les instructions occupent exactement la mĂȘme quantitĂ© d'espace mĂ©moire que l'exemple d'ARM.



Ok, maintenant faisons la fusion macro-op !



L'une des conditions pour que RISC-V autorise les opérations de fusion en une seule est que le registre cible correspond . Cette condition est remplie pour les commandes ADD



et LW



(mot de chargement, "mot de chargement"). Par conséquent, le processeur les transformera en une seule instruction.



Si cette condition Ă©tait remplie pour SLLI, nous pourrions fusionner les trois commandes en une seule . Autrement dit, le processeur verrait quelque chose qui ressemble Ă  une instruction ARM plus complexe:



LDR r0, [r0, r1, lsl #2]
      
      





Mais pourquoi ne pourrions-nous pas écrire cette opération de macro complexe directement dans le code?



Parce que ISA ne prend pas en charge une telle opération de macro! Rappelez-vous que nous avons un nombre limité de bits. Alors rallongons les commandes! Non, cela prendra trop de mémoire et débordera plus rapidement le précieux cache du processeur.



Cependant, si nous émettons ces instructions longues et semi-complexes à l'intérieur du processeur, aucun problÚme ne se pose. Un processeur n'a jamais plus de quelques centaines d'instructions à la fois. Par conséquent, si nous dépensons pour chaque commande, disons 128 bits, cela ne créera pas de difficultés. Il y aura encore assez de silicium pour tout.



Lorsqu'un dĂ©codeur reçoit une commande ordinaire, il la transforme gĂ©nĂ©ralement en une ou plusieurs micro-opĂ©rations. Ces micro-opĂ©rations sont les instructions avec lesquelles le processeur fonctionne rĂ©ellement. Ils peuvent ĂȘtre trĂšs larges et contenir de nombreuses informations utiles supplĂ©mentaires. Le prĂ©fixe "micro" semble ironique, car ils sont plus larges. Cependant, en rĂ©alitĂ©, «micro» signifie qu'ils ont un nombre limitĂ© de tĂąches.



La fusion de macro-opération bouleverse un peu le travail du décodeur: au lieu de transformer une commande en plusieurs micro-opérations, nous prenons de nombreuses opérations et les transformons en une seule micro-opération.



Autrement dit, ce qui se passe dans un processeur moderne peut sembler plutĂŽt Ă©trange:



  1. PremiĂšrement, il combine les deux Ă©quipes en une seule en utilisant la compression .
  2. Il les divise ensuite en deux à l'aide du déballage .
  3. Il les combine ensuite en une seule opération en utilisant la fusion macro-op .


D'autres commandes peuvent ĂȘtre divisĂ©es en plusieurs micro-opĂ©rations, plutĂŽt que fusionnĂ©es. Pourquoi certaines Ă©quipes fusionnent-elles tandis que d'autres se sĂ©parent? Y a-t-il un systĂšme dans cette folie?



Un aspect clé de la transition vers les micro-opérations est le niveau de complexité requis:



  • Pas trop complexe, car sinon ils ne pourront pas terminer dans un nombre fixe de cycles d'horloge allouĂ©s Ă  chaque commande.
  • Pas trop simple, sinon nous gaspillerons simplement les ressources du processeur. Faire deux micro-opĂ©rations prendra deux fois plus de temps qu'une seule.


Tout a commencĂ© avec les processeurs CISC. Intel a commencĂ© Ă  diviser ses instructions CISC complexes en micro-opĂ©rations pour les rendre plus faciles Ă  insĂ©rer dans des pipelines de processeurs comme les instructions RISC. Cependant, dans les constructions ultĂ©rieures, les dĂ©veloppeurs ont rĂ©alisĂ© que de nombreuses Ă©quipes du SCRC pouvaient ĂȘtre fusionnĂ©es en une Ă©quipe modĂ©rĂ©ment complexe. S'il y a moins de commandes Ă  exĂ©cuter, le travail sera terminĂ© plus rapidement.



Avantages obtenus



Nous avons discutĂ© de nombreux dĂ©tails, donc maintenant, il doit ĂȘtre difficile pour vous de comprendre ce que signifie tout ce travail. À quoi sert toute cette compression et cette fusion? Ils semblent faire beaucoup de travail inutile.



PremiÚrement, la compression des commandes est complÚtement différente de la compression du zip. Le mot «compression» est un peu trompeur car la compression ou la décompression instantanée d'une commande est tout à fait simple. Aucun temps n'est perdu à ce sujet.



Il en va de mĂȘme pour la fusion de macro-opĂ©ration. Bien que ce processus puisse sembler compliquĂ©, des systĂšmes similaires sont dĂ©jĂ  utilisĂ©s dans les microprocesseurs modernes. Par consĂ©quent, les coĂ»ts que toute cette complexitĂ© ajoute ont dĂ©jĂ  Ă©tĂ© payĂ©s.



Cependant, contrairement aux concepteurs d'ARM, MIPS et x86, lorsqu'ils ont commencé à concevoir leur ISA, les créateurs de RISC-V connaissaient la compression des commandes et la fusion des macro-opérations. Grùce à divers tests avec le premier jeu d'instructions minimal, ils ont fait deux découvertes importantes:



  1. Les programmes RISC-V occupent gĂ©nĂ©ralement Ă  peu prĂšs le mĂȘme ou moins d'espace mĂ©moire que toute autre architecture de processeur. Y compris x86, qui devrait utiliser la mĂ©moire efficacement, Ă©tant donnĂ© qu'il s'agit d'ISA CISC.
  2. Il doit effectuer moins de micro-opérations que les autres ISA.


En fait, en concevant l'ensemble d'instructions de base avec la fusion à l'esprit, ils ont pu fusionner suffisamment d'instructions pour que le processeur de tout programme doive effectuer moins de micro-opérations que les processeurs concurrents.



Cela a incitĂ© l'Ă©quipe de dĂ©veloppement RISC-V Ă  redoubler d'efforts pour mettre en Ɠuvre la fusion macro-opĂ©rationnelle en tant que stratĂ©gie fondamentale RISC-V. Le manuel RISC-V contient de nombreuses notes sur les opĂ©rations avec lesquelles vous pouvez fusionner. Il comprend Ă©galement des correctifs pour faciliter la fusion des commandes trouvĂ©es dans les modĂšles courants.



Le petit ISA facilite l'apprentissage des Ă©tudiants. Cela signifie qu'il est plus facile pour un Ă©tudiant en architecture de processeur de concevoir son propre processeur fonctionnant sur des instructions RISC-V. Il convient de rappeler que la compression de commande et la fusion macro-op sont facultatives.



RISC-V a un petit jeu de commandes fondamentales qui doit ĂȘtre implĂ©mentĂ©. Cependant, toutes les autres commandes sont implĂ©mentĂ©es dans le cadre des extensions. Les commandes compressĂ©es ne sont qu'une extension facultative.



La fusion macro-op n'est que l'optimisation. Il ne change pas de comportement en gĂ©nĂ©ral et n'a donc pas besoin d'ĂȘtre implĂ©mentĂ© dans votre propre processeur RISC-V.



Stratégie de conception RISC-V



RISC-V a pris tout ce que nous savons sur les processeurs modernes aujourd'hui et a utilisé ces connaissances pour concevoir des processeurs ISA. Par exemple, nous savons que:



  • Les cƓurs de processeur actuels ont un systĂšme de prĂ©diction de branche sophistiquĂ©.
  • Les cƓurs de processeur sont superscalaires, c'est-Ă -dire qu'ils exĂ©cutent de nombreuses instructions en parallĂšle.
  • Pour assurer la superscalaritĂ©, l'exĂ©cution des commandes avec un changement d'ordre (exĂ©cution dans le dĂ©sordre) est utilisĂ©e.
  • Ils ont des convoyeurs.


Cela signifie que des fonctionnalités telles que l'exécution conditionnelle prise en charge par ARM ne sont plus nécessaires. La prise en charge de cette fonction par ARM ronge des bits du format d'instruction. RISC-V peut sauvegarder ces bits.



L'exĂ©cution conditionnelle a Ă©tĂ© conçue Ă  l'origine pour Ă©viter les fourchettes, car elles sont mauvaises pour les pipelines. Pour accĂ©lĂ©rer le travail du processeur, il reçoit gĂ©nĂ©ralement Ă  l'avance les commandes suivantes, de sorte qu'immĂ©diatement aprĂšs l'exĂ©cution de la prĂ©cĂ©dente, Ă  la premiĂšre Ă©tape du processeur, la suivante peut ĂȘtre captĂ©e.



Avec le branchement conditionnel, nous ne pouvons pas savoir Ă  l'avance oĂč se trouvera la prochaine commande lorsque nous commencerons Ă  remplir le pipeline. Cependant, un processeur superscalaire peut simplement exĂ©cuter les deux branches en parallĂšle.



C'est pour cette raison que RISV-C n'a pas non plus de registres d'état, car ils créent des dépendances entre les commandes. Plus chaque commande est indépendante, plus il est facile de l'exécuter en parallÚle avec une autre commande.



Fondamentalement, la stratégie RISC-V est que nous pouvons rendre ISA aussi simple que possible et l'implémentation minimale du processeur RISC-V aussi simple que possible sans avoir besoin de décisions de conception qui rendraient impossible la création d'un processeur haute performance.






La publicité



Notre société propose des serveurs non seulement avec des processeurs Intel, mais également des serveurs avec des processeurs AMD EPYC. Comme pour les autres types de serveurs, il existe une vaste sélection de systÚmes d'exploitation pour une installation automatique, il est possible d'installer n'importe quel systÚme d'exploitation à partir de votre propre image. Essayez-le maintenant!






All Articles