Il y a quelques compromis différents à faire ici.
Tout d'abord, nous voulons que les instructions soient à largeur fixe (32 bits). Cela garantit que les instructions sont mises en cache et alignées sur la page, ce qui simplifie la présence de cache et de page et les vérifications d'autorisation.
Deuxièmement, nous voulons que les différents champs d'instructions ( opcode
/ source regs
/ immediates
) soient à largeur et position fixes. Cela les rend plus rapides / moins logiques à décoder et ils sont nécessaires dans les premières étapes du pipeline. (Le destination
registre n'est pas nécessaire jusqu'à la fin du pipeline, il peut donc être à différents endroits R
et I
instructions.) La position et la largeur du function
champ importent un peu moins car cela doit contrôler la fonction de l'ALU, mais c'est dans la troisième phase du pipeline, vous avez donc un peu de temps pour travailler avec elle si nécessaire.
I
J
J
228228I
les instructions sont également agréables pour les rédacteurs de compilateurs / éditeurs de liens. (Sur le SPARC, où le champ immédiat n'était que de 12 bits, ils ont dû ajouter une load-high
classe d'instruction spéciale entière avec un 20 bits immédiat.)
26= 64J
R
I
Mais cela laisse une marge de manœuvre avec les R
instructions. Mis à part l'opcode 6 bits, ceux-ci n'ont besoin que de 15 bits supplémentaires pour la spécification du registre, ce qui laisse 11 bits pour l'opcode étendu et / ou la quantité de décalage.
Vous devez considérer le function
champ comme un opcode étendu pour l' R
instruction. Il n'y a qu'un seul R
opcode d'instruction, mais il y en a 64 différentes functions
que l' R
instruction peut exécuter.
D'accord. Nous avons 60 I
instructions différentes et 64 R
instructions différentes , alors où devrions-nous mettre les instructions de changement immédiat?
Eh bien, non seulement il y a moins d' I
instructions, mais il y a beaucoup plus de choses que nous voulons faire avec les I
instructions. Rappelez-vous que toutes les instructions de branchement doivent être des I
instructions car elles ont un décalage relatif (immédiat). Toutes les instructions de chargement et de stockage sont également I
formatées sur MIPS. Et enfin, nous avons besoin que l'instruction load-upper-immediate soit une I
instruction. Non seulement cela, mais les R
instructions ont encore 5 bits supplémentaires inutilisés, (ce dont nous avons besoin pour l'immédiat d'un décalage immédiat sur cette architecture), donc cela incite davantage à faire des décalages immédiats en R
instructions spéciales (étranges) .
Beaucoup de ces décisions sont plus de l'art que de la science, mais il existe une logique sous-jacente qui peut être discernée. L'objectif clé est pas de faire le nombre d'instructions aussi petit que possible, il est de faire une haute performancepipeline installé sur une seule puce (de sorte que de petites entreprises, comme MIPS et Sun dans les années 1980, pouvaient concurrencer IBM et DEC). (Le nom RISC, inventé par David Patterson, est quelque peu malheureux. Il a fait son chemin parce qu'il était mignon, non pas parce que "instructions réduites" est une description précise de ce que les architectures MIPS et SPARC essayaient vraiment de faire.) Donc, vous voulez que le instructions largeur fixe (et relativement petite pour que vous obteniez un meilleur comportement I-cache) pour rendre la récupération, la pagination et le décodage plus simples et plus rapides. Vous voulez que les parties de l'instruction qui doivent être décodées tôt (leopcode
, les deux registres source et le signe étendu immédiatement) doivent avoir une largeur fixe et une position fixe. Vous voulez que les intermédiaires soient aussi longs que possible et vous voulez autant de types d'instructions différents que possible, compte tenu de toutes ces autres contraintes.
Pour comprendre les formats d'instructions MIPS I, vous devez comprendre le pipeline MIPS et repenser à la technologie d'implémentation du processeur vers 1985. Si vous regardez le diagramme (vous connaissez celui-ci), vous verrez que la lecture du fichier de registre se trouve dans le Étape d'identification, juste après IF.
Aux fins d'une instruction de type R, l'étape ID doit effectuer les tâches suivantes:
Aux fins de cette discussion, c'est la première tâche à laquelle vous devez penser. S'il y a beaucoup de travail de décodage d'instructions que vous devez faire pour même déterminer si vous avez besoin de valeurs de registres, cela augmente le délai avant de pouvoir démarrer les lectures de registre. Cela augmente également la complexité de l'étape d'identification. En réservant un seul opcode pour toutes les instructions de type R, vous gardez la complexité au minimum.
Il semble un peu étrange que vous consacriez cinq bits uniquement au décalage. Je peux penser à quelques explications possibles. La première est qu'elle simplifie le routage (ces cinq bits sont TOUJOURS introduits directement dans le fichier de registre, ces cinq bits sont TOUJOURS introduits dans le barillet, ces six bits sont TOUJOURS acheminés vers l'ALU pour déterminer la fonction à exécuter).
Ils ont peut-être pensé à introduire à l'avenir des instructions combinées de décalage vers la gauche et d'ajout. Ce serait probablement sous la forme:
Aujourd'hui, nous ne penserions probablement pas à deux fois à avoir une étape de décodage plus complexe, d'autant plus que les accès aux fichiers de registre ont tendance à se produire plus tard dans le pipeline d'un processeur superscalaire typique. De nombreux processeurs modernes effectuent même un décodage d'instructions grossières au moment où une instruction est insérée dans le cache L1 . Vous agrandissez les lignes I-cache de quelques bits pour stocker les informations supplémentaires (grâce à la loi de Moore, vous avez beaucoup de transistors à perdre) pour rendre le décodage des instructions "correct" plus simple et plus rapide.
Une des raisons pour lesquelles ils voulaient probablement garder le champ opcode aussi petit que possible est afin qu'il ne pénalise pas indûment les instructions de type J. Comme vous le savez probablement, les instructions de type J utilisent un adressage pseudo-direct. Pour le bénéfice de tous ceux qui jouent à la maison, je vais l'expliquer brièvement.
Le champ d'adresse d'une instruction de type J est de 26 bits. Comme les instructions sont toujours alignées sur 4 octets, vous n'avez pas besoin de stocker les deux bits les moins significatifs, ce qui signifie que vous avez effectivement 28 bits d'adresse. Cependant, l'espace d'adressage dans MIPS I est de 32 bits. Ainsi, les quatre premiers bits de l'emplacement de saut sont extraits du compteur de programmes.
Cela signifie que vous ne pouvez pas accéder directement à un emplacement où les quatre bits les plus significatifs de l'emplacement du PC sont différents. Vous devriez plutôt effectuer un saut à trois instructions plus cher dans un registre à gratter:
Ce n'est pas trop mal aujourd'hui, mais en 1985, c'est beaucoup de cycles d'horloge.
Voler un peu du champ d'adresse réduirait encore plus la portée effective d'un saut direct. Vous pouvez voir comment cela pourrait être un prix trop élevé à payer.
la source