Architecture des ordinateurs : Câblage des processeurs dans l'environnement « y86 » (INF155) F. Pellegrini Université de Bordeaux Ce document est copiable et distribuable librement et gratuitement à la condition expresse que son contenu ne soit modifié en aucune façon, et en particulier que le nom de son auteur et de son institution d'origine continuent à y figurer, de même que le présent texte. © 2014,2016 F. Pellegrini 1 Modélisation du câblage du y86 L'environnement pédagogique y86 couvre aussi le câblage du processeur y86 lui-même Câblage modélisé par un langage dédié : HCL (« Hardware Control Language ») Simplification de langages tels que Verilog et VHDL Compilation du HCL en C et intégration du code produit au sein de l'émulateur y86 Permet de mettre en œuvre plusieurs câblages du même jeu d'instructions http://csapp.cs.cmu.edu/ © 2014,2016 F. Pellegrini 2 Utilisation de HCL Description HCL Compilateur HCL Description C Liaison avec l'environnement Simulateur y86 © 2014,2016 F. Pellegrini 3 Syntaxe HCL (1) HCL permet de représenter le câblage des blocs fonctionnels du processeur y86 Syntaxe proche du langage C Types de données supportés : Booléens : type « bool » Signaux pilotant le fonctionnement des unités fonctionnelles du processeur Valeurs entières (au plus 32 bits) : type « int » Servent à coder les opérandes, adresses, … © 2014,2016 F. Pellegrini 4 Syntaxe HCL (2) Opérations supportées : Fonctions logiques sur des valeurs booléennes Fonctions logiques sur des valeurs entières Certains blocs fonctionnels ne font pas partie du périmètre du langage : Banque multi-ports des registres (« register file ») Mémoire centrale (instructions et données) UAL © 2014,2016 F. Pellegrini 5 Syntaxe HCL (3) Fonctions logiques sur des valeurs booléennes retournant un booléen : bool eq = (a && b) || (!a &&!b) ; # Test d'égalité bool out = (s && a) || (!s && b) ; # Multiplexeur 1 bit © 2014,2016 F. Pellegrini 6 Syntaxe HCL (4) Fonctions logiques sur des valeurs entières retournant un booléen : bool eq = (A == B) ; # Existent aussi : <, <=, >, >=,!= © 2014,2016 F. Pellegrini 7 Syntaxe HCL (5) bool s1 = (code == 2) || (code == 3) ; # Au cas par cas bool s0 = (code == 1) || (code == 3) ; bool s1 = code in { 2, 3 } ; # Notation ensembliste bool s0 = code in { 1, 3 } ; © 2014,2016 F. Pellegrini 8 Syntaxe HCL (5) Fonctions logiques retournant des mots : int out = [ # Multiplexeur s:A; # La valeur de sortie est la première 1:B; # valeur dont l'étiquette soit vraie ]; © 2014,2016 F. Pellegrini 9 Syntaxe HCL (6) int mult4 = [ # Un multiplexeur multiplexe... !s1 && !s0 : A ; # 00 !s1 : B; # 01 !s0 : C; # 10 1: D; # 11 ]; int min3 = [ # Toute fonction peut s'exprimer A <= B && A <= C : A ; # sous la forme d'un multiplexeur B <= A && B <= C : B ; 1:C ]; © 2014,2016 F. Pellegrini 10 Rappels sur l'ISA du y86 (1) Opcode : 1 octet Sa valeur détermine la taille de l'instruction Registres : 1 octet optionnel Valeur immédiate : 4 octets optionnels icode ifun valC rA rB © 2014,2016 F. Pellegrini 11 Rappels sur l'ISA du y86 (2) © 2014,2016 F. Pellegrini 12 Structure du y86-seq (1) L'exécution d'une instruction est organisée en six étapes principales : « Fetch » « Decode / Read » « Execute » « Memory » « Write back » « PC update » © 2014,2016 F. Pellegrini 13 Structure du y86-seq (2) Blocs bleu clair : unités matérielles non incluses dans le périmètre d'HCL Blocs gris : logique de contrôle Liaisons (pas toutes montrées sur le schéma) : Épaisses : 1 mot Fines : 1 octet ou quelques bits Pointillées : 1 bit Ovales blancs : noms des liaisons © 2014,2016 F. Pellegrini 14 Fonctionnement du y86-seq (1) Exécution de « OPl » / « rrmovl » / « irmovl » ! ! ! " # $ % % &' % + & & ( , + & , )* . / 0 % & % & % & 1 © 2014,2016 F. Pellegrini 15 Fonctionnement du y86-seq (2) Exécution de « rmmovl » / « mrmovl » $) * $) ! " % & - . # % % &' / " 0 ! " # $ * & & + " & % 1 © 2014,2016 F. Pellegrini 16 Fonctionnement du y86-seq (3) Exécution de « pushl » / « popl » 1 2 1 1 ! $ % % 3 21 &' & - . ! / " % 3 21 % 3 21 )4"* & 0 % 3 21 & + & % 3 21 % " " & 1 © 2014,2016 F. Pellegrini 17 Fonctionnement du y86-seq (4) Exécution de « jXX » / « call » / « ret » 566 " " 7 7 $ % 3 21 &' / ) * . / & " 0 1 © 2014,2016 F. Pellegrini )4"* & % 3 21 / 89 + % 3 21 % 3 21 & + & % 3 21 " " & 8 18 Câblage du y86-seq (1) « Fetch » : Récupération de l'instruction courante à exécuter De 1 à 6 octets lus à partir de l'adresse contenue dans le compteur ordinal Pré-calcul de l'adresse de l'instruction suivante © 2014,2016 F. Pellegrini 19 Câblage du y86-seq (2) « Decode » Accès éventuel à la banque des registres © 2014,2016 F. Pellegrini ## What register should be used as the A source? int srcA = [ icode in { IRRMOVL, IRMMOVL, IOPL, IPUSHL } : rA; icode in { IPOPL, IRET } : RESP; 1 : RNONE; # Don't need register ]; ## What register should be used as the B source? int srcB = [ icode in { IOPL, IRMMOVL, IMRMOVL } : rB; icode in { IPUSHL, IPOPL, ICALL, IRET } : RESP; 1 : RNONE; # Don't need register ]; ## What register should be used as the E destination? int dstE = [ icode in { IRRMOVL, IIRMOVL, IOPL} : rB; icode in { IPUSHL, IPOPL, ICALL, IRET } : RESP; 1 : RNONE; # Don't need register ]; ## What register should be used as the M destination? int dstM = [ icode in { IMRMOVL, IPOPL } : rA; 1 : RNONE; # Don't need register ]; 20 Câblage du y86-seq (3) « Execute » : Utilisation de l'UAL © 2014,2016 F. Pellegrini ## Select input A to ALU int aluA = [ icode in { IRRMOVL, IOPL } : valA; icode in { IIRMOVL, IRMMOVL, IMRMOVL } : valC; icode in { ICALL, IPUSHL } : -4; icode in { IRET, IPOPL } : 4; # Other instructions don't need ALU ]; ## Select input B to ALU int aluB = [ icode in { IRMMOVL, IMRMOVL, IOPL, ICALL, IPUSHL, IRET, IPOPL } : valB; icode in { IRRMOVL, IIRMOVL } : 0; # Other instructions don't need ALU ]; ## Set the ALU function int alufun = [ icode == IOPL : ifun; 1 : ALUADD; ]; ## Should the condition codes be updated? bool set_cc = icode in { IOPL }; 21 Câblage du y86-seq (4) «Memory» : Accès à la mémoire des données © 2014,2016 F. Pellegrini ## Set read control signal bool mem_read = icode in { IMRMOVL, IPOPL, IRET }; ## Set write control signal bool mem_write = icode in { IRMMOVL, IPUSHL, ICALL }; ## Select memory address int mem_addr = [ icode in { IRMMOVL, IPUSHL, ICALL, IMRMOVL } : valE; icode in { IPOPL, IRET } : valA; # Other instructions don't need address ]; ## Select memory input data int mem_data = [ # Value from register icode in { IRMMOVL, IPUSHL } : valA; # Return PC icode == ICALL : valP; # Default: Don't write anything ]; 22 Câblage du y86-seq (5) « PC update » : Mise à jour du compteur ordinal © 2014,2016 F. Pellegrini int new_pc = [ # Call. Use instruction constant icode == ICALL : valC; # Taken branch. Use instruction constant icode == IJXX && Bch : valC; # Completion of RET instruction. Use value from stack icode == IRET : valM; # Default: Use incremented PC 1 : valP; ]; 23 Analyse de l'architecture y86-seq (1) Caractéristiques : Connecte des blocs fonctionnels prédéfinis au moyen de fonctions logiques combinatoires Exprime chaque instruction sous la forme d'étapes simples Flot de contrôle et de données unique pour chaque instruction © 2014,2016 F. Pellegrini 24 Analyse de l'architecture y86-seq (2) Limitations : Au cours du cycle, le flot de contrôle doit se propager au sein de tous les circuits Chemin critique très long Fréquence d'horloge trop basse pour être compétitive (vintage '80s : 1 MHz) Les unités fonctionnelles ne sont réellement utiles que pendant une fraction du cycle Ceci conduit naturellement à en dériver une version pipe-linée © 2014,2016 F. Pellegrini 25